ruby-on-rails ActiveRecord::HasManyThroughOrderError

nue99wik  于 2023-04-22  发布在  Ruby
关注(0)|答案(4)|浏览(224)

我在3个模型之间有一个has_one关联,但它有一个错误,说“ActionView::Template::Error(Cannot have a has_many:through association 'Policy#intermediary' which goes through 'Policy#invoice' before the through association is defined.)”。
政策模型

class Policy < ApplicationRecord

    self.table_name = "gipi_polbasic"
    self.primary_key = "policy_id"

    has_one :invoice
    has_one :intermediary, through: :invoice, foreign_key: :intrmdry_intm_no

中介模型

class Intermediary < ApplicationRecord
    self.table_name = "giis_intermediary"
    self.primary_key = "intm_no"

    has_one :invoice, foreign_key: :intrmdry_intm_no
    belongs_to :policy, foreign_key: :policy_id

发票模型

class Invoice < ApplicationRecord
    self.table_name = "gipi_comm_invoice"
    self.primary_key = "intrmdry_intm_no"

    belongs_to :policy, foreign_key: :policy_id
    belongs_to :intermediary, foreign_key: :intrmdry_intm_no
h6my8fg2

h6my8fg21#

对于其他人-查看他们的线程https://github.com/rails/rails/issues/29123
对我来说,解决这个问题的方法是改变has_ones的顺序

has_one :intermediary, through: :invoice, foreign_key: :intrmdry_intm_no
has_one :invoice
2w2cym1i

2w2cym1i2#

这里有一个查找重复关联定义的技术,以防您有由几个猴子补丁组成的模型。
首先,找到has_many方法:

ActiveRecord::Associations::ClassMethods.instance_method(:has_many).source_location

然后,编辑该文件:

def has_many(name, scope = nil, options = {}, &extension)
      $has_manies ||= {}                               # <- Added
      $has_manies[[name, self]] ||= []                 # <- Added
      $has_manies[[name, self]] << [options,caller[0]] # <- Added
      reflection = Builder::HasMany.build(self, name, scope, options, &extension)
      Reflection.add_reflection self, name, reflection
    end

然后捕获HasManyThroughOrderError并启动调试器。评估以下内容:

$has_manies[[:intermediary, Policy]]

您不仅可以看到该关联是否被多次定义,还可以看到定义发生的位置。

ua4mk5z4

ua4mk5z43#

请确保您的Policy型号中没有另一个冗余has_one :intermediary。更新后出现相同的错误。

6rqinv9w

6rqinv9w4#

似乎新规则是在使用关系之前需要定义关系。
例如,这在rails 5.1中不起作用

class User < ActiveRecord::Base
  has_many :phone_calls,
           :through => :phone_call_participants,
           :source => :phone_call
  has_many :phone_call_participants, :as => :participant
end

但这个可以:

class User < ActiveRecord::Base
  has_many :phone_call_participants, :as => :participant
  has_many :phone_calls,
           :through => :phone_call_participants,
           :source => :phone_call
end

我猜这会加快代码解释的速度,因为文件不必扫描那么多次。

相关问题