rails form_with form_for form for ruby-on-rails ruby activerecord finder

ruby-on-rails - form_with - select rails helper



¿Cuál es la forma más limpia de anular el hallazgo de ActiveRecord tanto para modelos como para colecciones? (3)

Antes que nada, asegúrate de conocer bien la estructura de herencia de llamadas al método de Ruby, ya que sin esto puedes terminar apuñalando en la oscuridad.

La forma más directa de hacer esto dentro de una clase ActiveRecord es:

def self.find(*args) super end

Esto se aplicará también a las asociaciones, ya que usan el buscador de bases ellos mismos. Ahora solo necesitas hacer tu personalización. La complejidad de eso puede variar ampliamente, y no sé lo que estás haciendo, así que no puedo ofrecer ninguna recomendación.

También definir esto dinámicamente será un ejercicio en sí mismo, pero esto debería hacer que apuntes en la dirección correcta.

Tengo un código de biblioteca que anula el método de búsqueda de Ar. También incluyo el módulo para todas las clases de la Asociación, de modo que tanto MyModel.find como @ parent.my_models.find funcionen y apliquen el alcance correcto.

Basé mi código fuera de will_paginate:

a = ActiveRecord::Associations returning([ a::AssociationCollection ]) { |classes| # detect http://dev.rubyonrails.org/changeset/9230 unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation classes << a::HasManyThroughAssociation end }.each do |klass| klass.send :include, Finder::ClassMethods klass.class_eval { alias_method_chain :method_missing, :paginate } end

Mi problema es que solo quiero anular los buscadores para algunos modelos. Actualmente necesito extender todas las clases de colección de asociaciones que comparten todos los modelos. Sé que puedo extender las asociaciones por modelo pasando un módulo:

has_many :things, :extend => SomeCustomMethods

Pero mi biblioteca es básicamente un complemento de ActiveRecord, por lo que me gustaría una convención limpia para las extensiones de buscador enchufables que se apliquen tanto al modelo como a las colecciones de ámbito sin afectar a todos los modelos en la aplicación.


Desea anular find_every , que es el método AR que finalmente ejecutará find_by_sql con la consulta correspondiente. Anular el find no funcionará para los buscadores personalizados, y es más frágil.

Pero para ser compatible con otros complementos, no puedes simplemente sobrecargar este método. En cambio, alias y llama a la implementación original después de hacer lo que quieras:

module MyPlugin def self.included(base) class << base alias_method :find_every_without_my_plugin, :find_every def find_every(*args) # do whatever you need ... find_every_without_my_plugin(*args) end end end end ActiveRecord::Base.send :include, MyPlugin

Esto habilitará su complemento para todas las clases. ¿Cómo desea controlar qué modelos están habilitados? Tal vez un accesorio de complemento estándar?

class User < ActiveRecord::Base my_plugin end

Para apoyar esto, necesitas mover la class << base a un método de clase (por lo tanto, base debe ser self ). Me gusta:

module MyPlugin def self.included(base) class << base base.extend ClassMethods end end module ClassMethods def my_plugin class << self alias_method :find_every_without_my_plugin, :find_every # ... end end end end


''La respuesta de Pedro es correcta, pero hay un pequeño error.

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

debiera ser

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

El uso de la clase << base ... final tiene el efecto de invocar ''extender'' en ''base'' en el ámbito de método de clase, pero no hay ningún método ''base'' en ActiveRecord :: Base, por lo que se genera un error. Usar base.extend por sí mismo llamará al método ''extender'' de ActiveRecord :: Base.