Matthew Palmer
2006-Feb-10 02:34 UTC
[Rails] Auto-generated find queries adding bogus WHERE clauses
[Sorry for the poor subject; this is really hard to explain] I''m trying to run a search over several objects which themselves contain multiple model objects, like so: class Collection << ActiveRecord::Base def findpkg self.repositories.each do |r| p = r.packages.find(:all, :conditions => "name like ''%pkg%''") end end end Unfortunately, AR proceeds to generate SQL that looks like this: Package Load (0.000548) SELECT * FROM packages WHERE (packages.repository_id = 3 AND (name like ''%pkg%'')) Package Load (0.000167) SELECT * FROM packages WHERE (packages.repository_id = 4 AND (packages.repository_id = 3 AND (name like ''%pkg%''))) Package Load (0.000151) SELECT * FROM packages WHERE (packages.repository_id = 5 AND (packages.repository_id = 4 AND (packages.repository_id = 3 AND (name like ''%pkg%'')))) Package Load (0.000160) SELECT * FROM packages WHERE (packages.repository_id = 13 AND (packages.repository_id = 5 AND (packages.repository_id = 4 AND (packages.repository_id = 3 AND (name like ''%pkg%''))))) Note that each successive query prepends an extra clause, instead of replacing the previous repository_id clause. Has anyone seen anything like this? I can provide relevant chunks of code on request, but I''m not doing anything exciting in my models -- just standard sorts of has_many relationships. I''ll turn this into a bug report if needed, I just want to get a reality check before I go nuts. - Matt
Matthew Palmer
2006-Feb-11 05:57 UTC
Re: Auto-generated find queries adding bogus WHERE clauses
[Please respect MFT to rails-core; I think most of the discussion of this, if any, will be more topical there] On Fri, Feb 10, 2006 at 01:33:32PM +1100, Matthew Palmer wrote:> class Collection << ActiveRecord::Base > def findpkg > self.repositories.each do |r| > p = r.packages.find(:all, :conditions => "name like ''%pkg%''") > end > end > endThe bug is that HasManyAssociation#find modifies it''s arguments, so the above (slightly fictionalised) variant is misleading; the real code is: def findpkg(*args) self.repositories.each do |r| p = r.packages.find(*args) # Do things with p end end Adding "puts args.inspect" before and after the call to find() shows that args is in fact being modified, by the fact that the options object is the same as args[1] on the entry to HasManyAssociation#find. This simple patch makes the whole problem go away: ------8<------ --- has_many_association.rb 2006-02-10 16:37:32.000000000 +1100 +++ has_many_association.rb.orig 2006-02-10 16:37:21.000000000 +1100 @@ -51,7 +51,7 @@ end def find(*args) - options = Base.send(:extract_options_from_args!, args).dup + options = Base.send(:extract_options_from_args!, args) # If using a custom finder_sql, scan the entire collection. if @options[:finder_sql] ------>8------ I''m planning on reporting this in Trac, but I''m curious about people''s opinions -- is it reasonable to assume that arguments which appear, on the surface, to be read-only may be modified by called methods? - Matt