【问题标题】:How to write a Rails mixin that spans across model, controller, and view如何编写跨模型、控制器和视图的 Rails mixin
【发布时间】:2010-09-09 06:20:02
【问题描述】:

为了减少我的小 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 个模型之间共享。

【问题讨论】:

    标签: ruby-on-rails ruby refactoring dry


    【解决方案1】:

    如果你确实走插件路线,请查看Rails-Engines,它旨在以清晰的方式将插件语义扩展到控制器和视图。

    【讨论】:

    • 我快速浏览了一下,这也许可以解决我的问题。但我不太确定我是否处于这个阶段。
    【解决方案2】:

    你可以插件化它(使用脚本/生成插件)。

    然后在您的 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 行)

    【讨论】:

    • 我选择了这个答案,尽管 Hoyhoy 的也很好,只是因为它更适合我正在做的事情。
    • 其实是一回事。这是一个更好的语法。
    【解决方案3】:

    如果需要将该代码添加到所有模型和所有控制器中,您始终可以执行以下操作:

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

    如果您需要此模块中可用于视图的函数,您可以使用 application.rb 中的 helper_method 声明单独公开它们。

    【讨论】:

    • 这是我可能最终会做的事情,只要我的函数等没有任何名称冲突,这应该不是问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    • 2013-04-28
    • 2013-08-28
    相关资源
    最近更新 更多