在Rails 5 Application Record类中包含一个模块

时间:2017-06-12 12:02:28

标签: ruby-on-rails ruby metaprogramming ruby-on-rails-5

我正在使用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 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_scopeUser上的Message未定义。

有没有办法确保所包含的模块在适当的时间加载并可用于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

3 个答案:

答案 0 :(得分:5)

作为@ 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

答案 1 :(得分:3)

  

在这种情况下,我没有得到加载错误,但是boolean_scope就是   用户和消息未定义

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

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

现在您可以像User.boolean_scope一样调用它。以下是 include vs 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>

答案 2 :(得分:2)

您的fct()User类似乎没有继承Message。他们将如何访问ApplicationRecord

试试这个:

::boolean_scope