导入记录时 rails 中的反向有效性错误

Inverse validity error in rails when importing records

我在使用 sidekiq 导入记录时遇到错误 ActiveRecord::InverseOfAssociationNotFoundError (Could not find the inverse association for sponsorships (:sponsor_type in LegiscanModel::Sponsorship)。以下是我的模型。

sponsorship.rb

class LegiscanModel::Sponsorship < ApplicationRecord
  belongs_to :bill, class_name: 'LegiscanModel::Bill', foreign_key: 'bill_id', inverse_of: :sponsorships

  belongs_to :sponsor, class_name: 'LegiscanModel::Politician', foreign_key: :politician_id, inverse_of: :sponsorships
  accepts_nested_attributes_for :sponsor
  delegate :full_name, to: :sponsor, prefix: true, allow_nil: true

  validates :politician_id, uniqueness: { scope: :bill }

  belongs_to :sponsorship_type, class_name: 'LegiscanModel::SponsorType', foreign_key: :sponsor_type_id, inverse_of: :sponsorships
end

sponsor_type.rb

class LegiscanModel::SponsorType < ApplicationRecord
  has_many :sponsorships, class_name: 'LegiscanModel::Sponsorship', inverse_of: :sponsor_type, dependent: :destroy
end

politician.rb

has_many :sponsorships, dependent: :destroy, inverse_of: :sponsor, class_name: 'LegiscanModel::Sponsorship'

sidekiq 作业(部分)

  def handle_sponsors(sponsors, bill_id)
    sponsors.each do |sponsor|
      LegiscanModel::Politician.find_by(people_id: sponsor['people_id']).tap do |politician|
        LegiscanModel::Sponsorship.find_or_create_by!(politician_id: politician.id, bill_id: bill_id, sponsor_order: sponsor['sponsor_order'], sponsor_type_id: sponsor['sponsor_type_id'])
      end
    end
  end

如果您实际上通过显式嵌套正确设置了 类 而不是使用范围解析运算符,则可以显着改进此代码:

module LegiscanModel
  class Sponsorship < ApplicationRecord
    belongs_to :bill
    belongs_to :sponsor, 
       class_name: 'Politician', # specifying the module is optional
       inverse_of: :sponsorships
    belongs_to :sponsorship_type

    accepts_nested_attributes_for :sponsor
    delegate :full_name, to: :sponsor, prefix: true, allow_nil: true
    # should be the database column since its used to create a query
    validates :politician_id, uniqueness: { scope: :bill_id } 
  end
end 
module LegiscanModel
  class SponsorshipType < ApplicationRecord
    has_many :sponsorships, dependent: :destroy
  end
end

虽然这看起来像是一个微不足道的风格选择,但实际上并非如此 - 通过使用 module LegiscanModel 您将重新打开模块并设置模块嵌套,以便您可以引用同一命名空间中的常量。

这也避免了由于不断查找而导致的自动加载错误和错误。 :: 只应在引用常量时使用 - 而不是在定义常量时使用。

当可以从关联名称派生时,您也不需要指定外键选项。虽然它没有任何危害,但它会产生额外的噪音。 Rails 也可以自动推断逆。如果你想通过关联反射,你可以检查它:

LegiscanModel::Sponsorship.reflect_on_assocation(:sponsorship_type)
                          .inverse