views:

42

answers:

1

I have a table of events (in a sqlite3 database for what it's worth) with a column called "when" that contains a timestamp detailing precisely when the event that particular row denotes is set to occur. Right now, I have

@events = Event.find(:all)

in my controller and I am using template helper methods to calculate where to place each event on my display page based on the day of the week it occurs on. For example:

<% if(event.when.wday == 6) %>
    # DO SOMETHING
<% end %>

I want to abstract this logic to the controller however. My idea was to do the following:

@thursday_events = Event.find(:all, :conditions => ["when.wday=4"])

Obviously (I guess?) this didn't work. Throwing the error "SQLite3::SQLException: near "when": syntax error: SELECT * FROM "events" WHERE (when.wday=4)".

I'm assuming this is because I tried to use a helper method within a find condition but I don't know a better way to do this. Any advice? Thanks!

+1  A: 

The conditions parameter needs to be a fragment of SQL.

:conditions => ["when.wday=4"]

is a fragment of Ruby code, so no go.

Try

# Model Event has a datetime field named 'when'
Event.find(:all, :conditions => ["strftime('%w', events.when) = 4"])

SQLLite ref: http://www.sqlite.org/lang_datefunc.html

Added:

While more closely reading your post, I think you're planning to send multiple instance variables (one per day of the week) from your controller to your view. That's a good idea--moving logic out of the view. But, don't do more dbms queries!

Each query has significant overhead. Eg:

#Do NOT do it this way (too many db queries)
@sunday_events = Event.find(:all, 
   :conditions => ["strftime('%w', events.when) = 0"])
@monday_events = Event.find(:all, 
   :conditions => ["strftime('%w', events.when) = 1"])
@thursday_events = Event.find(:all, 
   :conditions => ["strftime('%w', events.when) = 4"])
# ... etc

# Better: Just 1 database query--
events = Event.find(:all)
@sunday_events   = events.select{|e| e.when.wday == 0}
@monday_events   = events.select{|e| e.when.wday == 1}
@thursday_events = events.select{|e| e.when.wday == 4} 
# ... etc

Final comment:

Current best practice thinking is to move code into the models from controllers wherever reasonable. This is called "Fat model, skinny controller" In the above example, you could have a class-level method in the model create the individual instance variables. Or perhaps better, one hash that contains 7 values, each being an array of the records. Eg

# in Event model
def Event.find_by_day
  events = Event.find(:all)
  result = {}
  days = [:sun, :mon, :tue, :wed, :thu, :fri, :sat]
  (0..6).each{|day_i| result[days[day_i]] = 
                        events.select{|e| e.when.wday == day_i}
              }

  result
end

# in controller
@events = Event.find_by_day

# in view
# @events[:sun] is array of the Sunday events
#   so do something with them...
Larry K
Thanks! This is perfect and extremely helpful in guiding me toward correct practices as I explore RoR for the first time. Much appreciated!
Pygmalion
One last question:Should that class-level method in the model go within the Events class? And if so, should it be "self.find_by_day"?
Pygmalion
Glad to be of help. Yes, the class-level method for the model would be in the Event class (singular word Event). That is, the event.rb file, representing the events (plural) table. For a class method, def self.find_by_day is the *exact same as* def Event.find_by_day since self (in this context) turns into Event
Larry K