views:

104

answers:

4

I'm struggling with the conditions for date querying in the 'find' method on my ActiveRecord models running over an SQLite3 database. My model is as follows:

Day:
  failure_day:   date
  failure_count: integer 

When I attempt to query Days, I get the following (pseudo code only):

Query:   Days.all
Result:  [{failure_day: 2010-04-14, failure_count: 1}]

Query:   Days.find(:first, :conditions=>'failure_day > 2010-02-01')
Result:  {failure_day: 2010-04-14, failure_count: 1}

Query:   Days.find(:first, :conditions=>'failure_day = 2010-04-14')
Result:  nil

Query:   Days.find(:first, :conditions=>'failure_day < 2010-05-05')
Result:  nil

What I can't understand is why the last two queries return 'nil'. The first query (Days.all) proves that I have a record in my database. The second one correctly matches 'failure_day' against a date that is less than 'failure_day', but when trying equal or less than it doesn't work.

Any ideas?

A: 

you should use

Days.find(:first, :conditions=>["DATE_FORMAT(failure_day, '%Y-%m-%d') > '2010-02-01'"])

Days.find(:first, :conditions=>["DATE_FORMAT(failure_day, '%Y-%m-%d') = '2010-04-14'"])

Days.find(:first, :conditions=>["DATE_FORMAT(failure_day, '%Y-%m-%d') < '2010-05-05'"])
Salil
Ok.. that looks feasible. What about if I am comparing an actual date object (:conditions => ["failure_day=?", my_date]). Do I still need DATE_FORMAT?
Aaron Janes
+2  A: 

You only provided pseudo-code, which makes it harder.

You're telling us that your failure_date column is of type DATE. Just let ActiveRecord handle the details for you:

Day.all(:conditions => {:failure_date => Date.today})
Day.all(:conditions => ["failure_date < ?", Date.today])
Day.all(:conditions => {:failure_date => Date.new(1900, 1, 1) .. 5.days.ago})
François Beausoleil
I agree this should work, but for some reason it doesn't. I get one record with: Day.all('SELECT * FROM "days" WHERE (failure_day < \'2010-05-14\')') No records with: Day.all(:conditions=>["failure_day < ?", '2010-04-14'])If I do a deliberate syntax error: Day.all(:conditions=>["failure_day < '?'", '2010-05-14'])I get an error: syntax error: SELECT * FROM "days" WHERE (failure_day < ''2010-05-14'')Clearly it is trying to execute the correct SQL (exactly the same as the first example except the extra quotes) but it doesn't work without using explicit SQL! What is going on??!
Aaron Janes
What version of ActiveRecord, SQLite, Ruby are you using? Post a gist of a session where we can see the code you enter at the console and what's in development.log
François Beausoleil
Due to the need for formatting, I've posted an answer to your comment above.
Aaron Janes
Thanks for the tip about viewing the log. I'm pretty new to Rails and hadn't seen the logs yet, really useful.
Aaron Janes
A: 

This is an answer to the comments by François Beausoleil: "What version of ActiveRecord, SQLite, Ruby are you using? Post a gist of a session where we can see the code you enter at the console and what's in development.log"

I'm putting it here because I can't get formatting in a comment and this post will be pretty much unreadable without formatting!

SQLite version:       3.6.12
ActiveRecord version: 2.3.5

Test code:

require 'test_helper'

class StatTest < ActiveSupport::TestCase
  test "Tmp" do
    # Prints: [#<Day id: 980190962, failure_day: "2010-04-14" ... >]
    p Day.all

    # Prints: []
    p Day.all(:conditions=>["failure_day < ?", '2010-05-14'])

    # Prints: []
    p Day.all(:conditions=>["failure_day < ?", Date.new(2010,5,4)])
  end
end

Test.log

Day Load (0.3ms)   SELECT * FROM "days" 
Day Load (0.1ms)   SELECT * FROM "days" WHERE (failure_day < '2010-05-14') 
Day Load (0.1ms)   SELECT * FROM "days" WHERE (failure_day < '2010-05-04') 

Running any of those commands directly from SQLite returns the expected rows, so the issue isn't with the SQLite command that ActiveRecord is generating. Bizarre.

Aaron Janes
In your test above, you don't generate any records. Did you know the that tests run in a separate DB? Thus, if you don't create any instances (or have fixtures generate instances for you), it is expected to have no records.
François Beausoleil
Bingo! Yes, I know about fixtures and the fact that tests run on a different DB. I also verified that the fixture was loading data (via the 'p Day.all' command returning records). What the problem was is that in the fixture I was defining the failure_day as 'failure_day: 2010/04/14' which Rails was translating to a string. Changed it to 'failure_day: 2010-04-14' and the fixture loaded the data as a date and all three queries worked! Thanks for your help in sparking off those ideas.
Aaron Janes
A: 

Thanks to the probing questions of François Beausoleil I was able to figure out what was wrong. François reminded me that tests load data from the test fixtures (in my case test/fixtures/days.yml). I had already set this up but thought I'd better double check the format. In the days.yml file I discovered:

one:
  failure_day:   2010/04/14
  failure_count: 1

Noticing that the date wasn't defined as 2010-04-14 as in the tests so I changed it to:

one:
  failure_day:   2010-04-14
  failure_count: 1

All queries now work!

Aaron Janes