2010-05-23 22 views
31

¿Hay alguna manera de anular uno de los métodos proporcionados por una asociación ActiveRecord?Rieles: Reemplazando el método de asociación ActiveRecord

decir, por ejemplo tengo el siguiente has_many típica polimórfica: a través de la asociación:

class Story < ActiveRecord::Base 
    has_many :taggings, :as => :taggable 
    has_many :tags, :through => :taggings, :order => :name 
end 


class Tag < ActiveRecord::Base 
    has_many :taggings, :dependent => :destroy 
    has_many :stories, :through => :taggings, :source => :taggable, :source_type => "Story" 
end 

Como usted probablemente sabe esto se suma una gran cantidad de métodos asociados al modelo de historia como etiquetas, etiquetas < <, etiquetas = , tags.empty ?, etc.

¿Cómo hago para anular uno de estos métodos? Específicamente las etiquetas < < método. Es bastante fácil anular los métodos de una clase normal, pero parece que no puedo encontrar información sobre cómo anular los métodos de asociación. Hacer algo como

def tags<< *new_tags 
    #do stuff 
end 

produce un error de sintaxis cuando se llama por lo que obviamente no es tan simple.

+2

¿Qué estás tratando de hacer esto? Esto podría terminar rompiendo otras funcionalidades de ActiveRecord, y probablemente haya una mejor manera de hacer lo que está intentando – Gareth

Respuesta

53

Usted puede utilizar bloque con has_many a ampliar su asociación con métodos. Vea el comentario "Use un bloque para extender sus asociaciones" here.
Sobrescribir los métodos existentes también funciona, pero no sé si es una buena idea.

has_many :tags, :through => :taggings, :order => :name do 
    def << (value) 
     "overriden" #your code here 
     super value 
    end  
    end 
+0

¡Por supuesto! Olvidé sobre eso. Esta es probablemente la mejor manera de hacer lo que está buscando. –

+1

¿Y cómo llamarías al método original? (Quiero anular el método de compilación, agregar algunos valores predeterminados y luego llamar al original) –

+1

@EranKampf no hace 'super' hacer el truco? – lulalala

0

Creo que quería def tags.<<(*new_tags) para la firma, que debería funcionar, o la siguiente que es equivalente y un poco más limpia si necesita anular múltiples métodos.

class << tags 
    def <<(*new_tags) 
    # rawr! 
    end 
end 
+0

No creo que ninguno de esos funcione. Parece que lo que sugiere es intentar extender la clase Eigen del valor devuelto por el método 'tags'. –

+0

Está definiendo un método dentro de la clase de autoejecución de lo que devuelve 'tags', que probablemente sea una matriz. Esto tiene el efecto de agregar un nuevo método de instancia a la matriz, que es lo que entendí que era la pregunta original. 'extender' tiene un significado específico en ruby ​​y eso no es lo que está pasando aquí. – x1a4

+0

Tienes razón, eso es exactamente lo que está haciendo. Supongo que simplemente no entendí dónde sugerías poner ese código. De todos modos, supongo que respondí más o menos lo mismo, solo que con un poco más de contexto. –

0

Debería definir el método de etiquetas para devolver un objeto que tiene un método <<.

Podrías hacerlo así, pero realmente no lo recomendaría. Sería mucho mejor que simplemente al agregar un método para su modelo que hace lo que desea, en lugar de tratar de reemplazar algo que ActiveRecord usa.

Esto esencialmente ejecuta el método predeterminado tags agrega un método < < al objeto resultante y devuelve ese objeto. Esto puede ser un recurso poco intensiva, ya que crea un nuevo método cada vez que se ejecuta

def tags_with_append 
    collection = tags_without_append 
    def collection.<< (*arguments) 
    ... 
    end 
    collection 
end 
# defines the method 'tags' by aliasing 'tags_with_append' 
alias_method_chain :tags, :append 
0

El método que uso es para extender la asociación. Se puede ver la forma en que manejo 'cantidad' atributos aquí: https://gist.github.com/1399762

Básicamente permite que acaba de hacer

has_many : tags, :through => : taggings, extend => QuantityAssociation 

Sin saber exactamente lo que su esperanza de lograr reemplazando los métodos de su difícil saber si podría hacer lo mismo.

0

Esto puede no ser útil en su caso, pero podría ser útil para otros que deseen investigarlo.

devoluciones de llamada Asociación: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

ejemplo, de los documentos:

class Project 
    has_and_belongs_to_many :developers, :after_add => :evaluate_velocity 

    def evaluate_velocity(developer) 
    ... 
    end 
end 

también ver las extensiones de la Asociación:

class Account < ActiveRecord::Base 
    has_many :people do 
    def find_or_create_by_name(name) 
     first_name, last_name = name.split(" ", 2) 
     find_or_create_by_first_name_and_last_name(first_name, last_name) 
    end 
    end 
end 

person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson") 
person.first_name # => "David" 
person.last_name # => "Heinemeier Hansson" 
17

Si desea acceder al modelo en sí mismo en Rails 3.2 que debiera use proxy_association.owner

Ejemplo:

class Author < ActiveRecord::Base 
    has_many :books do 
    def << (book) 
     proxy_association.owner.add_book(book) 
    end 
    end 

    def add_book (book) 
    # do your thing here. 
    end 
end 

Ver documentation

+0

este sigue siendo el caso en Rails 5.1 – coconup

+0

@coconup esto no funciona para mí en raíles 5.1 - el método << de anulación no se llama en absoluto :-( – dowi

0

Rails guides documentos sobre sustituyendo los métodos añadidos directamente.

El problema de OP con anulación << probablemente sea la única excepción a esto, para lo cual siga the top answer. Pero no funcionaría para el método de asignación has_one= ni para los métodos getter.

Cuestiones relacionadas