I have two models that contain the same method:
def foo
# do something
end
Where should I put this?
I know common code goes in the lib
directory in a Rails app.
But if I put it in a new class in lib
called 'Foo
', and I need to add its functionality to both of my ActiveRecord models
, do I do that like this:
class A < ActiveRecord::Base
includes Foo
class B < ActiveRecord::Base
includes Foo
and then both A
and B
will contain the foo
method just as if I had defined it in each?
Create a module, which you can put in the
lib
directory:You can then
include
the module in each of your model classes:The
A
andB
models will now have afoo
method defined.If you follow Rails naming conventions with the name of the module and the name of the file (e.g. Foo in foo.rb and FooBar in foo_bar.rb), then Rails will automatically load the file for you. Otherwise, you will need to use
require_dependency 'file_name'
to load your lib file.You really have two choices:
Use #1 if the shared functionality is not core to each class, but applicable to each class. For example:
Use #2 if the shared functionality is common to each class and A & B share a natural relationship:
Here's how I did it... First create the mixin:
Then mix it into every model that needs it:
It's almost pretty!
To complete the example, though it's irrelevant to the question, here's my slug model:
One option is to put them in a new directory, for example
app/models/modules/
. Then, you can add this toconfig/environment.rb
:This will
require
every file in in that directory, so if you put a file like the following in your modules directory:Then you can just use it in your models because it will be automatically loaded:
This approach is more organized than putting these mixins in the
lib
directory because they stay near the classes that use them.If you need ActiveRecord::Base code as a part of your common functionalities, using an abstract class could be useful too. Something like:
As simple as that. Also, if the code is not ActiveRecord related, please find
ActiveSupport::Concerns
as a better approach.As others have mentioned include Foo is the way to do things... However it doesn't seem to get you the functionality you want with a basic module. The following is the form a lot of Rails plugins take to add class methods and new callbacks in addition to new instance methods.