# Extending Rails Classes - Where?

**URL:** <https://www.ruby-forum.com/t/extending-rails-classes-where/168987>\
**Category:** Rails\
**Created:** [May 28, 2009, 6:07am UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987 "2009-05-28T06:07:24Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 6:07am UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/1 "2009-05-28T06:07:24Z")

</div>

Where is the best place to stash Ruby files that add functionality to  
Rails classes (in my case, ActiveRecord::Base)? I think my module is  
being loaded too late, and causing a class method to be undefined.

Here’s what I tried: I wrote a module to add a new class method to  
ActiveRecord::Base following a pattern that I picked up from  
[The Basics of Creating Rails Plugins — Ruby on Rails Guides](http://guides.rubyonrails.org/plugins.html); in my module implement the  
included callback and have it extend the target class with my class  
methods (actually singleton methods on the metaclass of my class  
object if I’m understanding all of this weirdness correctly):

```
def self.included(base)
  base.send :extend, ClassMethods
end

module ClassMethods
  def my_method
  end
end

```

Then outside of the module definition I tell ActiveRecord::Base to  
include my module:

ActiveRecord::Base.send(:include, MyModule)

And according to my (obviously poorly written) unit test, this all  
worked wonderfully:

def test\_responds\_to\_my\_method  
assert MyModel.respond\_to?(:my\_method, true)  
end

Great! Except…

class MyModel \< ActiveRecord::Base  
my\_method # undefined local variable or method `my\_method’  
end

So it seems reasonable to me that this might happen if my\_model.rb is  
loaded first, then my module, then the test. Additional evidence is  
that if I add a “debugger” line to my included callback, I’m never  
sent to the debugger. Unless I remove the call to my\_method, then I  
am.

So if my hypothesis is correct, it’s a bad idea to add my modules to  
lib\modules and append that to the end of my load path. But then  
where should I stash modules that update rails classes?

---

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 9:01am UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/2 "2009-05-28T09:01:19Z")

</div>

Hi,

On 28/05/2009, at 2:06 PM, Brian wrote:

> object if I’m understanding all of this weirdness correctly):
> 
> def self.included(base)  
> base.send :extend, ClassMethods  
> end
> 
> module ClassMethods  
> def my\_method  
> end  
> end

This is not a class method, is it? it’s an instance method. a class  
method would be

def self.my\_method  
end

> end
> 
> Great! Except…
> 
> class MyModel \< ActiveRecord::Base  
> my\_method # undefined local variable or method `my\_method’  
> end

I don’t follow what you want to do here… you’re calling the method  
inside the class definition. That makes no sense. What did you want to  
happen?  
In other words, you’re running a method WHILE declaring the class.

Perhaps you wanted something like this:

class MyModel \< ActiveRecord::Base  
def some\_other\_method  
my\_method  
end  
end

that will work, but my\_method is still here not a class method… it’s  
an instance method… (as far as my understanding goes) because of the  
way the module is defined.

* * *

Learn: [http://sensei.zenunit.com/](http://sensei.zenunit.com/)  
Last updated 20-May-09 (Rails, Basic Unix)  
Blog: [http://random8.zenunit.com/](http://random8.zenunit.com/)  
Twitter: [http://twitter.com/random8r](http://twitter.com/random8r)

---

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 10:14am UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/3 "2009-05-28T10:14:35Z")

</div>

On May 28, 5:06 am, Brian [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> So it seems reasonable to me that this might happen if my\_model.rb is  
> loaded first, then my module, then the test. Additional evidence is  
> that if I add a “debugger” line to my included callback, I’m never  
> sent to the debugger. Unless I remove the call to my\_method, then I  
> am.
> 
> So if my hypothesis is correct, it’s a bad idea to add my modules to  
> lib\modules and append that to the end of my load path. But then  
> where should I stash modules that update rails classes?

The problem is not so much where you put it but when it’s loaded. If  
you just stick a file in lib/blah rails isn’t going to magically trip  
over it. It will load your module if elsewhere you say MyModule, and  
in production mode it will load it at some point. So you need to  
require it explicitly and you need to do so at the right point, and  
that happens to be from an initializer (ie a file in config/  
initializers) - these are run after rails has been loaded, but before  
your application classes are.

Fred

---

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 10:15am UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/4 "2009-05-28T10:15:45Z")

</div>

On May 28, 7:59 am, Julian L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I don’t follow what you want to do here… you’re calling the method  
> inside the class definition. That makes no sense. What did you want to  
> happen?  
> In other words, you’re running a method WHILE declaring the class.

That’s reasonable enough. Just like acts\_as\_list, has\_many, etc…

Fred

---

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 3:30pm UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/5 "2009-05-28T15:30:13Z")

</div>

Thanks, Fred! This works as expected now.

I’ve made a config/initializers/modules.rb. For now I only require  
this one module, but I’ll probably just have this require everything  
in lib/modules so that I don’t have to worry about the next one.

On May 28, 4:13 am, Frederick C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 4:03pm UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/6 "2009-05-28T16:03:14Z")

