2

我的几个 Rails 模型中有一些逻辑,我想将它们拆分为单独的文件。

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

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

# 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'

但这会产生其他 gem 的问题(例如,加载 User 模型时未加载设计)。

有什么好方法可以做到这一点,还是我在这里不自在?利用 Ruby 的开放类是 Rails 之外的常见习惯用法。

4

3 回答 3

2

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

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

这将自动加载integrations/extRails 需要的类。(这恰好也是 DHH 的要点包含app/model/concerns文件的方式)。

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

于 2012-08-05T02:26:57.450 回答
1

如果我理解正确,您要做的是将仍然特定于模型的代码(在多个模型之间不常见,表明 mixin 是正确的方法) 模型中移出以使其保持“精简”;模型中实际上看起来“关闭”的代码。

当我看到模型中的代码变得有点过于复杂或涉及直接在模型中看起来错误的任务时,我会在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由于这种分离,它也更容易测试。

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

于 2012-08-05T19:30:05.900 回答
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

于 2012-08-05T08:27:39.400 回答