如何编写跨模型、控制器和视图的 Rails mixin
-
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.included 一起应该可以正常工作。
查看一些 acts_* 插件,这是一个非常常见的模式(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 中的声明。
如果您确实走插件路线,请查看 铁路发动机, ,旨在以清晰的方式将插件语义扩展到控制器和视图。
不隶属于 StackOverflow