Rails模型分为多个定义

时间:2012-08-05 02:20:28

标签: ruby-on-rails ruby ruby-on-rails-3 activesupport

我在我的几个rails模型中有一些逻辑,我想将它拆分成单独的文件。

具体来说,这是这些模型所独有的逻辑,而不是模型之间共享的东西。对于这种情况,我知道担忧/混合和问题like this

由于我们在这里处理Ruby,似乎要走的路是拥有多个类定义。 E.g:

# in app/models/user.rb
class User < ActiveRecord::Base
  ...
end

# in app/lib/integrations/ext/user.rb
class User
  ...
end

我现在面临的问题是现在需要在正确的位置进行模型扩展。由于自动加载,我被迫明确要求模型和扩展。我目前的最大努力是在初始化程序中预加载用户模型及其扩展名:

# in config/initializers/model_extensions.rb
require_dependency 'models/user'
require_dependency 'integrations/ext/user.rb'

但这会产生其他宝石的问题(例如,加载用户模型时不会加载Devise)。

有没有一个很好的方法可以做到这一点,还是我不在这里?利用Ruby的开放类是Rails之外的常用习语。

3 个答案:

答案 0 :(得分:2)

将以下内容添加到config/application.rb

config.autoload_paths += Dir["#{config.root}/lib"]

这将自动加载来自integrations/ext的类,因为Rails需要它们。 (这恰好也是DHH的要点也包括app/model/concerns文件)。

(我更改了自动加载以匹配@ denis.pelin所拥有的内容。我错过integrations/位于lib/,所以上面应该足以自动加载了

答案 1 :(得分:1)

如果我理解正确,你要做的是移动仍然特定于 a 模型的代码(在多个模型之间不常见,这表明mixin是正确的方法) out 模型以保持“瘦”;代码实际上只是在模型中存在“关闭”。

当我看到我的模型中的代码变得有点过于复杂或涉及直接在模型中看起来错误的任务时,我在lib/中创建了一个文件。对于(简化)示例,给出类似

的模型
class User < ActiveRecord::Base

  def self.create_admin!(attrs)
    # complex logic to setup admin user account here
    newly_created_user.deliver_confirmation_email!
  end

  def deliver_confirmation_email!
    # sends email off to user represented by this class instance
  end
end

这对我在模特中看起来很糟糕。但是在我的控制器的create操作中为上述方法设置了几十行代码看起来更糟糕,并且更难测试。

我会将此代码移至lib/MyNamespace/user_repo.rb

module MyNamespace
  module UserRepo
    extend self

    def create_admin!(attrs)
      # complex logic to setup admin user account here
      deliver_confirmation_email!(newly_created_user)
    end

    private
      def deliver_confirmation_email!(user)
        # sends email off to user represented by this class instance
      end
  end
end

现在,在我的控制器中的create操作中,而不是调用

User.create_admin!(params[:user])

我会打电话给

MyNamespace::UserRepo::create_admin!(params[:user])

MyNamespace::UserRepo负责管理管理员帐户的User记录发生的事情,让我的控制器操作我的模型保持良好和干净。由于这种分离,测试MyNamespace::UserRepo也更容易。

这仍然无法解决您在获取需要您正在寻找的代码时遇到的问题,但可能会为您要实现的目标提供替代解决方案。

答案 2 :(得分:0)

在我的一个应用程序中,我在application.rb中取消注释了自动加载行:

# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)

lib目录中的一些模块:

# lib/some_module.rb
module SomeModule
  def some_method
  end
end

并包含在模型中:

# app/models/user.rb
class User < ActiveRecord::Base
  include SomeModule
end

现在用户实例有some_method