【问题标题】:Filtering ActiveRecord queries in rails过滤 Rails 中的 ActiveRecord 查询
【发布时间】:2009-06-01 21:43:03
【问题描述】:

我习惯了 Django,您可以在其中对查询集运行多种过滤方法,即Item.all.filter(foo="bar").filter(something="else")

然而,这在 Rails 中并不容易做到。 Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }]) 返回一个数组,这意味着这不起作用:

Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])

所以我认为“堆叠”过滤器的最佳方法是修改条件数组,然后运行查询。

所以我想出了这个功能:

 def combine(array1,array2)
   conditions = []
   conditions[0] = (array1[0]+" AND "+array2[0]).to_s
   conditions[1] = {}
   conditions[1].merge!(array1[1])
   conditions[1].merge!(array2[1])
   return conditions
 end

用法:

array1 = ["foo = :foo", { :foo = 'bar' }] 数组2 = [“某事=:某事”,{:某事='其他'}] 条件 = 组合(数组 1,数组 2) items = Item.find(:all, :conditions => 条件)

这工作得很好。但是我希望能够组合任意数量的数组,或者基本上是写作的简写:

conditions = combine(combine(array1,array2),array3)

有人可以帮忙吗?提前致谢。

【问题讨论】:

标签: ruby-on-rails ruby activerecord


【解决方案1】:

你想要的是命名范围:

class Item < ActiveRecord::Base
  named_scope :by_author, lambda {|author| {:conditions => {:author_id => author.id}}}
  named_scope :since, lambda {|timestamp| {:conditions => {:created_at => (timestamp .. Time.now.utc)}}}
  named_scope :archived, :conditions => "archived_at IS NOT NULL"
  named_scope :active, :conditions => {:archived_at => nil}
end

在你的控制器中,像这样使用:

class ItemsController < ApplicationController
  def index
    @items = Item.by_author(current_user).since(2.weeks.ago)
    @items = params[:archived] == "1" ? @items.archived : @items.active
  end
end

返回的对象是一个代理,并且 SQL 查询将不会运行,直到您真正开始对集合执行一些实际操作,例如迭代(用于显示)或当您在代理上调用 Enumerable 方法时。

【讨论】:

  • 是的,这正是我想要的。我观看了截屏视频,这对我来说完全有意义。但是,当我启动代码时,我收到一个错误,说命名范围是一个未定义的方法。然后我注意到我正在使用 Rails 1.8,所以我将 rails 更新到 2.3.something 并且仍然遇到相同的错误....呃,我知道命名范围太好了,难以置信:/
  • 如果您冻结了 Rails,那么您的代码仍在使用以前版本的 Rails。 Rails 1.8 从未存在过,所以您一定指的是 Ruby 1.8。 rails -v 是一个命令,它会告诉你在命令行中存在什么版本的 Rails。 script/about 将告诉您有关应用程序环境的更多信息。
  • 很好 ruby​​ 脚本/about 未被识别。对于 Rails,frozen 是什么意思?
  • named_scope 现在在 Rails 4 中称为范围
  • 只是一个更新:现在在 Rails 4 中,您可以链接 where() 方法!
【解决方案2】:

我不会像你提议的那样做。

由于find返回的是一个数组,所以可以使用数组方法对其进行过滤,例如:

Item.find(:all).select {|i| i.foo == bar }.select {|i| i.whatever > 23 }...

您还可以使用命名范围来实现您想要的。

【讨论】:

  • 命名范围是更好的方法,它为您提供了可轻松重用的可链接方法。
  • @railsninja:我同意,但你必须在使用之前定义命名范围。如果你只想做一次事情,使用 select 会更容易。
  • 不正确。您可以即时执行匿名范围:railscasts.com/episodes/112-anonymous-scopes
  • 如果您已经查询了更大范围的查询并且想要节省一些时间(对大数据的影响),那么这就是您所需要的。这不会查询您的数据库,因为它在您的内存中工作。
【解决方案3】:

你可以看看Searchlogic
它使使用条件更容易 ActiveRecord 设置,甚至Arrays

希望对你有帮助。

【讨论】:

    【解决方案4】:

    您可以(或至少曾经能够)像在 Rails 中那样进行过滤:

    find(:all, :conditions => { :foo => 'foo', :bar => 'bar' })
    

    其中 :foo 和 :bar 是活动记录中的字段名称。似乎您需要做的就是传入 :field_name => 值对的哈希值。

    【讨论】:

      猜你喜欢
      • 2017-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-26
      • 1970-01-01
      相关资源
      最近更新 更多