使用动态 ransacker 进行分面搜索
Facet search with dynamic ransackers
我正在尝试使用 Rails 创建一个通用产品目录应用程序,为了让不同类型的产品具有不同的属性,我将产品属性抽象到它们自己的 table 中,并带有 link table 在产品和存储值的 属性 之间。
------------- --------------------
|products | |product_properties| ------------
|-----------| |------------------| |properties|
|name |---|value |---|----------|
|description| |product_id | |name |
|etc... | |property_id | ------------
------------- --------------------
例如,产品的宽度可能为 属性(将存储在 属性 table 中,以便重复使用),而宽度的值将被存储在 product_properties table 中记录了 link 产品的 属性。
这很好用,但我需要在产品模型中实现可分面搜索,并选择使用 ransack。所以要找到宽度大于 30 的所有产品,我必须做
Product.ransack(product_properties_property_name_eq: 'width', product_properties_value_gt: 30).result
这又可以正常工作,但我更愿意 'ransack' 使用 属性 名称
Product.ransack(width_gt: 30).result
是否有任何方法可以动态创建掠夺者(或替代方案)以允许我执行此操作?我试过使用 method_missing 但这让我很困惑。我正在考虑使用属性中的所有名称值在模型上创建范围 table 但我想我会先征求一些建议。
更新
我尝试在产品模型上实施一系列自定义洗劫程序
class Product < ActiveRecord::Base
Property.pluck(:name, :id).each do |name, id|
ransacker name, formatter: -> (value) { value.to_s.downcase } do
product_properties = Arel::Table.new(:product_properties)
product_properties[:value]
end
end
end
这让我越来越接近我能感觉到的答案。我还应该在这里做什么?
这很完美。这里的陷阱是 Arel::Nodes.build_quoted
。我最初把它排除在外,我不会得到 errors/warning 的回报,但我同样也不会得到任何结果,这让我很困惑。这显然只有在使用 Rails 4.2+ (Arel 6.0+) 时才有必要。
Property.pluck(:id, :name).each do |id, name|
product_properties = Arel::Table.new(:product_properties)
ransacker name.to_sym, formatter: -> (value) { value.to_s.downcase } do
Arel::Nodes::InfixOperation.new('AND',
Arel::Nodes::InfixOperation.new('=',
product_properties[:property_id], Arel::Nodes.build_quoted(id)
),
product_properties[:value]
)
end
end
要实际使用它,我需要明确地将 product_properties table 加入查询
Product.joins(:product_properties).ransack(width_gt: 30)
正如 ransack 文档所述,一些人在使用 ransackers 时遇到的困难并非源于 Ransack,而是因为不了解 Arel。这绝对是这里的情况。
我正在尝试使用 Rails 创建一个通用产品目录应用程序,为了让不同类型的产品具有不同的属性,我将产品属性抽象到它们自己的 table 中,并带有 link table 在产品和存储值的 属性 之间。
------------- --------------------
|products | |product_properties| ------------
|-----------| |------------------| |properties|
|name |---|value |---|----------|
|description| |product_id | |name |
|etc... | |property_id | ------------
------------- --------------------
例如,产品的宽度可能为 属性(将存储在 属性 table 中,以便重复使用),而宽度的值将被存储在 product_properties table 中记录了 link 产品的 属性。
这很好用,但我需要在产品模型中实现可分面搜索,并选择使用 ransack。所以要找到宽度大于 30 的所有产品,我必须做
Product.ransack(product_properties_property_name_eq: 'width', product_properties_value_gt: 30).result
这又可以正常工作,但我更愿意 'ransack' 使用 属性 名称
Product.ransack(width_gt: 30).result
是否有任何方法可以动态创建掠夺者(或替代方案)以允许我执行此操作?我试过使用 method_missing 但这让我很困惑。我正在考虑使用属性中的所有名称值在模型上创建范围 table 但我想我会先征求一些建议。
更新
我尝试在产品模型上实施一系列自定义洗劫程序
class Product < ActiveRecord::Base
Property.pluck(:name, :id).each do |name, id|
ransacker name, formatter: -> (value) { value.to_s.downcase } do
product_properties = Arel::Table.new(:product_properties)
product_properties[:value]
end
end
end
这让我越来越接近我能感觉到的答案。我还应该在这里做什么?
这很完美。这里的陷阱是 Arel::Nodes.build_quoted
。我最初把它排除在外,我不会得到 errors/warning 的回报,但我同样也不会得到任何结果,这让我很困惑。这显然只有在使用 Rails 4.2+ (Arel 6.0+) 时才有必要。
Property.pluck(:id, :name).each do |id, name|
product_properties = Arel::Table.new(:product_properties)
ransacker name.to_sym, formatter: -> (value) { value.to_s.downcase } do
Arel::Nodes::InfixOperation.new('AND',
Arel::Nodes::InfixOperation.new('=',
product_properties[:property_id], Arel::Nodes.build_quoted(id)
),
product_properties[:value]
)
end
end
要实际使用它,我需要明确地将 product_properties table 加入查询
Product.joins(:product_properties).ransack(width_gt: 30)
正如 ransack 文档所述,一些人在使用 ransackers 时遇到的困难并非源于 Ransack,而是因为不了解 Arel。这绝对是这里的情况。