我试图实现条件链接,这就是我得到的:
控制器索引操作代码:
@range_start = params[:range_start]
@range_stop = params[:range_stop]
Contract.within_range(@range_start, @range_stop)
型号代码:
def self.within_range(range_start = Date.today - 1.month, range_stop = nil)
self.started_after(range_start).started_before(range_stop)
end
def self.started_after(range_start)
if range_start.blank?
self
else
self.where('start_date >=?', range_start)
end
end
def self.started_before(range_stop)
if range_stop.blank?
self
else
self.where('start_date<=?', range_stop)
end
end
它有效,但看起来不太好。我尝试使用tap
稍微改进一下,但没有成功。如何改进此代码?
更新:在可以转换为内联条件,但也许可以改进其他东西?
range_start.blank? ? self : self.where('start_date >=?', range_start)
UPDATE2:如果未设置range_stop
,则此代码无效,started_after
条件不适用。
我必须从started_before
返回到不放松的第一个条件?
答案 0 :(得分:10)
时间已过,denis.peplin的解决方案已被弃用。否则它是正确的,你需要一个链接关系。因此,不应使用scoped
,而应使用all
,如下所示:
def self.started_before(range_stop)
if range_stop.blank?
all
else
where('start_date<=?', range_stop)
end
end
但你也可以把它写成一个更简洁的范围:
scope :started_before, ->(range_stop){ range_stop.blank? ? all : where('start_date<=?', range_stop) }
答案 1 :(得分:3)
在红宝石世界中,有一种名为scope
的东西可以满足您的需要。
scope :started_after, lambda {|x| where("start_date >=?", x) }
scope :started_before, lambda{|x| where("start_date <=?", x) }
或在一行
scope :starts_between, lambda{|start,finish| where("start_date >=? AND start_date <= ?", start, finish) }
范围是一种有效的记录功能,因此您只需调用:
Contract.starts_between(date1, date2)
如果希望secound参数有条件:
def self.within_range(start, finish = nil)
data = Contract.started_after(start)
data = data.started_before(finish) unless finish.nil?
data
end
答案 2 :(得分:3)
我想尝试澄清以这种方式进行条件链接的目的:想法是在某些方法和链式方法中隐藏条件,因此生成的方法将很简单。
有可能,但ActiveRecord :: Base类的子节点本身无法链接。只有关系可以链接。
所以不要这样做:
def self.started_before(range_stop)
if range_stop.blank?
self
else
self.where('start_date<=?', range_stop)
end
end
应该这样做:
def self.started_before(range_stop)
if range_stop.blank?
scoped
else
self.where('start_date<=?', range_stop)
end
end
只有一项更改:self
已替换为scoped
,现在方法始终返回范围,并且可以进行链接。
感谢这篇文章的提示:http://blog.mitchcrowe.com/blog/2012/04/14/10-most-underused-activerecord-relation-methods/
答案 3 :(得分:1)
我添加了这个:
scope :dynamic, -> (chain=nil) { chain.present? ? chain.call : nil }
现在你可以像这样使用它了
conditional_scope = x ? Model.scope1 : Model.scope2
Model.scope3.dynamic(conditional_scope).scope4