【问题标题】:Splitting a class into multiple files in Ruby on Rails在 Ruby on Rails 中将一个类拆分为多个文件
【发布时间】:2011-03-09 04:56:04
【问题描述】:

我正在尝试将大型模型拆分为多个文件以进行逻辑组织。所以我有两个文件:

model1.rb

class Model1 < ActiveRecord::Base
  before_destroy :destroying
  has_many :things, :dependent=>:destroy

  def method1
    ...
  end
  def method2
    ...
  end

end
require 'model1_section1'

model1_section1.rb

class Model1
  def method3
    ...
  end
  def self.class_method4
    ...
  end
end

但是当应用程序加载时,有一个对 Model1.class_method4 的调用,我得到:

undefined method `class_method4' for #<Class:0x92534d0>

我也尝试过这个要求:

require File.join(File.dirname(__FILE__), 'model1_section1')

我在这里做错了什么?

【问题讨论】:

  • @Kaleb Brasee 这应该有帮助吗?您是否对(完全制造的)类和方法名称做出反应,或者是否有合理的理由进行偏离主题的讽刺评论?
  • 只是在这里寻找语言语法/结构的帮助,而不是重构或优化,当然也不是为了技术术语下降。 这不是真正的代码 - 当然有味道。
  • 我也很惊讶这不起作用:我认为这就是 Ruby 中所谓的“类重新开放”。
  • 您是否尝试过要求第二个文件中的第一个文件,而不是第一个中的第二个文件?

标签: ruby-on-rails model


【解决方案1】:

我知道我回答这个问题有点晚了,但我刚刚在我的一个应用程序中完成了这个,所以我想我会发布我使用的解决方案。

这是我的模型:

class Model1 < ActiveRecord::Base

  # Stuff you'd like to keep in here
  before_destroy :destroying
  has_many :things, :dependent => :destroy

  def method1
  end
  def method2
  end

  # Stuff you'd like to extract
  before_create :to_creation_stuff
  scope :really_great_ones, #...

  def method3
  end
  def method4
  end
end

您可以将其重构为:

# app/models/model1.rb
require 'app/models/model1_mixins/extra_stuff'
class Model1 < ActiveRecord::Base

  include Model1Mixins::ExtraStuff

  # Stuff you'd like to keep in here
  before_destroy :destroying
  has_many :things, :dependent => :destroy

  def method1
  end
  def method2
  end
end

和:

# app/models/model1_mixins/extra_stuff.rb
module Model1Mixins::ExtraStuff

  extend ActiveSupport::Concern

  included do
    before_create :to_creation_stuff
    scope :really_great_ones, #...
  end

  def method3
  end
  def method4
  end
end

感谢ActiveSupport::Concern 为您提供的额外清洁,它可以完美运行。希望这能解决这个老问题。

【讨论】:

  • 我相信模型应该是模块
  • 这个方法对你有用吗?当我在模块中执行 def self.method3 时,它仍然对我不起作用。
  • 在 Rails 5.1(可能更早)中,您可以使用 model/concerns 文件夹来保存模块。该模块不需要命名空间(只是模块 ExtraStuff)。然后“包括额外的东西”并要求“关注/额外的东西”
【解决方案2】:

这里有一篇文章很好地提出了这个问题的解决方案:

http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

【讨论】:

    【解决方案3】:

    我知道我在这方面迟到了,但是在尝试自己解决这个问题时,我偶然发现了这个问题。

    我认为示例代码中为什么类重新打开没有按预期工作的答案是该类最初定义为:

    (在model1.rb中)

    class Model1 < ActiveRecord::Base
    

    然后重新打开为: (在model1_section1.rb中)

    class Model1
    

    即第二个定义缺少继承的类。

    我使用单独的 .rb 文件来拆分我的庞大模型,它们对我来说效果很好。虽然我承认我使用了 include 和类似的东西:

    (在 workcase.rb 中)

      class Workcase < ActiveRecord::Base
        include AuthorizationsWorkcase
        include WorkcaseMakePublic
        include WorkcasePostActions
    
        after_create :set_post_create_attributes 
        # associations, etc
    
        # rest of my core model definition
      end
    

    (在 workcase_make_public.rb 中)

      module WorkcaseMakePublic
        def alt_url_subject
          self.subject.gsub(/[^a-zA-Z0-9]/, '_').downcase
        end
        # more object definitions
      end
    
      class Workcase < ActiveRecord::Base
        def self.get_my_stuff
          do_something_non_instance_related
        end
        # more class definitions
      end  
    

    这使我可以将类和对象方法合并到每个包含的 .rb 文件中。唯一需要注意的是(因为我没有使用关注扩展)是从模块对象方法中访问类常量需要使用类名(例如 Workcase::SOME_CONST)而不是直接使用类名来限定常量。如果在主文件中调用。

    总体而言,这种方法似乎只需要对我的代码进行最少的重写就可以将事情变成可管理的代码块。

    也许这不是真正的“Rails 方式”,但它似乎在我的特定场景中运行良好。

    【讨论】:

      【解决方案4】:

      有一个名为modularity 的简洁宝石可以完全满足您的需求。

      gem-session 上有一个关于如何正确拆分它们的好指南。

      【讨论】:

      • 谢谢,我很感激,我已经看到了,但希望能够用语言本身而不是 gem 或插件来做到这一点。
      【解决方案5】:

      如果您真的想将一个类拆分为两个文件(类似于 C# 中的部分类),我不知道有一种对 ruby​​ 友好的方式来做到这一点。

      但是,一种常见的方法是通过Mixins 来结束具有大量功能(包括大量方法)的类。模块可以混合到一个类中,并且它们的方法实际上包含在类中。

      【讨论】:

        猜你喜欢
        • 2023-02-10
        • 1970-01-01
        • 2019-04-13
        • 1970-01-01
        • 2016-07-26
        • 2016-05-05
        • 2017-08-24
        • 1970-01-01
        • 2017-02-27
        相关资源
        最近更新 更多