Search code examples
ruby-on-railsmodelassociations

Creating a has_one through a has_many relationship


I currently have a ProductSale model that has_many sales. Also a sale belongs to an invoice.

My goal is to access an invoice through a ProductSale's association to sales. (product_sale.invoice)

Current ProductSale model below:

class ProductSale < ApplicationRecord
    has_many :sales
    has_one :invoice, through: :sales
end

However my current error is saying that this can't be done because the :through association is a collection, which i understand. Is there a way that this can be possible?

class Sale < ApplicationRecord
  belongs_to :invoice
 end

class Invoice < ApplicationRecord
  has_many :sales, inverse_of: :invoice, dependent: :destroy
end


Solution

  • All the sales on the ProductSale object have the same invoice. You know that you can just use the invoice of the first sale, but associations won't know that all the sales have the same invoice so you can use any, for instance the first one.

    To have a invoices method to get each of the invoices you could do this:

    class ProductSale < ApplicationRecord
        has_many :sales
        has_many :invoices, through: :sales
    end
    

    However, if you want to use your business logic that all the invoices are assumed to be the same, you will have to write a method to implement that business logic.

    class ProductSale < ApplicationRecord
        has_many :sales
    
        def invoice
          sales.first&.invoice
        end
    end
    

    If all the sales on the invoice will be sales in the ProductSale object, then maybe you should refactor as below.

    class ProductSale < ApplicationRecord
        has_one :invoice
        delegate :sales, :to => :invoice, :prefix => false, :allow_nil => true
    end
    

    Then you can both call the invoice method to get the invoice and also call the sales method to get all the sales on the invoice for the ProductSale object.