【问题标题】:How to share code across models? (Rails 2.3)如何跨模型共享代码? (轨道 2.3)
【发布时间】:2023-04-09 21:15:02
【问题描述】:

我想在模型之间共享几种方法,而不是复制和粘贴它们。在控制器中,我可以通过将方法放在 application_controller.rb 中来做到这一点,它会自动包含在每个控制器中。 模型有类似的东西吗?

谢谢!

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    为了补充 Josh 的答案,有时您可能想要共享一些定义多态关联的代码。你不能只把has_many方法调用放在你的模块中,因为你会得到一个错误,例如在一个名为Votable的模块中:

    undefined method `has_many' for Voteable:Module (NoMethodError)
    

    因此,您需要使用self.included(base) 方法和base.instance_eval。这是我的 Voteable 模块的示例:

    module Voteable
    
      def self.included(base)
        base.instance_eval do
          has_many :votes, as: :voteable
          has_many :voters, through: :votes
        end
      end
    
      def voted_up_by?(user)
        user and votes.exists?(value: 1, voter_id: user)
      end
    
      def voted_down_by?(user)
        user and votes.exists?(value: -1, voter_id: user)
      end
    
    end
    

    现在您可以在具有该行为的模型中include Voteable。这将执行self.included(base) 方法并定义包含类的关联。

    【讨论】:

    • 在 Rails 3 中,这更容易——您可以将 def self.included(base) base.instance_eval 替换为 extend ActiveSupport::Concern included
    【解决方案2】:

    上面的最佳解决方案对我有用。在 Rails 3 中,我发现我还必须将 application.rb 文件更新为:config.autoload_paths += Dir["#{config.root}/lib/**/"],此处回答:Best way to load module/class from lib folder in Rails 3?

    【讨论】:

      【解决方案3】:

      您可以通过多种方式在 2 个模型类之间共享方法。

      • 如果模型彼此相关,请使用inheritance,例如包含方法的共享父类,或者一个包含方法的子类。
      • 使用可以在多个模型之间共享的modules/mixins

      【讨论】:

      • Turn those methods into helper methods that both models have access to - 我认为模型无法访问辅助方法。这怎么可能(似乎是我正在尝试做的最干净的方法)
      • 你是对的。我在考虑实用方法,而不是 Rails 意义上的“辅助方法”。所以 mixin 方法会比实用方法更有用。
      【解决方案4】:

      您可以在 Rails 应用程序的 lib 目录中创建一个名为 functionality.rb 或类似名称的文件。制作以模块命名的文件,以便在 Rails 启动时自动加载它。例如,如果我想为多个模型添加标记,我会创建一个名为 lib/flagging.rb 的文件,它看起来像这样:

      module Flagging
        # Flags an object for further review
        def flag!
          self.update_attribute(:flagged, true)
        end
      
        # Clears all flags on an object
        def deflag!
          self.update_attribute(:flagged, false)
        end
      end
      

      在我想要添加此功能的每个模型中,我都会执行以下操作:

      class Foo < ActiveRecord::Base
        include Flagging
      end
      

      然后我就可以做类似的事情了:

      foo = Foo.create
      foo.flag!
      

      【讨论】:

      • 老兄。这都是关于 lib 目录的。我已经开始在那里放更多的代码,它只是组织东西的方便地方。
      【解决方案5】:

      你可以 a) 做一些类似于 application_controller 的事情并创建一个模型类,其他人可以从中继承或 b) 使用一个模块。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-23
        • 2012-05-09
        相关资源
        最近更新 更多