我这样做
@orders = Order.unscoped.dated
@orders = @orders.search_for(params["search"]) if params["search"].present?
@orders = @orders.where(:items_received_status => true) if params[:air].present? && params[:air] == 't'
@orders = @orders.tagged_with(params[:tags]) if params[:tags].present?
是否有更好的方法来编写相同的代码
类似
@orders = Order do
self.where(some condition)
self.joins(some table)
end
应该有办法避免重复赋值运算符
答案 0 :(得分:1)
我认为最简单的方法是为此创建模型方法:
class Order
def self.air(air)
return self.where(items_received_status: true) if air == 't'
self
end
def search(search...
所以你可以在控制器中链接它,如下所示:
Order.unscoped.dated.air(params[:air]).seach(...
答案 1 :(得分:0)
你可以这样做。它本质上是相同的代码,但它更整洁,因为逻辑并没有模糊正在做的事情:
@orders = build_orders
...
# In pure ruby, this is fine as a private method.
# In rails, it would be better to have this method in the `Order` model,
# perhaps split up as separate methods as Sergey Moiseev mentions.
private
def build_orders
orders = Order.unscoped.dated
orders = orders.search_for(params["search"]) if params["search"].present?
orders = orders.where(:items_received_status => true) if params[:air].present? && params[:air] == 't'
orders = orders.tagged_with(params[:tags]) if params[:tags].present?
orders
end
答案 2 :(得分:0)
您可以将查询委托给代理BasicObject
的{{1}}。
ActiveRecord::Relation
这里发生的是您将代理调用方法调用到ActiveRecord :: Relation,该调用是通过调用scope返回的。然后,如果您的代理返回ActiveRecord :: Relations或其子类的方法,if将该结果分配给委托目标。
然后你会这样做:
class QueryDelegator < BasicObject
def initialize(target)
@target = target
end
def method_missing(*args, &block)
result = target.send(*args, &block)
@target = result if result.kind_of? @target.class
result
end
end
或者你可以进一步重构并做:
@orders = QueryDelegator.new(Order.unscoped.dated)
@orders.search_for(params["search"]) if params["search"].present?
@orders.where(:items_received_status => true) if params[:air].present? && params[:air] == 't'
@orders.tagged_with(params[:tags]) if params[:tags].present?
然后在您的控制器中调用您的搜索,如下所示:
class Order < ActiveRecord::Base
# ...
def self.search(params)
orders = query_builder(unscoped.dated)
orders.search_for(params["search"]) if params["search"].present?
orders.where(:items_received_status => true) if params[:air].present? && params[:air] == 't'
orders.tagged_with(params[:tags]) if params[:tags].present?
end
def self.query_builder(scope = nil)
scope ||= scoped
QueryDelegator.new(scope)
end
end
Ryan Bates对这种模式做了RailsCast。使用自负。正如一些评论者所说,你可能只是为了方便而牺牲了可读性。