March 3rd, 2009 By: Daniel
We ran into a few little gotchas with ActiveRecord’s find method when upgrading from Rails 2.1.1 to 2.2.2. The solutions are pretty trivial, so the main lesson here is to test your code so things like this get caught by your test suite and not the client.
Gotcha #1
>> Rails.version
=> "2.1.1"
>> Client.find_all_by_notify_by(%w(email txt both)).size
=> 2
>> Rails.version
=> "2.2.2"
>> Client.find_all_by_notify_by(%w(email txt both)).size
ActiveRecord::StatementInvalid: Mysql::Error: Operand should contain 1 column(s): SELECT * FROM `clients` WHERE (notify_by = 'email','txt','both' AND clients.deleted_at IS NULL)
>> Client.find(:all, :conditions => ["notify_by = ? OR notify_by = ? OR notify_by = ?", *%w(email txt both)]).size
=> 2
Gotcha #2
>> Rails.version
=> "2.1.1"
>> Client.find_all_by_agent_id(nil).size
=> 26
>> Rails.version
=> "2.2.2"
>> Client.find_all_by_agent_id(nil).size
=> 0
>> Client.find(:all, :conditions => "agent_id IS NULL").size
=> 26
April 29th, 2009 at 5:53 pm
I would like to point out a couple of things. First off, I would tend to avoid writing code with the named finders. The reason for this is that they are really a hack, what they do is wait for the undefined method error and then catch it and build the query from there. Repetitive use of those can slow your page load down.
Client.find(:all, :conditions => {:notify_by => %w(email txt both)}) will generate an sql query SELECT * FROM clients WHERE notify_by in (’email’,'txt’,'both’);
Client.find(:all, :conditions => {’projects.payment_type’ => %w(paying nonpaying both)}, :join => :project)
will generate
SELECT * FROM clients LEFT JOIN projects on clients.id = projects.client_id WHERE projects.payment_type in (’paying’,'nonpaying’,'both’);
Client.find(:all, :conditions => {:activated => true})
Will generate the expected where activated = 1
Client.find(:all, :conditions => {:created_at => (Time.now-30.days)..Time.now})
Will generate created_at BETWEEN (’2009-04-1′, ‘2009-04-30′)
Client.find(:all, :conditions => {:agent => nil})
Will generate agent IS NULL
April 30th, 2009 at 9:02 am
May 12th, 2009 at 8:49 pm
May 16th, 2009 at 12:27 am
def method_missing(name, *args, &block)
if name.to_s =~ /^find_by_/
method = Proc.new { #some dynamic finder code }
class << self.class
self.define_method(name, method)
end
self.send(name, *args, block)
end
end
end
May 18th, 2009 at 9:51 am