As suggested in my thread in Ruby On Rails: Talk (http:// groups.google.com/group/rubyonrails-talk/browse_thread/thread/ 66ae64e6581a3896) i''m posting an issue i''m having with Rails 2.0 and overloading find_by methods here. Hoepfully someone can either suggest what I am doing wrong and should be doing instead to get this working, or tell me where to submit a bug report so this can get fixed if it is not desired behaviour: This came up when I migrated from rails 1.2.3 to 2.0.2. Previously, my code was working fine. I am using a mysql backend database, in which I am storing IPv4 addresses as 32 bit unsigned integers. Of course, I don''t want my users to have to enter the IP they are searching for in this fashion, nor do I want to have to make the conversion myself every time I call the find_by_ip function or find_or_create_by_ip function for the model, so I have overloaded those two functions. find_by_ip now reads as follows: def self.find_by_ip(ip) super(NetAddr::CIDR.create(ip).to_i) end This works, the first time Ip.find_by_ip(address) is called (this test done in script/console):>> ip = Ip.find_by_ip("10.21.1.8")=> #<Ip id: 13, ip: 169148680> However any subsequent calls to find_by_ip just return nil, even for the same IP address, until the environment is reloaded:>> reload!Reloading... => true>> ip = Ip.find_by_ip("10.21.1.8")=> #<Ip id: 13, ip: 169148680>>> ip = Ip.find_by_ip("10.21.1.8")=> nil If I add some puts statements in my overloaded find_by_ip, they never get printed out after the first call to it has been done. Equally, if I call find_by_ip with a 32 bit int form of an IPv4 address it works reliably: def self.find_by_ip(ip) puts "Testing\n" super(NetAddr::CIDR.create(ip).to_i) end ?> reload! Reloading... => true>> ip = Ip.find_by_ip("10.21.1.8")Testing => #<Ip id: 13, ip: 169148680>>> ip = Ip.find_by_ip("10.21.1.8")=> nil>> ip = Ip.find_by_ip(169148680)=> #<Ip id: 13, ip: 169148680> It is as if, after the first call to my overloaded find_by_ip, rails decides to ignore my overloaded function and go straight to the base functionality it has for creating find_by functions. The suggestion was that, in Rails 2.0, instead of calling the method_missing function every time I call super() from within a find_by_function (as there is no specific find_by function of that name in ActiveRecord::Base), it instead creates the find_by_ip function, which overwrites my one, and subsequent calls hit that and thus don''t get the IP address converted to an int, and thus don''t find any matching record in the database. I am assuming this change was made for speed, as as long as you are not overloading a find_by function it will be faster if the function is pre-generated instead of having to be created every time it is called, but what can I do to fix this? Is the best fix to call my ''overload'' function get_by_ip (or similar), so that the created find_by_ip function doesn''t have a namespace conflict, and then call self.find_by_ip from within that once I have got my IP in numerical format? This does work, but does mean that my code is sometimes using find_by and sometimes using get_by (or whatever), which makes it harder for anyone following to debug as it is not consistent. Thanks Dan Meyers Network Support, Lancaster University --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Jan De Poorter
2008-Jan-16 15:37 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
Hi, When you call a dynamic finder action (in your case find_by_ip), the ruby method_missing function is called. This magic functions takes the function you requested and creates it, which causes your function to be overwritten in favor of the created function. When you reload!, your model gets loaded again, and the created function is overwritten again. This isn''t to be expected ofcourse. Could you file a bug about this on http://dev.rubyonrails.com ? Regards, DefV On 16 Jan 2008, at 16:26, Carr0t wrote:> > As suggested in my thread in Ruby On Rails: Talk (http:// > groups.google.com/group/rubyonrails-talk/browse_thread/thread/ > 66ae64e6581a3896) i''m posting an issue i''m having with Rails 2.0 and > overloading find_by methods here. Hoepfully someone can either suggest > what I am doing wrong and should be doing instead to get this working, > or tell me where to submit a bug report so this can get fixed if it is > not desired behaviour: > > This came up when I migrated from rails 1.2.3 to 2.0.2. Previously, my > code was working fine. I am using > a mysql backend database, in which I am storing IPv4 addresses as 32 > bit unsigned integers. Of course, I don''t want my users to have to > enter the IP they are searching for in this fashion, nor do I want to > have to make the conversion myself every time I call the find_by_ip > function or find_or_create_by_ip function for the model, so I have > overloaded those two functions. find_by_ip now reads as follows: > > def self.find_by_ip(ip) > super(NetAddr::CIDR.create(ip).to_i) > end > > This works, the first time Ip.find_by_ip(address) is called (this test > done in script/console): > >>> ip = Ip.find_by_ip("10.21.1.8") > => #<Ip id: 13, ip: 169148680> > > However any subsequent calls to find_by_ip just return nil, even for > the same IP address, until the environment is reloaded: > >>> reload! > Reloading... > => true >>> ip = Ip.find_by_ip("10.21.1.8") > => #<Ip id: 13, ip: 169148680> >>> ip = Ip.find_by_ip("10.21.1.8") > => nil > > If I add some puts statements in my overloaded find_by_ip, they never > get printed out after the first call to it has been done. Equally, if > I call find_by_ip with a 32 bit int form of an IPv4 address it works > reliably: > > def self.find_by_ip(ip) > puts "Testing\n" > super(NetAddr::CIDR.create(ip).to_i) > end > > ?> reload! > Reloading... > => true >>> ip = Ip.find_by_ip("10.21.1.8") > Testing > => #<Ip id: 13, ip: 169148680> >>> ip = Ip.find_by_ip("10.21.1.8") > => nil >>> ip = Ip.find_by_ip(169148680) > => #<Ip id: 13, ip: 169148680> > > It is as if, after the first call to my overloaded find_by_ip, rails > decides to ignore my overloaded function and go straight to the base > functionality it has for creating find_by functions. The suggestion > was that, in Rails 2.0, instead of calling the method_missing function > every time I call super() from within a find_by_function (as there is > no specific find_by function of that name in ActiveRecord::Base), it > instead creates the find_by_ip function, which overwrites my one, and > subsequent calls hit that and thus don''t get the IP address converted > to an int, and thus don''t find any matching record in the database. I > am assuming this change was made for speed, as as long as you are not > overloading a find_by function it will be faster if the function is > pre-generated instead of having to be created every time it is called, > but what can I do to fix this? Is the best fix to call my ''overload'' > function get_by_ip (or similar), so that the created find_by_ip > function doesn''t have a namespace conflict, and then call > self.find_by_ip from within that once I have got my IP in numerical > format? This does work, but does mean that my code is sometimes using > find_by and sometimes using get_by (or whatever), which makes it > harder for anyone following to debug as it is not consistent. > > Thanks > > Dan Meyers > Network Support, Lancaster University > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Jan-16 15:41 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
On 16 Jan 2008, at 15:37, Jan De Poorter wrote:> > Hi, > > When you call a dynamic finder action (in your case find_by_ip), the > ruby method_missing function is called. This magic functions takes the > function you requested and creates it, which causes your function to > be overwritten in favor of the created function. When you reload!, > your model gets loaded again, and the created function is overwritten > again. This isn''t to be expected ofcourse.I reached that conclusion over on rails-talk, but I''m not entirely sure what do about it check whether the method that''s about to be created exists and if so use a different (but predictable) name so that in your own find_by_x function you can call the ''normal'' find_by_x Fred> > > Could you file a bug about this on http://dev.rubyonrails.com ? > > Regards, > DefV > > On 16 Jan 2008, at 16:26, Carr0t wrote: > >> >> As suggested in my thread in Ruby On Rails: Talk (http:// >> groups.google.com/group/rubyonrails-talk/browse_thread/thread/ >> 66ae64e6581a3896) i''m posting an issue i''m having with Rails 2.0 and >> overloading find_by methods here. Hoepfully someone can either >> suggest >> what I am doing wrong and should be doing instead to get this >> working, >> or tell me where to submit a bug report so this can get fixed if it >> is >> not desired behaviour: >> >> This came up when I migrated from rails 1.2.3 to 2.0.2. Previously, >> my >> code was working fine. I am using >> a mysql backend database, in which I am storing IPv4 addresses as 32 >> bit unsigned integers. Of course, I don''t want my users to have to >> enter the IP they are searching for in this fashion, nor do I want to >> have to make the conversion myself every time I call the find_by_ip >> function or find_or_create_by_ip function for the model, so I have >> overloaded those two functions. find_by_ip now reads as follows: >> >> def self.find_by_ip(ip) >> super(NetAddr::CIDR.create(ip).to_i) >> end >> >> This works, the first time Ip.find_by_ip(address) is called (this >> test >> done in script/console): >> >>>> ip = Ip.find_by_ip("10.21.1.8") >> => #<Ip id: 13, ip: 169148680> >> >> However any subsequent calls to find_by_ip just return nil, even for >> the same IP address, until the environment is reloaded: >> >>>> reload! >> Reloading... >> => true >>>> ip = Ip.find_by_ip("10.21.1.8") >> => #<Ip id: 13, ip: 169148680> >>>> ip = Ip.find_by_ip("10.21.1.8") >> => nil >> >> If I add some puts statements in my overloaded find_by_ip, they never >> get printed out after the first call to it has been done. Equally, if >> I call find_by_ip with a 32 bit int form of an IPv4 address it works >> reliably: >> >> def self.find_by_ip(ip) >> puts "Testing\n" >> super(NetAddr::CIDR.create(ip).to_i) >> end >> >> ?> reload! >> Reloading... >> => true >>>> ip = Ip.find_by_ip("10.21.1.8") >> Testing >> => #<Ip id: 13, ip: 169148680> >>>> ip = Ip.find_by_ip("10.21.1.8") >> => nil >>>> ip = Ip.find_by_ip(169148680) >> => #<Ip id: 13, ip: 169148680> >> >> It is as if, after the first call to my overloaded find_by_ip, rails >> decides to ignore my overloaded function and go straight to the base >> functionality it has for creating find_by functions. The suggestion >> was that, in Rails 2.0, instead of calling the method_missing >> function >> every time I call super() from within a find_by_function (as there is >> no specific find_by function of that name in ActiveRecord::Base), it >> instead creates the find_by_ip function, which overwrites my one, and >> subsequent calls hit that and thus don''t get the IP address converted >> to an int, and thus don''t find any matching record in the database. I >> am assuming this change was made for speed, as as long as you are not >> overloading a find_by function it will be faster if the function is >> pre-generated instead of having to be created every time it is >> called, >> but what can I do to fix this? Is the best fix to call my ''overload'' >> function get_by_ip (or similar), so that the created find_by_ip >> function doesn''t have a namespace conflict, and then call >> self.find_by_ip from within that once I have got my IP in numerical >> format? This does work, but does mean that my code is sometimes using >> find_by and sometimes using get_by (or whatever), which makes it >> harder for anyone following to debug as it is not consistent. >> >> Thanks >> >> Dan Meyers >> Network Support, Lancaster University >>> > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
From: rubyonrails-core@googlegroups.com [mailto:rubyonrails-core@googlegroups.com] On Behalf Of Jan De Poorter>When you call a dynamic finder action (in your case find_by_ip), the >ruby method_missing function is called. This magic functions takes the >function you requested and creates it, which causes your function to >be overwritten in favor of the created function. When you reload!, >your model gets loaded again, and the created function is overwritten >again. This isn''t to be expected ofcourse.I must be missing something, because I don''t see how the "manual" method could be overwritten. The creation of the dynamic finder happens in method_missing, which wouldn''t be called if the method existed, right? ///ark --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Matthew Palmer
2008-Jan-16 19:36 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
On Wed, Jan 16, 2008 at 07:26:00AM -0800, Carr0t wrote:> This came up when I migrated from rails 1.2.3 to 2.0.2. Previously, my > code was working fine. I am using > a mysql backend database, in which I am storing IPv4 addresses as 32 > bit unsigned integers. Of course, I don''t want my users to have to > enter the IP they are searching for in this fashion, nor do I want to > have to make the conversion myself every time I call the find_by_ip > function or find_or_create_by_ip function for the model, so I have > overloaded those two functions. find_by_ip now reads as follows: > > def self.find_by_ip(ip) > super(NetAddr::CIDR.create(ip).to_i) > endDon''t use super(), instead construct the call to find yourself. That''ll avoid calling method_missing, which will avoid the automatic creation of methods you don''t want. - Matt --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Jan De Poorter
2008-Jan-16 19:44 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
He calls super, which calls the method_missing On 16 Jan 2008, at 19:55, Mark Wilden wrote:> > From: rubyonrails-core@googlegroups.com > [mailto:rubyonrails-core@googlegroups.com] On Behalf Of Jan De Poorter > >> When you call a dynamic finder action (in your case find_by_ip), the >> ruby method_missing function is called. This magic functions takes >> the >> function you requested and creates it, which causes your function to >> be overwritten in favor of the created function. When you reload!, >> your model gets loaded again, and the created function is overwritten >> again. This isn''t to be expected ofcourse. > > I must be missing something, because I don''t see how the "manual" > method > could be overwritten. The creation of the dynamic finder happens in > method_missing, which wouldn''t be called if the method existed, right? > > ///ark > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Rick DeNatale
2008-Jan-16 23:36 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
On 1/16/08, Mark Wilden <mark@mwilden.com> wrote:>> I must be missing something, because I don''t see how the "manual" method > could be overwritten. The creation of the dynamic finder happens in > method_missing, which wouldn''t be called if the method existed, right?Right, if the method exists then method_missing won''t be called. And that''s what''s causing the observed behavior. Initially, he has his hard coded find_by_ip method which gets called. This calls super No super method for find_by_ip is found, so method_missing gets called. In Rails < 2.0 the dynamic finder methods implementation was inside of method_missing, and afterwards there would still be no find_by_ip and so it would go. In Rails 2.0 the method_missing method dynamically adds a find_by_ip method, which overwrites the hard coded one (not I said overwrites rather than overrides). So the next time, his method is no longer there to do the parameter conversion thing. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
From: rubyonrails-core@googlegroups.com [mailto:rubyonrails-core@googlegroups.com] On Behalf Of Rick DeNatale> No super method for find_by_ip is found, so method_missing gets called.Ah, in the calling object, not in the superclass.> (note I said overwrites rather than overrides)Thanks, that''s a pet peeve of mine. :) ///ark --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Michael Koziarski
2008-Jan-18 00:49 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
> In Rails 2.0 the method_missing method dynamically adds a find_by_ip > method, which overwrites the hard coded one (not I said overwrites > rather than overrides). So the next time, his method is no longer > there to do the parameter conversion thing.So is it defining the find_by_ip method on AR::Base or overwriting the original definition? In either case it''s a bug but the fix is different. -- Cheers Koz --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Rick DeNatale
2008-Jan-19 05:22 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
On 1/17/08, Michael Koziarski <michael@koziarski.com> wrote:> > > In Rails 2.0 the method_missing method dynamically adds a find_by_ip > > method, which overwrites the hard coded one (not I said overwrites > > rather than overrides). So the next time, his method is no longer > > there to do the parameter conversion thing. > > So is it defining the find_by_ip method on AR::Base or overwriting the > original definition? In either case it''s a bug but the fix is > different.It has to be overwriting the definition in his subclass of AR::Base, otherwise he wouldn''t have seen the problem. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
From: rubyonrails-core@googlegroups.com [mailto:rubyonrails-core@googlegroups.com] On Behalf Of Rick DeNatale>It has to be overwriting the definition in his subclass of AR::Base, >otherwise he wouldn''t have seen the problem.Let me see if I got this straight. 1) Model#find_x is defined 2) When find_x is called, it calls super, which is AR::Base#find_x. 3) AR::Base has no such method, so method_missing is called in the context of Model (not AR::Base) 4) method_missing generates Model#find_x So what''s weird is that method_missing is adding a method to the subclass that already exists, just because the method can''t be found in the superclass. Am I understanding this right? ///ark --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
Rick DeNatale
2008-Jan-19 20:36 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
On 1/19/08, Mark Wilden <mark@mwilden.com> wrote:> > From: rubyonrails-core@googlegroups.com > [mailto:rubyonrails-core@googlegroups.com] On Behalf Of Rick DeNatale > > >It has to be overwriting the definition in his subclass of AR::Base, > >otherwise he wouldn''t have seen the problem. > > Let me see if I got this straight. > > 1) Model#find_x is defined > 2) When find_x is called, it calls super, which is AR::Base#find_x. > 3) AR::Base has no such method, so method_missing is called in the context > of Model (not AR::Base) > 4) method_missing generates Model#find_x > > So what''s weird is that method_missing is adding a method to the subclass > that already exists, just because the method can''t be found in the > superclass. > > Am I understanding this right?Yes, here''s a synopsis of the code from ActiveRecord::Base#method_missing in ActiveRecord 2.0.2, I''ve replaced some code with #... to make it shorter and more obvious. module ActiveRecord #... class Base #... class << self # Class methods # ... def method_missing(method_id, *arguments) if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) # ... self.class_eval %{ def self.#{method_id}(*args) # body of generated method elided for this post end }, __FILE__, __LINE__ send(method_id, *arguments) elsif match /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/.match(method_id.to_s) # ... self.class_eval %{ def self.#{method_id}(*args) # Body of method elided for this post end }, __FILE__, __LINE__ send(method_id, *arguments) else super end end #... end end in those two self.class_eval calls, self will be the subclass of ActiveRecord::Base and that''s where the method will get defined overwriting the existing method, which got to method_missing by calling super. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---
On 20/01/2008, at 7:36 AM, Rick DeNatale wrote:>> So what''s weird is that method_missing is adding a method to the >> subclass >> that already exists, just because the method can''t be found in the >> superclass. >> >> Am I understanding this right? > > Yes, here''s a synopsis of the code from > ActiveRecord::Base#method_missing in ActiveRecord 2.0.2, I''ve replaced > some code with #... to make it shorter and more obvious.There''s a ticket open on this issue: http://dev.rubyonrails.org/ticket/10831 and it stemmed from: http://dev.rubyonrails.org/changeset/7510 and: http://dev.rubyonrails.org/ticket/9317 I''d like to see the change rolled back as it makes for a pretty nasty behaving method_missing. -- tim --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com To unsubscribe from this group, send email to rubyonrails-core-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en -~----------~----~----~----~------~----~------~--~---