Learning something new every day
Posted by christine - 12/02/09 at 03:12:34 amAfter staring at a rake task for twenty minutes and manually testing some cases in a console, I’ve got some interesting larnin’s about ActiveRecord::Base.find and what it does with an options hash.
Background
There are typically two ways to provide conditions for a database search via ActiveRecord. The first is find, which looks like this most of the time: User.find(:all, :conditions => {:first_name => 'Bob', :last_name => 'Smith'}, :limit => 5). find takes two arguments: {:all, :first, :last}, and an options hash (more here).
Or taking advantage of existing relationships, which basically ORM-magic away a one-to-many foreign-key relationship between tables, e.g. some_user.files would return an array of some_user’s File objects. So on and so forth.
And a third way, which I like and think cleans things up really nicely but is apparently not relevant to this bit of learning, is using named scopes (more references) – essentially, a way to wrap up any part of that options hash into what looks like a method on the model itself. An example involving a female named scope on our beloved Usermodel.
class User < ActiveRecord::Base
named_scope :female, :conditions => {:gender => 'female'}
end
This allows you to not only get all female Users by calling User.female, but also allows combining of named scopes and the find method to minimize repetition and narrow the scope of a query. For example:
User.female.find(:all, :conditions => {:first_name => 'Christine'})
But wait!
In a script I was working on recently, I needed to loop through an array, and look something up at each step:
args = { :select => 'some_attr_id', :limit => 5 }
user_array.each do |user|
if condition
files = user.files.published.find(:all, args)
else
files = user.files.unpublished.find(:all, args)
end
... < do stuff with the files >
end
Interestingly enough, as args passed through the loop each time, it picked up the parameters added by the user-files relationship! Meaning, the first time through the loop with User 1, the args hash looked like this:
{:include=>nil, :readonly=>nil,
:conditions=>"`files`.user_id = 1",
:joins=>nil, :select=>"some_attr_id", :group=>nil,
:offset=>nil, :limit=>5, :having=>nil, :order=>"files.created_at DESC"}
… which makes all sorts of sense, considering a query like user.files.published would just be a search across some files table with user_id and a published conditions, but how irritating that the args hash was 1) mutable at all, and 2) modified by being passed into the ActiveRecord query!,
1 Comment »
RSS feed for comments on this post. TrackBack URI
Leave a comment
Powered by WordPress with GimpStyle Theme design by Horacio Bella.
Entries and comments feeds.
Valid XHTML and CSS.
so I guess you got burned by reusing args in a following .find() query and not getting data. amirite? or maybe the query generator would recognize the bogus clause? sounds like a very awful bug to hunt down. yes too many things are mutable in ruby! I’m actually just referring to strings. immutable hashes would be helpful too. I have a little class in python called frozendict. it helps when something expects a
dict but often the dict is empty, this let’s me reuse
the empty frozendict object as nauseum. helpful for not thrashing my heap although I don’t think people on the server side care that much about memory usage. it’s not such a big deal to restart a process. but imagine if firefox suddenly restarted itself! lol keep up the coding posts plz
Comment by rian — December 2, 2009 #