Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the preferred way to add some method in active record base?

I want to create a module which provides some common methods to the classes which are inherited from active record base.

Following is the two-way we can achieve it.

1)

module Commentable

def self.extended(base)
    base.class_eval do
        include InstanceMethods
        extend ClassMethods
    end
end

module ClassMethods
    def test_commentable_classmethod
        puts 'test class method'
    end
end

module InstanceMethods
    def test_commentable_instance_method
        puts 'test instance method'
    end
end
end


ActiveRecord::Base.extend(Commentable)

2)

module Commentable

def self.included(base)
    base.extend(ClassMethods)
end

module ClassMethods
    def test_commentable_classmethod
        puts 'test class method'
    end
end

def test_commentable_instance_method
    puts 'test instance methods'
end
end

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

Which one is the preferred way to handle this?

And

What to use when?

like image 283
krunal shah Avatar asked Jul 31 '14 22:07

krunal shah


People also ask

What is Active Records database?

Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database. It is an implementation of the Active Record pattern which itself is a description of an Object Relational Mapping system.

What is active record pattern in rails?

The active record pattern is an approach to accessing data in a database. A database table or view is wrapped into a class. Thus, an object instance is tied to a single row in the table. After creation of an object, a new row is added to the table upon save. Any object loaded gets its information from the database.

What is an ActiveRecord relation?

An instance of ActiveRecord::Base is an object that represents a specific row of your database (or might be saved into the database). Whereas an instance of ActiveRecord::Relation is a representation of a query that can be run against your database (but wasn't run yet).

What is ActiveRecord ORM?

ORM - Object Relational Mapping provides a variety of frameworks and techniques that are helpful in working with Relational Databases such as MySQL, PostgreSQL, etc. “Active record - an object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.”


1 Answers

As of Rails 5, the recommended way is to make a module and include it in the models where it is needed, or everywhere using ApplicationRecord, which all models inherit from. (You can easily implement this pattern from scratch in older versions of Rails.)

# app/models/concerns/my_module.rb
module MyModule
  extend ActiveSupport::Concern

  module ClassMethods
    def has_some_new_fancy_feature(options = {})
      ...
    end
  end
end

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  include MyModule
end

Modules are a form of multiple-inheritance, and sometimes add unnecessary complexity. Check if a decorator, service, or other kind of object makes more sense first. Not everything needs be a fancy macro that adds 50 callbacks to your model. You will hate your life if you do this too much.


If you want to monkey-patch (DON'T DO THIS), here is my old answer:

# config/initializers/activerecord_extensions.rb
ActiveRecord::Base.send(:include, MyModule)

Or without monkey-patching (see Mori's response):

# app/models/base_model.rb
class BaseModel < ActiveRecord::Base
  self.abstract_class = true
  include MyModule
end

Edit: Several months down the road in a large project, I have realized its better to have every model inherit from a new base model class, as Mori explains. The problem with including modules directly into ActiveRecord::Base is this can interfere with third-party code that also relies on ActiveRecord. It is just better not to monkey-patch when you don't have to. In this case, creating a new base class can end up being simpler in the long run.

like image 104
wmakley Avatar answered Oct 12 '22 22:10

wmakley