views:

314

answers:

2

I have an invoicing system that manages debits and credits. Basically the invoice amount is obtained by the sum of its debits and the balance is derived by taking the sum of its credits and subtracting it against the total amount.

I'm doing this with four models.

  1. Invoice
  2. Line Item
  3. Debit
  4. Credit

The way it works is via a join model (Line Item) that has a polymorphic association called recordable. Everything appears to work properly at first glance. However, inspecting the line item shows that while the recordable_id shows up alright, the recordable_type is nil.

Here is a break down of the code:

class Invoice < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
  has_many :debits, :through => :line_items, :as => :recordable
  has_many :credits, :through => :line_items, :as => :recordable
end

class LineItem < ActiveRecord::Base
  belongs_to :invoice
  belongs_to :recordable, :polymorphic => true
  belongs_to :credit, :class_name => "Credit", :foreign_key => "recordable_id"
  belongs_to :debit,  :class_name => "Debit",   :foreign_key => "recordable_id"
end

class Credit < ActiveRecord::Base
  has_many :line_items, :as => :recordable, :dependent => :destroy
end

class Debit < ActiveRecord::Base
  has_many :line_items, :as => :recordable, :dependent => :destroy
end

Can anyone point me into the right direction here?

A: 

Hi Jim.

Invoice.last.credits << Credit.new

This is the correct way in assigning associations to I am stumped as to why the recordable_type is not being picked up.

Clutching at straws here but have you tried:

Invoice.last.credits << Credit.create(:value => 1, :date => Time.now, ...)

I've personally had issues when using multi-type many-to-many join tables in Rails, which was often resolved by using the has_many_polymorphs plugin.

Sorry that this does not directly answer your question.

Nazar
Yeah I ended up just creating a direct relationship as the behavior of the application no longer needed the many to many relationship of invoices to debits. I'm not sure why it's not picking it up either though. I have done the same exact setup for different objects in the past. Maybe I've stumbled onto a protected name but I can't think of it. Originally I was using item_id and item_type but even after changing to recordable_id and type it still didn't work. Completely stumped.
Jim Jeffers
A: 

You are declaring ambigous associations on your LineItem class.

In a nutshell, belongs_to does this in your class:

  1. belongs_to :invoice creates a method invoice which searches the invoices table for a record referenced by invoice_id
  2. belongs_to :recordable, :polymorphic => true creates a method recordable which searches the recordable_type.underscore.pluralize table for a record referenced by recordable_id
  3. belongs_to :credit, :class_name => "Credit", :foreign_key => "recordable_id" creates a method credit which searches through through the credits table for a record referenced by recordable_id. Note, that recordable_type is ignored here.
  4. same applies to belongs_to :debit respectively.

Since your LineItem may only belong to either a Credit or a Debit it makes no sense to declare these associations additionally. You can refer to these via the recordable association.

mikezter