use*_*882 6 ruby sql ruby-on-rails arel ruby-on-rails-3
我正在使用Ruby on Rails 3.2.2,我想生成以下SQL查询:
SELECT `articles`.* FROM `articles` WHERE (`articles`.`user_id` = 1 OR `articles`.`status` = 'published' OR (`articles`.`status` = 'temp' AND `articles`.`user_id` IN (10, 11, 12, <...>)))
Run Code Online (Sandbox Code Playgroud)
通过这种方式使用Arel
Article
.where(
arel_table[:user_id].eq(1)
.or(arel_table[:status].eq("published"))
.or(
arel_table[:status].eq("temp")
.and(
arel_table[:user_id].in(10, 11, 12, <...>)
)
)
)
Run Code Online (Sandbox Code Playgroud)
它会生成以下内容(注意:括号与第一个SQL查询不同):
SELECT `articles`.* FROM `articles` WHERE (((`articles`.`user_id` = 1 OR `articles`.`status` = 'published') OR `articles`.`status` = 'temp' AND `articles`.`user_id` IN (10, 11, 12, <...>)))
Run Code Online (Sandbox Code Playgroud)
由于我认为后一个SQL查询不能作为第一个"工作",我怎么能使用Arel(或者,可能还有别的东西)来生成SQL查询作为第一个?
鉴于上面的SQL查询"工作"相同,但我仍然希望生成确切的SQL查询作为问题中的第一个(主要原因是第一个SQL查询比第一个SQL查询更可读一个用得少而且"明确"括号),我怎么能用Arel来做到这一点?
mmi*_*haa 13
我有同样的问题.我在网上搜索了几个小时,最后在Arel :: FactoryMethods中找到了一个名为分组的方法,只是在表达式周围添加括号.
你应该通过电话包裹你的小组arel_table.grouping(...).
如何arel_table.grouping(...)用作范围的一部分的示例
# app/model/candy.rb
class Candy < ActiveRecord::Base
has_many :candy_ownerships
has_many :clients, through: :candy_ownerships, source: :owner, source_type: 'Client'
has_many :users, through: :candy_ownerships, source: :owner, source_type: 'User'
# ....
scope :for_user_or_global, ->(user) do
# ->() is new lambda syntax, lamdba{|user| ....}
worldwide_candies = where(type: 'WorldwideCandies').where_values.reduce(:and)
client_candies = where(type: 'ClientCandies', candy_ownerships: { owner_id: user.client.id, owner_type: 'Client'}).where_values.reduce(:and)
user_candies = where(type: 'UserCandies', candy_ownerships: { owner_id: user.id, owner_type: 'User' }).where_values.reduce(:and)
joins(:candy_ownerships).where( worldwide_candies.or( arel_table.grouping(client_candies) ).or( arel_table.grouping(user_candies) ) )
end
# ....
end
Run Code Online (Sandbox Code Playgroud)
呼叫
Candy.for_user_or_global(User.last)
#=> SELECT `candies`.* FROM `candies` INNER JOIN `candy_ownerships` ON `candy_ownerships`.`candy_id` = `candies`.`id` WHERE (`candies`.`deleted_at` IS NULL) AND (((`candies`.`type` = 'WorldwideCandies' OR (`candies`.`type` = 'ClientCandies' AND `candy_ownerships`.`owner_id` = 19 AND `candy_ownerships`.`owner_type` = 'Client')) OR (`candies`.`type` = 'UserCandies' AND `candy_ownerships`.`owner_id` = 121 AND `candy_ownerships`.`owner_type` = 'User')))
Run Code Online (Sandbox Code Playgroud)
thx micha为小费
我已经成功地使用了这个宝石:squeel,它位于 Arel 之上,因此您不必弄乱它。因此,为了生成查询,您可以在 Squeel 中执行以下操作:
@articles = Article.
where{
( user_id.eq(1) | status.eq('published') ) |
( user_id.in([10, 11, 12, '<...>']) & status.eq('temp') )
}
# since this is an ActiveRecord::Relation we can play around with it
@articles = @articles.select{ [ user_id, status ] }
# and you can also inspect your SQL to see what is going to come out
puts @articles.to_sql
Run Code Online (Sandbox Code Playgroud)
您的查询越复杂,您就会越喜欢这个宝石。
| 归档时间: |
|
| 查看次数: |
2908 次 |
| 最近记录: |