ruby-on-rails ruby include extend

ruby on rails - ¿Cuál es la forma preferida de agregar algún método en la base de registros activa?



ruby-on-rails include (3)

Quiero crear un módulo que proporcione algunos métodos comunes a las clases que se heredan de la base de registros activos.

Lo siguiente es de dos vías que podemos lograr.

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)

¿Cuál es la forma preferida de manejar esto?

Y

¿Qué usar cuando?


refiriendo con la respuesta de Mori ... puedes hacer algo como:

Module ActiveRecordUtilities class MyBase < ActiveRecord::Base self.abstract_class = true def self.a_class_method end def an_instance_method end end end##class ends end##module ends

y puede usarlo ... supongo en user.rb

include ActiveRecordUtilities::MyBase User.a_class_method @user.instance_method

========================= O ====================

module MyUtils def do_something_funky # Some exciting code end end class Account < ActiveRecord::Base belongs_to :person, :extend => MyUtils end And then call it like this: @account = Account.first @account.person.do_something_funky


Otra forma es crear su propia clase base heredando ActiveRecord::Base y luego dejar que sus modelos hereden de esa clase base. Esto tiene la ventaja de dejar en claro que sus modelos no se están ejecutando en ActiveRecord vainilla:

class MyBase < ActiveRecord::Base self.abstract_class = true def self.a_class_method end def an_instance_method end end class Foo < MyBase end Foo.a_class_method Foo.new.an_instance_method


A partir de Rails 5, la forma recomendada es crear un módulo e incluirlo en los modelos donde sea necesario, o en cualquier lugar utilizando ApplicationRecord, del que heredan todos los modelos. (Puede implementar fácilmente este patrón desde cero en versiones anteriores de 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

Los módulos son una forma de herencia múltiple y, a veces, agregan complejidad innecesaria. Verifique si un decorador, servicio u otro tipo de objeto tiene más sentido primero. No todo necesita ser una macro elegante que agrega 50 devoluciones de llamada a su modelo. Odiarás tu vida si haces esto demasiado.

Si quieres un parche de mono (NO HAGAS ESTO), aquí está mi respuesta anterior:

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

O sin parche de mono (ver la respuesta de Mori ):

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

Editar: Varios meses después, en un proyecto grande, me di cuenta de que es mejor tener todas las modelos heredadas de una nueva clase de modelo base, como explica Mori . El problema de incluir módulos directamente en ActiveRecord :: Base es que esto puede interferir con el código de un tercero que también depende de ActiveRecord. Es mejor no hacer un parche de mono cuando no es necesario. En este caso, crear una nueva clase base puede terminar siendo más simple a largo plazo.