1

En ce moment j'ai un initialiseur qui fait cela:Comment ajouter une association has_many sur tous les modèles

ActiveRecord::Base.send :has_many, :notes, :as => :notable ActiveRecord::Base.send :accepts_nested_attributes_for, :notes

Il construit l'association très bien, sauf quand je charge une vue qui l'utilise, la deuxième charge me donne: can't dup NilClass de:

/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2184:in `dup' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2184:in `scoped_methods' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2188:in `current_scoped_methods' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2171:in `scoped?' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2439:in `send' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2439:in `initialize' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/reflection.rb:162:in `new' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/reflection.rb:162:in `build_association' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:423:in `build_record' 
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:102:in `build' 
(my app)/controllers/manifests_controller.rb:21:in `show' 

Toutes les idées? Est-ce que je fais cela dans le mauvais sens? Fait intéressant, si je déplace l'association sur le modèle avec lequel je travaille en ce moment, je n'obtiens pas cette erreur. Je pense que je dois construire incorrectement l'association globale.

+2

Y at-il raison vous ne spécifiez pas cette association directement dans vos modèles? –

+0

J'ai beaucoup, beaucoup de modèles, et je veux qu'ils aient tous des notes. Le principe DRY dit de mettre cela dans la classe dont ils héritent tous. – joshsz

+0

BTW, j'ai fait quelques recherches supplémentaires et constaté que le problème existe seulement dans le développement, où Rails recharge des classes à chaque demande. Il semble que Rails ne recharge pas ActiveRecord :: Base, quand dans ce cas je le veux. – joshsz

Répondre

-1

Merci à Rich Kilmer (de InfoEther), nous avons trouvé la façon élégante (et légèrement opaque) de fixer ceci:

# config/initializers/has_many_notes.rb 
module ActiveRecord 
    class Base 
    def self.inherited(klass) 
     super 
     klass.send :has_many, :notes, :as => :notable 
     klass.send :accepts_nested_attributes_for, :notes 
    end 
    end 
end 

maintenant aucun changement d'héritage, et il est très sec

+2

@joshsz, les chances sont, vous rencontrerez un modèle que vous ne voulez pas être 'Notable' à un moment donné. Ce n'est pas moins sec que la méthode de John Topley. De plus, si vous êtes trop accro à DRY, vous devriez également respecter ** Convention Over Configuration **.Votre méthode est cryptique et non auto-documentée. –

+1

DRY n'est pas ce que vous faites. Chaque modèle hérite actuellement de ActiveRecord :: Base. Le faire hériter d'un NotableModel n'ajoute aucune répétition, c'est exactement le même montant. Le déplacement de ce code associé du modèle à partir du dossier du modèle n'est pas du tout intuitif. Cela fonctionne absolument, ne vous méprenez pas, mais en pensant à quelqu'un d'autre approchant votre code, je devrais faire un peu de chasse pour trouver cela. L'héritage existe pour résoudre exactement ce genre de problème. L'héritage devrait être préféré au rapiéçage de singe. – Tilendor

+0

Ceci est la bonne solution pour ce projet, mais seulement pour les raisons suivantes: 1) Ce projet a d'autres problèmes transsubstantiels de code (traitement d'événements, par exemple) qui sont traités de la même manière. 2) Les principes de ce domaine stipulent que * tout * doit toujours être notable, même (potentiellement) des notes. Si nous faisons surface la fonctionnalité par modèle est une décision à prendre plus tard, mais toujours une possibilité. 3) Il n'est pas rare d'étendre les classes de base. Si vous considérez ceci comme une extension de base, c'est soudainement un peu moins bizarre. – joshsz

0

un coup d'oeil à unloadable il peut vous aider

+0

Ce blog était intéressant, mais il n'a pas résolu mes problèmes. Voir mes commentaires sur la question initiale pour savoir pourquoi :) – joshsz

0

Il est recommandé de faire de chaque association dans chaque modèle! C'est une façon DRY inutile de faire de telles choses! Du tout, c'est mon opinion!

7

Vous indiquez que vous avez plusieurs modèles, qui nécessitent tous cette association. Si c'était moi, j'irais avec l'approche de créer une classe de modèle de base qui contient l'association et ensuite en hériter tous les autres modèles. Quelque chose comme:

class NotableModel < ActiveRecord::Base 

    # Prevents ActiveRecord from looking for a database table for this class 
    self.abstract_class = true 

    has_many :notes, :as => :notable 
    accepts_nested_attributes_for :notes 
end 

class Foo < NotableModel 
    ... 
end 

class Bar < NotableModel 
    ... 
end 

À mon avis, cette approche est plus autodocumenté par rapport à l'aide d'un peu de metaprogramming caché dans un initialiseur.

+1

Je suis d'accord - définir explicitement cela dans une classe de base ou un module inclus. –

+0

Cette méthode fonctionne, mais elle modifie la chaîne d'héritage. Généralement c'est bien, mais j'aime la méthode DRYer – joshsz

+2

C'est DRY; que pensez-vous est répété? –

Questions connexes