</div>

On May 28, 2:59 am, Julian L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> This is not a class method, is it? it’s an instance method. a class  
> method would be
> 
> def self.my\_method  
> end

I have all of 20 hours of Ruby experience now, so I’ll probably screw  
up this explanation. The whole include/extend thing is still very  
confusing to me, but I’m having ActiveRecord::Base call include on my  
module and attaching a callback so that I can do more.  
ActiveRecord::Base is an instance of the Class class, so when the  
callback uses extend, it is the ActiveRecord::Base instance itself  
(and ActiveRecord::Base objects) that pick up the new my\_method  
instance method. My understanding is that Ruby then attaches this to  
a metaclass for the ActiveRecord::Base instance, making it a singleton  
method. And I think that’s all class methods really are; singleton  
methods on the metadata class for an instance of the Class class. So  
through module trickery I have created a new class method.

If I have this wrong, let me know. I don’t like to write code that I  
don’t understand, so the sooner I wrap my head around the actual  
mechanics of how this works, the better.

> I don’t follow what you want to do here… you’re calling the method  
> inside the class definition. That makes no sense. What did you want to  
> happen?  
> In other words, you’re running a method WHILE declaring the class.

For any language other than ruby, I would agree that this doesn’t make  
sence. 🙂

Apparently it’s standard practice though for this language. You can  
run methods right in the middle of your class definition. You can try  
this out pretty easily in irb:

irb(main):001:0\> class A  
irb(main):002:1\> puts “hello!”  
irb(main):003:1\> end  
hello!  
=\> nil

Strange! But useful. In my case I’m actually planning to create  
three class methods similar to my\_method above. When run these will  
generate instance methods for my models (similar to associations).

---

<div class="post-metadata">

**Author:** ![brian](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/97f17d/32.png) [@brian](https://www.ruby-forum.com/u/brian)\
**Post date:** [May 28, 2009, 5:00pm UTC](https://www.ruby-forum.com/t/extending-rails-classes-where/168987/7 "2009-05-28T17:00:25Z")

</div>

On Thu, May 28, 2009 at 10:02 AM, Brian [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> > > ```
> > > end
> > > 
> > > ```
> 
> I have all of 20 hours of Ruby experience now, so I’ll probably screw  
> through module trickery I have created a new class method.
> 
> If I have this wrong, let me know. I don’t like to write code that I  
> don’t understand, so the sooner I wrap my head around the actual  
> mechanics of how this works, the better.

No, you have this quite right, and extending a class/module with a  
‘class methods’ module inside another module using the included hook  
is the standard way to add class methods.

–  
Rick DeNatale

Blog: [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)  
Twitter: [http://twitter.com/RickDeNatale](http://twitter.com/RickDeNatale)  
WWR: [http://www.workingwithrails.com/person/9021-rick-denatale](http://www.workingwithrails.com/person/9021-rick-denatale)  
LinkedIn: [http://www.linkedin.com/in/rickdenatale](http://www.linkedin.com/in/rickdenatale)
