【问题标题】:Unable to extend ActiveRecord from within gem无法从 gem 中扩展 ActiveRecord
【发布时间】:2023-04-02 19:08:01
【问题描述】:

我希望我的 gem 为我的 AR 类添加一个方法,以启用某些功能:

class User < ApplicationRecord
  enable_my_uber_features :blah
end

为此,在 my_uber_gem/lib/uber_gem.rb 中,我尝试以下操作:

# my_uber_gem/lib/uber_gem.rb

require "active_support"
# ...
require "uber/extensions"
# ...

ActiveSupport.on_load(:active_record) do

  class ActiveRecord::Base
    include Uber::Extensions
  end
end

在 uber/extensions.rb 我有:

# my_uber_gem/lib/uber/extensions.rb

require 'active_support/concern'
module Uber
    module Extensions
        extend ActiveSupport::Concern
        
        instance_methods do
            def foo
                p :bar
            end
        end

        class_methods do
            def enable_my_uber_features(value)
                p value
            end
        end
    end
end

现在我希望在实例化用户时在控制台中看到一个废话,但是我收到一个错误:

[...] `method_missing': undefined method `enable_my_uber_features' for User:Class (NoMethodError)

我尝试将 Uber::Extensions 包含到 ApplicationRecord 而不是 ActiveRecord::Base 中,但没有成功。

我也尝试过扩展Uber::Extensions,没有运气。

我也尝试在 Uber::Extensions 中定义一个 module ClassMethods 扩展/包含,仍然没有运气。

我也按照这个人的指导信了:https://waynechu.cc/posts/405-how-to-extend-activerecord,仍然没有运气。

我做错了吗?

【问题讨论】:

  • 你使用的是什么 ruby​​ on rails 版本?
  • 你是如何安装这个 gem 的?你确定这个文件正在加载吗?
  • 如果ApplicationRecord 可以做同样的事情,为什么还要扩展ActiveRecord::Base
  • 您希望enable_my_uber_features 成为类方法还是实例方法?您将其作为 User 类中的类方法调用,但您将其定义为实例方法。
  • 我从来没有真正明白为什么 gems 不能让你明确地包含它们而不是猴子修补它们进入系统的方式。您只是为最终用户节省了一行代码。

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


【解决方案1】:

我这样做的方式是:

# in my_uber_gem/lib/active_record/base/activerecord_base.rb
require 'uber/extensions'
class ActiveRecord::Base
  include Uber::Extensions
  def baz
    p "got baz"
  end
end

# and in the my_uber_gem/lib/my_uber_gem.rb
module MyUberGem
  require_relative './active_record/base/activerecord_base.rb'
end

# and finally define the extension in my_uber_gem/lib/uber/extensions.rb
require 'active_support/concern'
class Uber
  module Extensions
    extend ActiveSupport::Concern
    def foobar(val)
      p val
    end
  end
end

# now you can do
User.first.foobar("qux") #=> "qux"
User.first.baz #=> "got baz"

【讨论】:

  • require_relative 放在模块定义中不会改变其范围。
  • @engineersmnky 我不确定你的意思。但无论如何,我有这个工作,如图所示。
  • 我的意思是把require_relative 放在MyUberGem 里面并不包含在这个模块的范围内。它与将其放置在模块之外或其他任何地方具有相同的影响。 Example
【解决方案2】:

事实证明,Rails 正在缓存我正在处理的本地 gem,而我对任何 gem 文件所做的任何更改仅在新应用程序中或重建整个机器后可见。

我可以将其关闭,以便在每次重新加载控制台时重新加载 gem:

  # config/environments/development.rb
  config.autoload_paths += %W(#{config.root}/../my_uber_gem/lib)
  ActiveSupport::Dependencies.explicitly_unloadable_constants << 'MyUberGem'

【讨论】:

    猜你喜欢
    • 2015-03-13
    • 1970-01-01
    • 2015-07-20
    • 2015-06-18
    • 1970-01-01
    • 2011-05-27
    • 2019-06-20
    • 2010-09-07
    相关资源
    最近更新 更多