Home > Back-end >  Inverse validity error in rails when importing records
Inverse validity error in rails when importing records

Time:12-13

I'm getting the error ActiveRecord::InverseOfAssociationNotFoundError (Could not find the inverse association for sponsorships (:sponsor_type in LegiscanModel::Sponsorship) when importing records using sidekiq. Below are my models.

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 job(partial)

  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

CodePudding user response:

If you actually set your classes up properly with explicit nesting instead of using the scope resolution operator you can dramatically improve this code:

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

While this might seem like a trivial stylistic choice its really not - by using module LegiscanModel you're reopening the module and setting the module nesting so that you can refer to constants in the same namespace.

This also avoids autoloading errors and bugs due to suprising constant lookup. :: should only be used when refering to constants - not when defining them.

You also do not need to specify the foreign key option when it can be derived from the name of the assocation. While there is no harm in it but its extra noise. Rails can also automatically infer the inverses. You can check it with if you want to through the assocation reflexion:

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