3

I have a standard ActiveRecord model with the following:

class MyModel < ActiveRecord::Base
  custom_method :first_field, :second_field
end

At the moment, that custom_method is picked up by a module sent to ActiveRecord::Base. The functionality basically works, but of course, it attaches itself to every model class, not just MyModel. So if I have MyModel and MyOtherModel in the same action, it'll assume MyOtherModel has custom_method :first_field, :second_field as well.

So, my question is: How do I attach a method (eg: def custom_method(*args)) to every class that inherits from ActiveRecord::Base, but not by attaching it to ActiveRecord::Base itself?

Any ideas appreciated.

===

Edit

The custom_method is currently attached to ActiveRecord::Base by the following:

module MyCustomModule
  def self.included(base)
    base.extend(self)
  end

  def custom_method(*args)
    # Zippity doo dah - code goes here
  end
end

ActiveRecord::Base.send(:include, MyCustomModule)
PlankTon
  • 12,443
  • 16
  • 84
  • 153
  • Sounds like the key is what does `custom_method` do? – Frederick Cheung Mar 31 '12 at 11:32
  • Opens up ActionView::Helpers::FormHelper --> fields_for & appends args from custom_method(*args) to the top of any form_for (wrapped in h1 tag). …Effectively a useless gem, but I'm trying to find my feet re: gem creation. – PlankTon Mar 31 '12 at 11:36
  • I think we'd need to see exactly what it's doing in order to conjecture why what is being done applies to all models (although it seems that a custom form builder might be more appropriate here) – Frederick Cheung Mar 31 '12 at 11:58
  • 1
    Why not define a class that inherits from ActiveRecord::Base, and have your models inherit from that? Or is this something that you want completely hidden so that other developers can keep inheriting from ActiveRecord::Base and get the functionality without requesting it explicitly? – Marc Talbot Mar 31 '12 at 12:30
  • Hi Marc - cheers for the response. I was tempted by that, but yes - ideally I'd like the gem user to require no more input than appending the 'custom_method' line. I have vague memories of some sort of hook for appending instance methods to inherited classes(?), but maybe I just dreamt it up. Any other suggestions appreciated. – PlankTon Mar 31 '12 at 12:36
  • 1
    I woud like to see the module you are including and how you are attaching attaching the method. You have strayed into the land of meta programming and I think what you have done is attached the methods to the base class, you should be attaching the methods to the meta class. check this out: http://reference.jumpingmonkey.org/programming_languages/ruby/ruby-metaprogramming.html#h5 – Ben Miller Mar 31 '12 at 13:02
  • Cheers Ben. Added attachment process above. Meta might be the next step, but I was hoping/thinking there was some sort of simple hook on initialization that could add methods to any inherited class. ...Starting to think I may have hallucinated it. ;-) – PlankTon Mar 31 '12 at 15:15
  • 1
    If you were to call define_method from inside custom_method that would only add methods to the model in question – Frederick Cheung Mar 31 '12 at 15:20
  • Actually - cheers, yeah - define_method might be easier than I'd thought. I'm just reading up on .descendants mentioned below...if that fails, define_method might be the best option. – PlankTon Mar 31 '12 at 15:29

1 Answers1

2

Do you know about descendants?

ActiveRecord::Base.descendants

You have to be sure to touch the models before calling it.

See excellent discussion here:

Is there a way to get a collection of all the Models in your Rails app?

I concur with the commentors above that you may want to consider adding your methods to the meta class, or an intermediary class, or a Module mixin.

Community
  • 1
  • 1
joelparkerhenderson
  • 34,808
  • 19
  • 98
  • 119
  • Excellent - I suspect that's exactly what I was thinking of. (But have to run out before I can try it - back in a few hours) – PlankTon Mar 31 '12 at 15:50