在 Rails 5 申请记录中包含一个模块 class

Including a module in a Rails 5 Application Record class

我正在使用 Application Record 来简化整个应用程序的共享逻辑。

这是一个为布尔值及其逆函数编写作用域的示例。这很好用:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def self.boolean_scope(attr, opposite = nil)
    scope(attr, -> { where("#{attr}": true) })
    scope(opposite, -> { where("#{attr}": false) }) if opposite.present?
  end
end

class User < ApplicationRecord
  boolean_scope :verified, :unverified
end

class Message < ApplicationRecord
  boolean_scope :sent, :pending
end

我的申请记录 class 足够长,我可以将其分解成单独的模块并根据需要加载它们。

这是我尝试的解决方案:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  include ScopeHelpers
end

module ScopeHelpers
  def self.boolean_scope(attr, opposite = nil)
    scope(attr, -> { where("#{attr}": true) })
    scope(opposite, -> { where("#{attr}": false) }) if opposite.present?
  end
end

class User < ApplicationRecord
  boolean_scope :verified, :unverified
end

class Message < ApplicationRecord
  boolean_scope :sent, :pending
end

在这种情况下,我没有收到加载错误,但是 boolean_scopeUserMessage.

上未定义

有没有办法确保包含的模块在适当的时间加载并可供 Application Record 及其继承模型使用?


我也曾尝试让模型直接包含模块,但这并没有解决问题。

module ScopeHelpers
  def self.boolean_scope(attr, opposite = nil)
    scope(attr, -> { where("#{attr}": true) })
    scope(opposite, -> { where("#{attr}": false) }) if opposite.present?
  end
end

class User < ApplicationRecord
  include ScopeHelpers
  boolean_scope :verified, :unverified
end

class Message < ApplicationRecord
  include ScopeHelpers
  boolean_scope :sent, :pending
end

您的 UserMessage 类 似乎没有继承 ApplicationRecord。他们将如何访问 ::boolean_scope

试试这个:

class User < ApplicationRecord
  boolean_scope :verified, :unverified
end

class Message < ApplicationRecord
  boolean_scope :sent, :pending
end

In this case, I don't get a load error, but boolean_scope is then undefined on User and Message

问题是 include 在 class 的 实例上添加方法。您需要使用 extend

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  extend ScopeHelpers
end

现在您可以像 User.boolean_scope 那样称呼它了。以下是 include 与 extend

的示例
module Foo
  def foo
    puts 'heyyyyoooo!'
  end
end

class Bar
  include Foo
end

Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class

class Baz
  extend Foo
end

Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>

作为@Pavan 答案的替代方案,您可以这样做:

module ScopeHelpers
  extend ActiveSupport::Concern # to handle ClassMethods submodule

  module ClassMethods
    def boolean_scope(attr, opposite = nil)
      scope(attr, -> { where(attr => true) })
      scope(opposite, -> { where(attr => false) }) if opposite.present?
    end
  end
end

# then use it as usual
class ApplicationRecord < ActiveRecord::Base
  include ScopeHelpers
  ...
end