Pregunta

He hecho un poco de lectura acerca de cómo extender ActiveRecord: La clase base para que mis modelos tendrían algunos métodos especiales. ¿Cuál es el camino más fácil para extenderlo (tutorial paso a paso)?

¿Fue útil?

Solución

Existen varios enfoques:

Uso ActiveSupport :: preocupación (preferido)

Leer la documentación ActiveSupport :: preocupación para más detalles.

Crea un archivo llamado active_record_extension.rb en el directorio lib.

require 'active_support/concern'

module ActiveRecordExtension

  extend ActiveSupport::Concern

  # add your instance methods here
  def foo
     "foo"
  end

  # add your static(class) methods here
  class_methods do
    #E.g: Order.top_ten        
    def top_ten
      limit(10)
    end
  end
end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecordExtension)

Crea un archivo en el directorio llamado config/initializers extensions.rb y añadir la siguiente línea al archivo:

require "active_record_extension"

Inheritance (preferido)

Consulte la de Toby respuesta .

Monkey parches (debe ser evitado)

Crea un archivo en el directorio llamado config/initializers active_record_monkey_patch.rb.

class ActiveRecord::Base     
  #instance method, E.g: Order.new.foo       
  def foo
   "foo"
  end

  #class method, E.g: Order.top_ten        
  def self.top_ten
    limit(10)
  end
end

La famosa cita sobre expresiones regulares por Jamie Zawinski puede ser re-utilizados para ilustrar los problemas asociados con el mono-aplicación de parches.

  

Algunas personas, cuando se enfrenta a un problema, creo “Lo sé, lo vamos a usar   mono parches.”Ahora tienen dos problemas.

Mono parches es fácil y rápida. Sin embargo, el tiempo y el esfuerzo ahorrado siempre se extrae de vuelta algún día en el futuro; con interés compuesto. En estos días me limitan mono parches de forma rápida un prototipo de una solución en los rieles de la consola.

Otros consejos

Sólo puede extender la clase y simplemente utilizar la herencia.

class AbstractModel < ActiveRecord::Base  
  self.abstract_class = true
end

class Foo < AbstractModel
end

class Bar < AbstractModel
end

También puede utilizar ActiveSupport::Concern y ser más carriles idiomática núcleo como:

module MyExtension
  extend ActiveSupport::Concern

  def foo
  end

  module ClassMethods
    def bar
    end
  end
end

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

[Editar] siguiendo el comentario de @ Daniel

A continuación, todos los modelos tendrán la foo método incluye como un método de instancia y los métodos en ClassMethods incluyen como métodos de clase. P.ej. en un FooBar < ActiveRecord::Base tendrá: FooBar.bar y FooBar#foo

http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

Con los carriles 4, el concepto de la utilización de las preocupaciones de modularizar y secar sus modelos ha sido en las altas luces.

Las preocupaciones básicamente le permite agrupar código similar de un modelo o en varios modelos en un solo módulo y luego usar este módulo en los modelos. He aquí un ejemplo:

Considere un modelo artículo, un modelo de eventos y un comentario de modelo. Un evento artículo o A tiene muchos comentarios. Un comentario pertenece a cualquiera artículo o evento.

Tradicionalmente, los modelos pueden tener este aspecto:

Comentario Modelo:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

Artículo Modelo:

class Article < ActiveRecord::Base
  has_many :comments, as: :commentable 

  def find_first_comment
    comments.first(created_at DESC)
  end

  def self.least_commented
   #return the article with least number of comments
  end
end

Modelo de eventos

class Event < ActiveRecord::Base
  has_many :comments, as: :commentable 

  def find_first_comment
    comments.first(created_at DESC)
  end

  def self.least_commented
   #returns the event with least number of comments
  end
end

Como podemos notar, hay una pieza importante de común código para ambos eventos y el artículo modelo. El uso de las preocupaciones que puede extraer el código común en un módulo separado commentable.

Para crear un archivo de este commentable.rb en app / modelo / preocupaciones.

module Commentable
    extend ActiveSupport::Concern

    included do 
        has_many :comments, as: :commentable 
    end

    # for the given article/event returns the first comment
    def find_first_comment
        comments.first(created_at DESC)
    end

    module ClassMethods     
        def least_commented
           #returns the article/event which has the least number of comments
        end
    end 
end

Y Ahora sus modelos se parecen a esto:

Comentario Modelo:

    class Comment < ActiveRecord::Base
      belongs_to :commentable, polymorphic: true
    end

Artículo Modelo:

class Article < ActiveRecord::Base
    include Commentable
end

Modelo de eventos

class Event < ActiveRecord::Base    
    include Commentable
end

Un punto que va a destacar durante el uso de las preocupaciones es que Las preocupaciones se debe utilizar para 'dominio basado en' la agrupación en lugar de 'técnica' de agrupación. Por ejemplo, una agrupación de dominio es como 'commentable' , 'taggable', etc. Una técnica basada en la agrupación será como 'FinderMethods', 'ValidationMethods'.

Aquí hay un enlace a un poste que me pareció muy útil para la comprensión de las preocupaciones en los modelos.

Esperamos que la valoración crítica ayuda:)

Paso 1

module FooExtension
  def foo
    puts "bar :)"
  end
end
ActiveRecord::Base.send :include, FooExtension

Paso 2

# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'

Paso 3

There is no step 3 :)

Los carriles 5 proporciona un mecanismo incorporado de para extender ActiveRecord::Base.

Esto se consigue proporcionando capa adicional:

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  # put your extensions here
end

y todos los modelos heredan de que uno:

class Post < ApplicationRecord
end

Véase, por ejemplo esta entrada de blog .

Sólo para añadir a este tema, he pasado un tiempo trabajando cómo probar tales extensiones (descendí la ruta ActiveSupport::Concern.)

Así es como he creado un modelo para probar mis extensiones.

describe ModelExtensions do
  describe :some_method do
    it 'should return the value of foo' do
      ActiveRecord::Migration.create_table :test_models do |t|
        t.string :foo
      end

      test_model_class = Class.new(ActiveRecord::Base) do
        def self.name
          'TestModel'
        end

        attr_accessible :foo
      end

      model = test_model_class.new(:foo => 'bar')

      model.some_method.should == 'bar'
    end
  end
end

Con los carriles 5, todos los modelos son heredados de ApplicationRecord y da buena manera de incluir o ampliar otras bibliotecas de extensión.

# app/models/concerns/special_methods.rb
module SpecialMethods
  extend ActiveSupport::Concern

  scope :this_month, -> { 
    where("date_trunc('month',created_at) = date_trunc('month',now())")
  }

  def foo
    # Code
  end
end

Supongamos que los métodos especiales para el módulo debe estar disponible en todos los modelos, lo incluye en el archivo application_record.rb. Si nos quiere aplicar esto para un conjunto particular de los modelos, a continuación, incluirlo en las clases respectivo modelo.

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

# app/models/user.rb
class User < ApplicationRecord
  include SpecialMethods

  # Code
end

Si usted quiere tener los métodos definidos en el módulo como métodos de clase, ampliar el módulo de ApplicationRecord.

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

La esperanza es ayudar a los demás!

tengo

ActiveRecord::Base.extend Foo::Bar

en un inicializador

Para un módulo, como a continuación

module Foo
  module Bar
  end
end
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top