在我的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,依此类推。 我该如何实现这样的查询?
答案 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)
部分来满足您的需要来实现。
这里是introduction和examples。在documentation中了解更多详细信息。