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.