views:

119

answers:

3

Hello everyone.

I have this piece of code in a model that sets a start date and end date according to the time of the day that the method is run.

Let's jump right into the code example:

#MODEL
now = Time.now
if now.hour >= 17 && now.hour <= 23
    #night
    n = now+1.day
    startd = Time.local(now.year, now.month, now.day, 17, 00, 00)
    endd = Time.local(n.year, n.month, n.day, 8, 00, 00)
elsif now.hour >= 0 && now.hour <= 7
    #morning
    n = now-1.day
    startd = Time.local(n.year, n.month, n.day, 8, 00, 00)
    endd = Time.local(now.year, now.month, now.day, 17, 00, 00)     
end

Then inside a model (same or another), I am trying to run this function inside a find.

#MODEL(SAME OR OTHER)
Model.find(:all, 
 :conditions => ['created_at >= ? AND created_at <= ?', startd, endd])

The problem is that I'm going to use that function to set the start and end dates a lot, and I dont know where to place it to not repeat myself. It's going to be used from different models.

Thanks for any help.

+3  A: 

You can include it in a module in the lib directory. All ruby files in RAILS_ROOT/lib are automatically loaded.

# time_calculations.rb

module TimeCalculations
  def calc_start_and_end_times
    now = Time.now
    if now.hour >= 17 && now.hour <= 23
        #night
        n = now+1.day
        startd = Time.local(now.year, now.month, now.day, 17, 00, 00)
        endd = Time.local(n.year, n.month, n.day, 8, 00, 00)
    elsif now.hour >= 0 && now.hour <= 7
        #morning
        n = now-1.day
        startd = Time.local(n.year, n.month, n.day, 8, 00, 00)
        endd = Time.local(now.year, now.month, now.day, 17, 00, 00)     
    end
    [startd, endd]
  end
end

# model.rb

class Model < ActiveRecord::Base
  extend TimeCalculations

  def self.my_find()
    startd, endd = calc_start_and_end_times
    Model.find(:all, 
      :conditions => ['created_at >= ? AND created_at <= ?', startd, endd])
  end

end

Edited to reflect final/correct answer.

erik
This sounded like a good solution, I tried that one already but it gave me "undefined method `calc_start_and_end_times' for #<Class:0xb6f3bb30>" error. I included the module on top of my model class. Any idea?
mickey
Try changing def self.calc_start_and_end_times to def calc_start_and_end_timesI couldn't remember if you need self or not on the method definition.
erik
Tried that too, sorry for not mentioning. It sounds like the model can't access the method from the Module.
mickey
Remove the "self." from the def in the module. When you import the module, since you're trying to modify the class itself, use: class << self import TimeCalculations end. The import goes on its own line; I can't format code in a comment here.
jdl
Here we go. Remove the self in "def self.calc_..." and use "extend TimeCalculations" instead of "include TimeCalculations". When you want to use class methods, you need extend. include is for instance methods.
erik
That worked! Thanks a lot for your help!
mickey
A: 

you can add method find_by_date_range (startd, endd) inside model class and use Model.find_by_date_range(something, something_else)

Alexey Poimtsev
So, where is the part that calculates the start and end datetime?
mickey
Let me explain. First of all you need to decide - will be start/end calculations used elsewhere in your code. If yes - it will be useful to move method, that responsible for calculations of start and end. Next step - develop find-method in your model, that will return all records by your criteria (erik have entered good example).And yet another helpful solution - you can use named_scope - http://apidock.com/rails/ActiveRecord/NamedScope/ClassMethods/named_scope
Alexey Poimtsev
correction for my comment - "If yes - it will be useful to move method, that responsible for calculations of start and end to the module, if not - it' not so necessary"
Alexey Poimtsev
+1  A: 

Hi mickey,

The simplest way is to add your code to a module, maybe in an initializer:

module SmartDates

  def start_date
    now = Time.now
    if now.hour >= 17 && now.hour <= 23
      #night
      n = now+1.day
      return Time.local(now.year, now.month, now.day, 17, 00, 00)
    elsif now.hour >= 0 && now.hour <= 7
      #morning
      n = now-1.day
      return Time.local(n.year, n.month, n.day, 8, 00, 00)
    end
  end

  def end_date
    now = Time.now
    if now.hour >= 17 && now.hour <= 23
      #night
      n = now+1.day
      return Time.local(n.year, n.month, n.day, 8, 00, 00)
    elsif now.hour >= 0 && now.hour <= 7
      #morning
      n = now-1.day
      return Time.local(now.year, now.month, now.day, 17, 00, 00)
    end
  end

end

# Now include your module
ActiveRecord::Base.include(SmartDates)
ActionController::Base.include(SmartDates)

Now start_date and end_date are available in both models and controllers.

mixonic
Thanks, the module code goes in /lib? What about the include code, where would you put it?
mickey
I'd probably put it in an initializer, as I mentioned above. In `config/initializers/smart_dates.rb` or something. Maybe I'd put the module in lib/ and the includes in the initializer.
mixonic