alt*_*alt 5 ruby arrays activerecord ruby-on-rails
我有一个用户之前"投票"的ActiveRecord关系...
@previous_votes = current_user.votes
Run Code Online (Sandbox Code Playgroud)
我只需要根据当前的"挑战"过滤掉这些,所以Ruby的select方法似乎是最好的方法......
@previous_votes = current_user.votes.select { |v| v.entry.challenge_id == Entry.find(params[:entry_id]).challenge_id }
Run Code Online (Sandbox Code Playgroud)
但我还需要更新这些记录的属性,该select方法将我的关系转换为无法更新或保存的数组!
@previous_votes.update_all :ignore => false
# ...
# undefined method `update_all' for #<Array:0x007fed7949a0c0>
Run Code Online (Sandbox Code Playgroud)
如何像select方法那样过滤我的关系,但是不能失去用ActiveRecord更新/保存项目的能力?
在谷歌周围看似似乎named_scope出现在类似问题的所有答案中,但我无法弄清楚它们能否专门完成我所追求的目标.
问题是这select不是 SQL 方法。它获取所有记录并在 Ruby 端过滤它们。这是一个简化的示例:
votes = Vote.scoped
votes.select{ |v| v.active? }
# SQL: select * from votes
# Ruby: all.select{ |v| v.active? }
Run Code Online (Sandbox Code Playgroud)
由于 update_all 是一个 SQL 方法,因此您不能在 Ruby 数组上使用它。您可以坚持在 Ruby 中执行所有操作,也可以将其中一些(全部)操作移至 SQL 中。
votes = Vote.scoped
votes.select{ |v| v.active? }
# N SQL operations (N - number of votes)
votes.each{ |vote| vote.update_attribute :ignore, false }
# or in 1 SQL operation
Vote.where(id: votes.map(&:id)).update_all(ignore: false)
Run Code Online (Sandbox Code Playgroud)
如果您实际上不使用获取的投票,那么在 SQL 端执行整个选择和更新会更快:
Vote.where(active: true).update_all(ignore: false)
Run Code Online (Sandbox Code Playgroud)
虽然前面的示例适用于您的select,但这个示例需要您用 SQL 重写它。如果您已经在 Rails 模型中设置了所有关系,您可以大致这样做:
entry = Entry.find(params[:entry_id])
current_user.votes.joins(:challenges).merge(entry.challenge.votes)
# requires following associations:
# Challenge.has_many :votes
# User.has_many :votes
# Vote.has_many :challenges
Run Code Online (Sandbox Code Playgroud)
Rails 将为您构建适当的 SQL。但如果出现问题,您始终可以退回到手动编写 SQL。
| 归档时间: |
|
| 查看次数: |
3150 次 |
| 最近记录: |