Comment écrire un mixin Rails qui couvre plusieurs modèles, contrôleurs et vues
-
09-06-2019 - |
Question
Dans le but de réduire la duplication de code dans ma petite application Rails, je travaille à obtenir du code commun entre mes modèles dans son propre module séparé, jusqu'à présent, tout va bien.
Le modèle est assez simple, il suffit d'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 bien, mais je vais maintenant avoir un contrôleur et un code d'affichage communs à ces modèles, jusqu'à présent, j'ai ceci pour mes éléments à envoyer:
# 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
En gros, je prévois de faire simplement include avec Sendable :: Controller, et Sendable :: View (ou l’équivalent) pour le contrôleur et la vue, mais existe-t-il une méthode plus propre pour le faire? Je cherche un moyen génial d’avoir un tas de codes communs entre mon modèle, mon contrôleur et ma vue.
Éditer: Juste pour clarifier, cela doit juste être partagé entre 2 ou 3 modèles.
La solution
Vous pouvez le brancher (utilisez le plugin script / generate).
Ensuite, dans votre init.rb, faites quelque chose comme:
ActiveRecord::Base.send(:include, PluginName::Sendable)
ActionController::Base.send(:include, PluginName::SendableController)
Et avec votre auto.included cela devrait fonctionner très bien.
Découvrez quelques-uns des plugins act_ *, il s'agit d'un modèle assez courant ( http://github.com/technoweenie/acts_as_paranoid/tree/master/init.rb , vérifiez la ligne 30)
Autres conseils
Si ce code doit être ajouté à 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 aviez besoin des fonctions de ce module disponibles pour les vues, vous pouvez les exposer individuellement avec des déclarations helper_method
dans application.rb.
Si vous suivez la route du plugin, consultez Rails-Engines , qui sont destinés à être étendus. sémantique du plug-in aux contrôleurs et aux vues de manière claire.