I''ve got an interesting replecatable bug that has sprung up since I migrated some code i''ve written from rails 1.2.3 to 2.0.2. 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. Can anyone else test this to prove it''s not just me, and/or suggest who/where I should report it as a bug? Thanks Dan Meyers Network Support, Lancaster University --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Jan-16 15:09 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
On 16 Jan 2008, at 14:57, Carr0t wrote:> > I''ve got an interesting replecatable bug that has sprung up since I > migrated some code i''ve written from rails 1.2.3 to 2.0.2. 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) > endI expect what happens is as follows: you call find_by_ip and go through to your method. You call super and hit method_missing. In rails 1.2 this just called find for you with the right arguments. In rails 2.x, rails actually creates a find_by_ip method (so overwriting your one) and calls that. On your next call to find_by_ip you go straight to the rails generate one, which isn''t coercing the string to the appropriate ip. You could create a ticket on dev.rubyonrails.org, but i''d first bring up the issues on rubyonrails-core. I''m not sure what the best way of resolving this would be. Fred> > > 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. Can anyone else > test this to prove it''s not just me, and/or suggest who/where I should > report it as a bug? > > Thanks > > Dan Meyers > Network Support, Lancaster University > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Jean-François Trân
2008-Jan-16 15:26 UTC
Re: Bug in Rails 2.0 when overloading a find_by method?
2008/1/16, Carr0t <d.c.meyers-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:> def self.find_by_ip(ip) > super(NetAddr::CIDR.create(ip).to_i) > end[...]> 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. Can anyone else > test this to prove it''s not just me, and/or suggest who/where I should > report it as a bug?- You''ve defined find_by_ip in your AR::B subclass to overload a dynamic finder. And in your method, you call super. - In Rails < 2.* (like 1.2.* series), dynamic finders are handled by a method_missing mechanism. So in 1.2.*, that''s how things work : Ip.find_by_ip("10.21.1.8") calls your defined find_by_ip method. With super, Ruby tries to see if there''s a find_by_ip in parent classes. There is not, so method_missing is called, that makes your AR::B.find on the fly and retrieves for you the right results. - In Rails 2.0.*, dynamic finders are handled by a method missing mechanism at the first call, a finder method is generated at the first call, this fresh method handles your query. In the doc "Each dynamic finder or initializer/creator is also defined in the class after it is first invoked, so that future attempts to use it do not run through method_missing." So in 2.0.* your stuff works like that : Ip.find_by_ip("10.21.1.8") calls your defined class method in Ip class. your method invokes super : Ruby looks for a find_by_ip method in parent classes. There aren''t. method_missing is called. First time called, a find_by_ip is generated, overiding your defined method. Rails call the new method, retrieving the right results. At the second call, Rails use the new method that overrides yours, but can''t deal string like "10.21.1.8", so your query returns nil. If you pass an integer as argument it works, using the one-the-fly generated method, not yours. 3/ In a nutshell, in your defined find_by_ip, call AR::B.find directly (or another dynamic finder !), don''t use super, to bypass all this method_missing mechanism. HTH, -- Jean-François. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---