Reputation: 781
I'm trying to set up a system where my Billing Profile can hold an Address and Payment Method through a User. With addresses, it works fine since User only has one but with Payment Method, since User has_many, I keep getting the error:
ActiveRecord::HasManyThroughSourceAssociationNotFoundError:
Could not find the source association(s) :payment_method_id in model User.
Try 'has_many :payment_method, :through => :user, :source => <name>'.
Is it one of :address, :billing_profile, or :payment_methods?**
BillingProfile
class BillingProfile < ActiveRecord::Base
attr_accessible :user, :payment_method
belongs_to :user
has_one :address, :through => :user
has_one :payment_method, :through => :user
end
User
class User < ActiveRecord::Base
...
has_one :billing_profile
has_many :payment_methods
has_one :address, :as => :addressable
accepts_nested_attributes_for :address
end
Address
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
attr_accessible :city, :country, :state, :street_line_1, :street_line_2, :zip_code
end
PaymentMethod
class PaymentMethod < ActiveRecord::Base
attr_accessible :user_id, :is_default
belongs_to :user
validates_presence_of :user_id
end
BillingProfile Table
create_table :billing_profiles do |t|
t.integer :user_id
t.integer :payment_method_id
t.timestamps
end
Any idea how if this is even possible or if there is a better way to approach it? I have dabbled in the idea of just manually setting the id's when I create the Billing Profile but then I'd have to create methods to get the payment method which is not terrible but it'd be nice if Rails was able to do it for me.
EDIT
So since it appears that what I hoped for is not possible. I simple added a method to Billing Profile to simulate the association.
def payment_method
PaymentMethod.find(payment_method_id)
end
Upvotes: 0
Views: 130
Reputation: 20106
The :through
option is there to link relationships. So, the following hold true:
billing_profile.user.address == biling_profile.address
However, the following can't be true (because you want only one in one side and a list in the other):
billing_profile.user.payment_methods == billing_profile.payment_method
You need an extra column to make this relationship. You can only use the :through
relationship if both returns the same, because there is no "extra memory" to hold only one from a list.
So, in short, you need to add a has_one
or a belong_to
without :trhough
and add a new column (extra memory) to hold this relationship.
Upvotes: 2