Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using if with scope on model

I am trying to make a named scope called :current_season where the it will correctly identify the records associated with the year we are in. Mostly easy enough except I want everything June and later to use the current year and everything prior to June to use the previous year.

in rails 3.1 I can easily use:

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

to get the scope to only work if we are at the end of the year and :

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

But it seems to wasteful to have to name it all twice and not use an if/else type of thing or be able to call in something I define below to show the exact year such as:

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

But that just laughs at me when I try it. Is there a cleaner way? I will also have a scope :last_season and scope :previous_season most likely and they will follow similar logic.

thanks in advance for any advice!

like image 334
Aaron Thomas Avatar asked Dec 07 '22 19:12

Aaron Thomas


1 Answers

Named scopes are just a DSL for writing a class methods that all have a similar functionality. Whenever you find them to be limiting you, just switch to a class method instead:

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

Of course, you could also include that in a scope like this:

scope :current_season, do
  # same code as above...
end

It's just going to define it as a class method on the model though. The tradeoff is clarity in the intention of a scope (it's expected to return a chainable ActiveRecord::Relation) versus clarity in documentation (if you run something like RDoc it isn't going to notice a method available at Model.current_season because it hasn't been defined in the code yet).

Update:

There is one additional benefit from using a scope instead of a class method:

User.admin.create name: 'Corey'  #=> <User: @name="Corey" @admin=true>

You can use a scope to create an object with certain parameters, as well. In this case, this isn't very useful, but it's worth considering when deciding which to use.

like image 59
coreyward Avatar answered Dec 20 '22 05:12

coreyward