동적 검색 방법을 구축하여 검색 결과를 필터링하려고합니다.레일 - 검색 결과 필터링을위한 동적 쿼리 작성
내 모델 :
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
나는 기본적으로 모든 주문을 표시하는 페이지가 있습니다. 결과 필터링을 허용하는 확인란을 갖고 싶습니다. 필터는 Year, State, Sales 및 Counsel입니다. 검색어의 예는 다음과 같습니다. 상태 (has_many부터 NJ, PA, CA 등)의 2016 년, 2015 년 ("order.title_number LIKE?", "% NYN # {year} %")의 모든 주문은 sales_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를 호출하기 때문에, 나는 1 년이라고 가정합니다. 그래서 하나의 쿼리가 아닙니다. 이 경우 (4 개의 쿼리 인 경우) 실제로 문제가 무엇인지 알지 못합니다 ... –
예 하나의 쿼리로 모든 것을 호출하려고합니다. 현재 쿼리 메서드에 전달 된 인수를 기반으로 쿼리를 개별적으로 호출하려고합니다. 인수의 예는 { "year"=> [ "16", "15"], "state"=> [ "31", "39"]}입니다. 제 생각에는 _by_year를 _by_state 조건으로 여러 번 호출 할 수있는 능력이 있다고 생각합니다. 그러나 나는 몇 년 동안 국가가 파견 될지 모른다. @Joel_Blum –
'scope '에 따라 opt_keys의 이름을 지어 보시지 않겠습니까? ''by_state : [ "31", "39"], by_year : "16"}'그러면 opts.inject (Order) {| order, (scope, value) | order.public_send (범위, 값)}'. 이렇게하면 지정된 모든 필터로 ActiveRecord :: Relation이 작성됩니다. 그런 다음에 행동 할 때 쿼리가 실제로 실행됩니다. BTW 여러 해를지기를 원하면'by_year' 범위를 수정해야합니다. – engineersmnky