【发布时间】:2016-12-05 17:21:59
【问题描述】:
我正在尝试构建一个动态查询方法来过滤搜索结果。
我的模型:
class Order < ActiveRecord::Base
scope :by_state, -> (state) { joins(:states).where("states.id = ?", state) }
scope :by_counsel, -> (counsel) { where("counsel_id = ?", counsel) }
scope :by_sales_rep, -> (sales) { where("sales_id = ?", sales) }
scope :by_year, -> (year) { where("title_number LIKE ?", "%NYN#{year}%") }
has_many :properties, :dependent => :destroy
has_many :documents, :dependent => :destroy
has_many :participants, :dependent => :destroy
has_many :states, through: :properties
belongs_to :action
belongs_to :role
belongs_to :type
belongs_to :sales, :class_name => 'Member'
belongs_to :counsel, :class_name => 'Member'
belongs_to :deal_name
end
class Property < ActiveRecord::Base
belongs_to :order
belongs_to :state
end
class State < ActiveRecord::Base
has_many :properties
has_many :orders, through: :properties
end
我有一个默认显示所有订单的页面。我希望有复选框以允许过滤结果。过滤器是:年份、州、销售和顾问。一个查询示例是:2016 年、2015 年的所有订单(“order.title_number LIKE ?”、“%NYN#{year}%”)在 NJ、PA、CA 等州(has_many through)NJ、PA、CA 等,sales_id 无限制 id 和Counsel_id 无限制的 Counsel_id。
简而言之,我试图弄清楚如何创建一个考虑到用户检查的所有选项的查询。这是我当前的查询代码:
def Order.query(opt = {})
results = []
orders = []
if !opt["state"].empty?
opt["state"].each do |value|
if orders.empty?
orders = Order.send("by_state", value)
else
orders << Order.send("by_state", value)
end
end
orders = orders.flatten
end
if !opt["year"].empty?
new_orders = []
opt["year"].each do |y|
new_orders = orders.by_year(y)
results << new_orders
end
end
if !opt["sales_id"].empty?
end
if !opt["counsel_id"].empty?
end
if !results.empty?
results.flatten
else
orders.flatten
end
end
这是我想出的允许无限量过滤的解决方案。
def self.query(opts = {})
orders = Order.all
opts.delete_if { |key, value| value.blank? }
const_query = ""
state_query = nil
counsel_query = nil
sales_query = nil
year_query = nil
queries = []
if opts["by_year"]
year_query = opts["by_year"].map do |val|
" title_number LIKE '%NYN#{val}%' "
end.join(" or ")
queries << year_query
end
if opts["by_sales_rep"]
sales_query = opts["by_sales_rep"].map do |val|
" sales_id = '#{val}' "
end.join(" or ")
queries << sales_query
end
if opts["by_counsel"]
counsel_query = opts["by_counsel"].map do |val|
" counsel_id = '#{val}' "
end.join(" or ")
queries << counsel_query
end
if opts["by_state"]
state_query = opts["by_state"].map do |val|
"states.id = '#{val}'"
end.join(" or ")
end
query_string = queries.join(" AND ")
if state_query
@orders = Order.joins(:states).where("#{state_query}")
@orders = @orders.where(query_string)
else
@orders = orders.where("#{query_string}")
end
@orders.order("title_number DESC")
end
【问题讨论】:
-
您的意思是您需要一种方法来调用所有这些查询吗?因为在您的代码中您调用 by_state,它是一个,然后我假设 year 是另一个,依此类推。所以这不是一个查询。在那种情况下(如果是 4 个查询)我真的看不出有什么问题......
-
是的,我想用一个查询来调用所有内容。目前我正在尝试根据传递给查询方法的参数单独调用查询。参数的示例是 {"year"=>["16", "15"], "state"=>["31", "39"]}。我认为我的问题是能够在 _by_state 条件下多次调用 _by_year 。但不知多少年,州会发。我希望这是有道理的@Joel_Blum
-
为什么不尝试按照
scopes命名 opt_keys,例如{by_state: ["31","39"],by_year: "16"}那么你通常可以使用类似opts.inject(Order) {|order,(scope,value)| order.public_send(scope,value)}的东西。这将构建一个包含所有指定过滤器的 ActiveRecord::Relation。然后,当您对其采取行动时,查询实际上会触发。顺便说一句,如果您希望通过多年,您将需要修复by_year范围。 -
您可以使用在最近的 ruby 版本 (> 1.9) 中接受可选参数的范围方法。你用的是什么红宝石?
标签: ruby-on-rails ruby activerecord arel