# Bug in Rails 2.0 when overloading a find\_by method?

**URL:** <https://www.ruby-forum.com/t/bug-in-rails-2-0-when-overloading-a-find-by-method/126232>\
**Category:** Rails\
**Created:** [January 16, 2008, 3:57pm UTC](https://www.ruby-forum.com/t/bug-in-rails-2-0-when-overloading-a-find-by-method/126232 "2008-01-16T15:57:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![carr0t](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8e8cbc/32.png) [@carr0t](https://www.ruby-forum.com/u/carr0t)\
**Post date:** [January 16, 2008, 3:57pm UTC](https://www.ruby-forum.com/t/bug-in-rails-2-0-when-overloading-a-find-by-method/126232/1 "2008-01-16T15:57:54Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![carr0t](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8e8cbc/32.png) [@carr0t](https://www.ruby-forum.com/u/carr0t)\
**Post date:** [January 16, 2008, 4:10pm UTC](https://www.ruby-forum.com/t/bug-in-rails-2-0-when-overloading-a-find-by-method/126232/2 "2008-01-16T16:10:52Z")

</div>

On 16 Jan 2008, at 14:57, Carr0t wrote:

> def self.find\_by\_ip(ip)  
> super(NetAddr::CIDR.create(ip).to\_i)  
> end

I 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](http://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

---

<div class="post-metadata">

**Author:** ![carr0t](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/8e8cbc/32.png) [@carr0t](https://www.ruby-forum.com/u/carr0t)\
**Post date:** [January 16, 2008, 4:27pm UTC](https://www.ruby-forum.com/t/bug-in-rails-2-0-when-overloading-a-find-by-method/126232/3 "2008-01-16T16:27:20Z")

</div>

2008/1/16, Carr0t [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> 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.

```
