在模型上使用if作用域

Aar*_*mas 4 ruby-on-rails ruby-on-rails-3.1

我正在尝试创建一个名为:current_season的命名范围,它将正确识别与我们所在年份相关的记录.除了我希望6月及以后的所有内容使用当前年份以及6月之前的所有内容时,我非常容易使用去年.

在rails 3.1我可以轻松使用:

scope :current_season, lambda { where('season = ?',Time.now.year) } if Time.now.month >= 6
Run Code Online (Sandbox Code Playgroud)

如果我们在年底时才能使范围有效:

scope :current_season, lambda { where('season = ?',Time.now.year - 1) } if Time.now.month < 6
Run Code Online (Sandbox Code Playgroud)

但是,将它全部命名为两次并且不使用if/else类型的东西或者能够调用我在下面定义的内容以显示确切的年份似乎是浪费的,例如:

scope :current_season, lambda { where('season = ?',:current_season_year) } 

def current_season_year
  if Time.now.month >= 6
    Time.now.year
  else
    Time.now.year - 1
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试时,这只是嘲笑我.有更干净的方式吗?我也有一个范围:last_season和范围:previous_season最有可能,他们将遵循类似的逻辑.

提前感谢任何建议!

cor*_*ard 14

命名范围只是用于编写具有类似功能的类方法的DSL.每当你发现它们限制你时,只需切换到类方法:

def self.current_season
  year = Time.now.month >= 6 ? Time.now.year : Time.now.year - 1
  where('season = ?', year)
end
Run Code Online (Sandbox Code Playgroud)

当然,你也可以在这样的范围内包含它:

scope :current_season, do
  # same code as above...
end
Run Code Online (Sandbox Code Playgroud)

它只是将它定义为模型上的类方法.权衡是范围意图的明确(它预期会返回可链接的ActiveRecord::Relation)与文档的清晰度相比(如果运行类似RDoc的东西,它不会注意到可用的方法,Model.current_season因为它没有在代码中定义然而).

更新:

使用范围而不是类方法还有一个好处:

User.admin.create name: 'Corey'  #=> <User: @name="Corey" @admin=true>
Run Code Online (Sandbox Code Playgroud)

您也可以使用范围来创建具有特定参数的对象.在这种情况下,这不是很有用,但在决定使用哪个时,值得考虑.