ActiveRecord::Base不属于从ActiveRecord下降的层次结构。

15

我正在尝试创建一个Rails插件。在大部分情况下,我所编写的代码都是有效的。然而,在关联方面出现了问题。当我尝试调用一个关联时,会出现以下错误:

ActiveRecord::Base doesn't belong in a hierarchy descending from ActiveRecord

目前,该插件的外观如下:

module ControlledVersioning
  module ActsAsVersionable
    extend ActiveSupport::Concern

    included do
      has_many :versions, as: :versionable

      after_create :create_initial_version
    end

    module ClassMethods
      def acts_as_versionable(options = {})

        cattr_accessor :versionable_attributes
        self.versionable_attributes = options[:versionable_attributes]
      end
    end

    private
    def create_initial_version
      version = versions.create
    end
  end
end

ActiveRecord::Base.send :include, ControlledVersioning::ActsAsVersionable

再次强调,每当我尝试调用关联时都会触发错误消息。我在after_create回调中使用了调试器并尝试运行:

> versions.create
*** ActiveRecord::Base doesn't belong in a hierarchy descending from ActiveRecord

> versions
*** ActiveRecord::Base doesn't belong in a hierarchy descending from ActiveRecord

> Version.new
#<Version id: nil, versionable_id: nil, versionable_type: nil>

你可能会发现这个答案有用,还要阅读答案上的评论https://dev59.com/4HrZa4cB1Zd3GeqP57j_ - jamesc
不确定这是否适用于此情况。由于这是一个插件,我无法直接将关注点包含在模型中。我正在使用Rails指南推荐的相同格式,您可以在此处看到:http://guides.rubyonrails.org/plugins.html#add-an-instance-method。他们在插件中使用关注点,在他们的情况下似乎运行良好。 - nullnullnull
1
决定查看paperclip的处理方式。他们没有使用concern,而是在has_paper_trail函数中包含了所有关联和回调。我也效仿了这种做法,一切都正常工作了。 - nullnullnull
在使用scope调用时遇到这个问题后,我只是创建了一个自定义方法。对于作用域而言,在Rails 3中它几乎等效。同样的逻辑也可能适用于关联。 - mahemoff
2个回答

1

为了代码能够正常工作,您需要更改几个方面。

首先,versions是Rails中保留的关键字 -- 您无法使用该名称建立关系 - (我使用名称versionings使其正常工作)

另外,您需要确定只为想要acts_as_versionable的模型添加has_many versionings - 这意味着将has_many :versionings,as::versionable,class_name:'Version'after_create :create_initial_version调用移动到acts_as_versionable 方法内部。

下面是整体代码:

module ControlledVersioning
  module ActsAsVersionable
    extend ActiveSupport::Concern

    module ClassMethods
      def acts_as_versionable(options = {})
        has_many :versionings, as: :versionable, class_name: 'Version'
        after_create :create_initial_version

        cattr_accessor :versionable_attributes
        self.versionable_attributes = options[:versionable_attributes]
      end
    end

    private

    def create_initial_version
      version = versionings.create
    end
  end
end

ActiveRecord::Base.send :include, ControlledVersioning::ActsAsVersionable

进行这些更改使插件对我起作用:

irb(main):003:0> Post.create!
   (0.1ms)  begin transaction
  Post Create (0.7ms)  INSERT INTO "posts" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2019-07-16 08:55:13.768196"], ["updated_at", "2019-07-16 08:55:13.768196"]]
  Version Create (0.2ms)  INSERT INTO "versions" ("versionable_type", "versionable_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["versionable_type", "Post"], ["versionable_id", 3], ["created_at", "2019-07-16 08:55:13.772246"], ["updated_at", "2019-07-16 08:55:13.772246"]]
   (2.0ms)  commit transaction
=> #<Post id: 3, created_at: "2019-07-16 08:55:13", updated_at: "2019-07-16 08:55:13", name: nil>
irb(main):004:0> Post.last.versionings
  Post Load (0.2ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ?  [["LIMIT", 1]]
  Version Load (0.2ms)  SELECT  "versions".* FROM "versions" WHERE "versions"."versionable_id" = ? AND "versions"."versionable_type" = ? LIMIT ?  [["versionable_id", 3], ["versionable_type", "Post"], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Version id: 2, versionable_type: "Post", versionable_id: 3, created_at: "2019-07-16 08:55:13", updated_at: "2019-07-16 08:55:13">]>
irb(main):005:0> 

0
我会尝试在初始化程序中扩展Active Record而不是包含它。

initializers/acts_as_versionable.rb ActiveRecord::Base.extend(ControlledVersioning::ActsAsVersionable)

同样在开发中,或者任何重新加载文件的环境中,你可能会看到一个错误信息,类似于“已从模块树中删除但仍处于活动状态”。请确保你的插件文件位于config.eager_load_paths中,而不是实际上在concern路径中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接