2008-09-16 14 views
5

Dans le but de réduire la duplication de code dans ma petite application Rails, j'ai travaillé pour obtenir du code commun entre mes modèles dans son propre module séparé, loin si bon.Comment écrire un mixage Rails à travers le modèle, le contrôleur et la vue

Le truc modèle est assez facile, je dois juste inclure le module au début, par exemple:

class Iso < Sale 
    include Shared::TracksSerialNumberExtension 
    include Shared::OrderLines 
    extend Shared::Filtered 
    include Sendable::Model 

    validates_presence_of :customer 
    validates_associated :lines 

    owned_by :customer 

    def initialize(params = nil) 
    super 
    self.created_at ||= Time.now.to_date 
    end 

    def after_initialize 
    end 

    order_lines    :despatched 

    # tracks_serial_numbers :items 
    sendable :customer 

    def created_at=(date) 
    write_attribute(:created_at, Chronic.parse(date)) 
    end 
end 

Cela fonctionne très bien, maintenant cependant, je vais avoir un code du contrôleur et vue qui va être commun entre ces modèles et, jusqu'à présent, j'ai pour mon truc expédiable:

# This is a module that is used for pages/forms that are can be "sent" 
# either via fax, email, or printed. 
module Sendable 
    module Model 
    def self.included(klass) 
     klass.extend ClassMethods 
    end 

    module ClassMethods 
     def sendable(class_to_send_to) 
     attr_accessor :fax_number, 
         :email_address, 
         :to_be_faxed, 
         :to_be_emailed, 
         :to_be_printed 

     @_class_sending_to ||= class_to_send_to 

     include InstanceMethods 
     end 

     def class_sending_to 
     @_class_sending_to 
     end 
    end # ClassMethods 

    module InstanceMethods 
     def after_initialize() 
     super 
     self.to_be_faxed = false 
     self.to_be_emailed = false 
     self.to_be_printed = false 

     target_class = self.send(self.class.class_sending_to) 
     if !target_class.nil? 
      self.fax_number  = target_class.send(:fax_number) 
      self.email_address = target_class.send(:email_address) 
     end 
     end 
    end 
    end # Module Model 
end # Module Sendable 

Fondamentalement, je prévois faire juste un include :: expédiable Controller et expédiable :: Voir le (ou l'équivalent) pour le contrôleur et la vue, mais, y a-t-il une façon plus propre de faire ce? Je suis d'une manière soignée d'avoir un tas de code commun entre mon modèle, contrôleur et vue. Edit: Juste pour clarifier, cela doit juste être partagé entre 2 ou 3 modèles.

Répondre

7

Vous pouvez le pluginiser (utilisez script/generate plugin).

Ensuite, dans votre init.rb faire quelque chose comme:

ActiveRecord::Base.send(:include, PluginName::Sendable) 
ActionController::Base.send(:include, PluginName::SendableController) 

Et avec votre self.included qui devrait fonctionner très bien.

Découvrez quelques-unes des acts_ * plugins, il est un modèle assez courant (http://github.com/technoweenie/acts_as_paranoid/tree/master/init.rb, vérifiez la ligne 30)

+0

J'ai choisi cette réponse, même si Hoyhoy est aussi très bien, juste parce que ça correspond mieux à ce que je fais. – Mike

+0

C'est vraiment la même chose. C'est une meilleure syntaxe. – hoyhoy

6

Si ce code doit s'ajouter à tous les modèles et tous les contrôleurs, vous pouvez toujours effectuer les opérations suivantes:

# maybe put this in environment.rb or in your module declaration 
class ActiveRecord::Base 
    include Iso 
end 

# application.rb 
class ApplicationController 
    include Iso 
end 

Si vous avez besoin des fonctions de ce module disponible à la vue, vous pouvez les exposer individuellement helper_method déclarations dans application.rb.

+0

C'est ce que je vais probablement faire, ça ne devrait pas être un problème tant que mes fonctions, etc, n'ont pas de collisions de noms? – Mike

1

Si vous allez la route plug-in, faire vérifier Rails-Engines, qui sont destinés à étendre la sémantique plugin à Contrôleurs et vues d'une manière claire.

+0

J'ai jeté un coup d'œil, cela pourrait peut-être résoudre mon problème. Mais je ne suis pas sûr d'être encore à ce stade. – Mike