ruby-on-rails - queries - rails where
Rieles que extienden ActiveRecord:: Base (9)
Con Rails 4, el concepto de utilizar las preocupaciones para modularizar y DRY hasta sus modelos ha estado en lo más destacado.
Las preocupaciones básicamente le permiten agrupar códigos similares de un modelo o en varios modelos en un solo módulo y luego usar este módulo en los modelos. Aquí hay un ejemplo:
Considere un modelo de artículo, un modelo de evento y un modelo de comentario. Un artículo o un evento tiene muchos comentarios. Un comentario pertenece a cualquier artículo o evento.
Tradicionalmente, los modelos pueden verse así:
Modelo de comentario:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Modelo del artículo:
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 evento
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 observar, hay un fragmento significativo de código común para el modelo de evento y artículo. Usando las preocupaciones, podemos extraer este código común en un módulo separado Commentable.
Para esto crea un archivo commentable.rb en la aplicación / modelo / inquietudes.
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 tus modelos se ven así:
Modelo de comentario:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Modelo del artículo:
class Article < ActiveRecord::Base
include Commentable
end
Modelo de evento
class Event < ActiveRecord::Base
include Commentable
end
Un punto que me gustaría resaltar al usar Preocupaciones es que las Preocupaciones deberían usarse para la agrupación ''basada en dominio'' en lugar de la agrupación ''técnica''. Por ejemplo, una agrupación de dominios es como ''Commentable'', ''Etiquetable'', etc. Una agrupación basada en tecnología será como ''FinderMethods'', ''ValidationMethods''.
Aquí hay un enlace a una publicación que encontré muy útil para entender las preocupaciones en los Modelos.
Espero que la crítica ayude :)
He leído algo sobre cómo extender ActiveRecord: clase base para que mis modelos tengan algunos métodos especiales. ¿Cuál es la manera más fácil de ampliarlo (tutorial paso a paso)?
Con Rails 5, todos los modelos se heredan de ApplicationRecord y ofrece una forma agradable 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 el módulo de métodos especiales debe estar disponible en todos los modelos, inclúyalo en el archivo application_record.rb. Si queremos aplicar esto para un conjunto particular de modelos, luego incluirlo en las respectivas clases 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 desea tener los métodos definidos en el módulo como métodos de clase, amplíe el módulo a ApplicationRecord.
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend SpecialMethods
end
Espero que ayude a los demás!
Hay varios enfoques:
Uso de ActiveSupport :: Preocupación (Preferido)
Lea la documentación de ActiveSupport::Concern para más detalles.
Cree un archivo llamado active_record_extension.rb
en el directorio lib
.
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)
Cree un archivo en el directorio config/initializers
llamado extensions.rb
y agregue la siguiente línea al archivo:
require "active_record_extension"
Herencia (Preferido)
Consulte la answer de Toby.
Parche de mono (debe evitarse)
Cree un archivo en el directorio config/initializers
llamado 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 de Jamie Zawinski se puede reutilizar para ilustrar los problemas asociados con el parche de monos.
Algunas personas, cuando se enfrentan con un problema, piensan "Lo sé, utilizaré el parche de monos". Ahora tienen dos problemas.
El parche de mono es fácil y rápido. Pero, el tiempo y el esfuerzo ahorrado siempre se extraen en el futuro; con interés compuesto. En estos días, limito el parche de mono para prototipar rápidamente una solución en la consola de rieles.
Puedes extender la clase y simplemente usar herencia.
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
Rails 5 proporciona un mecanismo integrado para extender ActiveRecord::Base
.
Esto se logra 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 ese:
class Post < ApplicationRecord
end
Ver, por ejemplo, este blogpost .
Solo para agregar a este tema, pasé un tiempo trabajando en cómo probar tales extensiones (bajé por la ruta ActiveSupport::Concern
).
Así es como configuré 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
También puede usar ActiveSupport::Concern
y tener más Core Rails Idiomatic 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
Entonces todos sus modelos tendrán el método foo
incluido como método de instancia y los métodos en ClassMethods
incluidos como métodos de clase. Por ejemplo, en FooBar < ActiveRecord::Base
tendrás: FooBar.bar
y FooBar#foo
yo tengo
ActiveRecord::Base.extend Foo::Bar
en un inicializador
Para un módulo como a continuación
module Foo
module Bar
end
end
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 :)