Ruby on Rails:基于几个条件过滤模型上的关联

时间:2013-04-07 16:32:40

标签: ruby-on-rails ruby model associations

在我的ROR应用程序中,我有模型Category,Item,Property和PropertyValuation。 这个想法是一个类别包含项目,一个项目有几个属性。 PropertyValuation的目的是存储特定项的属性值。模型定义如上:

class Category < ActiveRecord::Base
  attr_accessible :name, :description, :parent, :children, :items, :parent_id

  has_many :children, :class_name => "Category", :foreign_key => "parent_id", :dependent => :nullify
  belongs_to :parent, :class_name => "Category"

  has_many :categorizations
  has_many :items, :through => :categorizations
end

class Item < ActiveRecord::Base
  attr_accessible :name, :description, :property_valuations, :barcode

  has_many :property_valuations, :dependent => :destroy  
  has_many :properties, :through => :property_valuations 

  has_many :categorizations
  has_many :categories, :through => :categorizations

end

class Property < ActiveRecord::Base
  attr_accessible :name, :description, :value_type, :unit, :unit_id

  has_many :property_valuations, :dependent => :destroy  
  has_many :items, :through => :property_valuations
  has_many :property_ranges, :dependent => :destroy

  belongs_to :unit
end

class PropertyValuation < ActiveRecord::Base     
  attr_accessible :property, :item, :value, :categorization

  belongs_to :property
  belongs_to :item
end

现在我的问题是,我已成功设法按名称过滤类别项:

@category.items.where("lower(items.name) like ?", "%#{params[:keywords].downcase}%")

但现在我还想根据相关的属性值过滤这些项目。 示例:我想要名称中包含“foo”的类别项,其中属性“A”的值为1,属性B的值为2,依此类推。 我该如何实现这样的查询?

3 个答案:

答案 0 :(得分:0)

您可以链接ActiveRecord范围,包括where。因此,您可以先限制名称,然后链接另一个where以限制结果。下面的示例将限制属性“A”的值为1的结果,如您的问题中所述:

keywords = params[:keywords].downcase
@category.items.where("lower(items.name) like ?", "%#{keywords}%").where(:A => 1)

您还可以将范围存储在变量中。例如,如果要分别按属性A和B限制同一数据集,则可以执行以下操作:

keywords = params[:keywords].downcase
matched_by_name = @category.items.where("lower(items.name) like ?", "%#{keywords}%")
foo = matches_by_name.where(:A => 1)
bar = matches_by_name.where(:B => 1)

答案 1 :(得分:0)

您应该将表格加在一起,然后根据您的标准进行限制。

# Category items by name
Category.joins(:items).where(:items => { :name => keywords })

您可能会发现http://guides.rubyonrails.org/active_record_querying.html#joining-tables并致电.to_sql

答案 2 :(得分:0)

可以做到这一点的宝石:activerecord_where_assoc(我是作者)

有了它,您可以按照以下方式做您想做的事情:
我想要类别项目,其名称包含“ foo”,并且属性“ A”的值为1,属性B的值为2,依此类推。

@category.items.where(name: "foo").where_assoc_exists(:property_valuations) { |pv|
  pv.where(value: 1).where_assoc_exists(:property, name: 'A')
}.where_assoc_exists(:property_valuations) { |pv|
  pv.where(value: 2).where_assoc_exists(:property, name: 'B')
}

这显示了宝石的最大威力,可以无冲突地重用。进行join操作会很痛苦。但是,当需求很复杂时,结果也很稠密...使用范围可以轻松解决。

# In items:
scope :with_property, lambda {|name, value| 
  where_assoc_exists(:property_valuations) { |pv|
    pv.where(value: value).where_assoc_exists(:property, name: name)
}}

@category.items.where(name: "foo").with_property('A', 1).with_property('B', 2)

如果您想制作一个更强大的示波器,可以接收一个运算符,则可以通过更改where(value: value)部分来满足您的需要来实现。

这里是introductionexamples。在documentation中了解更多详细信息。