モデル、コントローラー、ビューにまたがる Rails ミックスインを作成する方法
-
09-06-2019 - |
質問
私の小さな Rails アプリでコードの重複を減らすために、モデル間の共通コードを独自の別個のモジュールに取り込むことに取り組んできましたが、これまでのところうまくいきました。
モデルの作業は非常に簡単で、最初にモジュールを含めるだけです。例:
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
これは正常に動作していますが、これらのモデル間で共通となるいくつかのコントローラーとビューのコードを用意します。これまでのところ、送信可能なものには次のコードがあります。
# 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
基本的に、コントローラーとビューに対して Sendable::Controller と Sendable::View (または同等のもの) を含めることを計画していますが、これを行うよりクリーンな方法はありますか?モデル、コントローラー、ビューの間で共通のコードをたくさん持つための巧妙な方法を探しています。
編集:明確にしておきますが、これは 2 つまたは 3 つのモデル間で共有する必要があるだけです。
解決
プラグイン化することもできます (スクリプトを使用/プラグインを生成)。
次に、init.rb で次のようなことを実行します。
ActiveRecord::Base.send(:include, PluginName::Sendable)
ActionController::Base.send(:include, PluginName::SendableController)
そして、あなたの self.include と一緒に、それは問題なく動作するはずです。
いくつかの act_* プラグインをチェックしてください。これは非常に一般的なパターンです (http://github.com/technoweenie/acts_as_paranoid/tree/master/init.rb, 、30行目を確認してください)
他のヒント
そのコードをすべてのモデルとすべてのコントローラーに追加する必要がある場合は、いつでも次の操作を行うことができます。
# maybe put this in environment.rb or in your module declaration
class ActiveRecord::Base
include Iso
end
# application.rb
class ApplicationController
include Iso
end
このモジュールの関数をビューで使用できるようにする必要がある場合は、次のようにしてそれらを個別に公開できます。 helper_method
application.rb 内の宣言。
プラグインのルートを選択する場合は、チェックしてください レールエンジン, 、これはプラグインのセマンティクスを明確な方法でコントローラーとビューに拡張することを目的としています。