问题
I have the following code (somewhat simplified ...
create_table :signatures do |t|
t.integer :signer_id
t.integer :card_id
t.timestamps
end
With the models looking like ...
class Signature < ActiveRecord::Base
belongs_to :card
belongs_to :user
end
class Card < ActiveRecord::Base
has_many :signatures
has_many :signers, :through => :signatures, :foreign_key => "card_id"
end
class User < ActiveRecord::Base
has_many :sent_cards, :class_name => "Card", :foreign_key => "sender_id"
has_many :received_cards, :class_name => "Card", :foreign_key => "recipient_id"
has_many :signatures
has_many :signed_cards, :through => :signatures, :foreign_key => "signer_id"
end
I see the following error using the rails console ...
ruby-1.9.2-p0 > u15.signed_cards
ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not find the source association(s) :signed_card or :signed_cards in model Signature. Try 'has_many :signed_cards, :through => :signatures, :source => <name>'. Is it one of :card or :user?
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.1.0/lib/active_record/reflection.rb:517:in `check_validity!'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.1.0/lib/active_record/associations/association.rb:27:in `initialize'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.1.0/lib/active_record/associations/collection_association.rb:24:in `initialize'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.1.0/lib/active_record/associations.rb:164:in `new'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.1.0/lib/active_record/associations.rb:164:in `association'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.1.0/lib/active_record/associations/builder/association.rb:41:in `block in define_readers'
from (irb):11
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/railties-3.1.0/lib/rails/commands/console.rb:45:in `start'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/railties-3.1.0/lib/rails/commands/console.rb:8:in `start'
from /home/slabounty/.rvm/gems/ruby-1.9.2-p0/gems/railties-3.1.0/lib/rails/commands.rb:40:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
I get the same thing when I do add the source => :card/:user
(should be :card in this case I believe).
Any ideas what I'm doing wrong here?
Showing a partial solution because I wanted to clean up a few things. The migration remained the same as the previous version. I'm now seeing a SQL error (see below) where it can't find user_id in Signature. I hate to say it, but mostly I've been putting in :foreign_key whereever I think they might help to no avail.
class Signature < ActiveRecord::Base
belongs_to :card
belongs_to :signer, :class_name => "User"
end
class Card < ActiveRecord::Base
# Correct
has_many :signatures
has_many :signers, :through => :signatures, :source => :user
end
class User < ActiveRecord::Base
# Wrong!
has_many :signatures, :foreign_key => "signer_id"
has_many :signed_cards, :through => :signatures, :source => :card
end
With the error (minus stack trace)
ruby-1.9.2-p0 > u15.signed_cards
Card Load (0.5ms) SELECT "cards".* FROM "cards" INNER JOIN "signatures" ON "cards"."id" = "signatures"."card_id" WHERE "signatures"."user_id" = 15 ORDER BY cards.created_at DESC
SQLite3::SQLException: no such column: signatures.user_id: SELECT "cards".* FROM "cards" INNER JOIN "signatures" ON "cards"."id" = "signatures"."card_id" WHERE "signatures"."user_id" = 15 ORDER BY cards.created_at DESC
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: signatures.user_id: SELECT "cards".* FROM "cards" INNER JOIN "signatures" ON "cards"."id" = "signatures"."card_id" WHERE "signatures"."user_id" = 15 ORDER BY cards.created_at DESC
Card.signers
returns an empty array as expected.
Still looking for some help on this one. I haven't been able to locate much in the way of simple, straightforward explanations of this where you're not using the same names (i.e. you need a foreign_key and source.
回答1:
User should be defined like this:
class User < ActiveRecord::Base
has_many :sent_cards, :class_name => "Card", :foreign_key => "sender_id"
has_many :received_cards, :class_name => "Card", :foreign_key => "recipient_id"
has_many :signatures
has_many :signed_cards, :through => :signatures, :source => :card
end
When your association name is different than the name used at the :through you have to define the source parameter. If you look at the exception message it explicitly asks you to do it.
回答2:
OK, since I had such a hard time with this, I wanted to show everyone what the final version looked like. A good part of the reason I had such a hard time firguring this out, was the fact that the rails console didn't seem to be reloading things correctly as I made changes. I didn't realize this until I gave up one night, came back the next morning and the case that had been working the previous night wasn't and the case that wasn't working was.
The migration is the same, but I'll repeat it for completeness sake.
def change
create_table :signatures do |t|
t.integer :signer_id
t.integer :card_id
t.boolean :signed, :default => false
t.text :message
t.timestamps
end
end
The Signature class has the two belongs_to with card being the case that normally gets shown in the examples and the signer being of type user.
class Signature < ActiveRecord::Base
belongs_to :card
belongs_to :signer, :class_name => "User"
end
The User has many signatures (necessary even if you don't use them directly) an dmany signed_cards through signatures with a source of card (telling Rails which class type the signed_cards are.
class User < ActiveRecord::Base
has_many :signatures, :foreign_key => "signer_id"
has_many :signed_cards, :through => :signatures, :source => :card
end
Finally, the Card has many signatures (once again necessary) and many signers through signatures and the foreign_key for the signer of signer_id.
class Card < ActiveRecord::Base
has_many :signatures
has_many :signers, :through => :signatures, :foreign_key => 'signer_id'
end
Hopefully, this will help others having similar issues.
来源:https://stackoverflow.com/questions/8621630/rails-activerecordhasmanythroughsourceassociationnotfounderror-could-not-fin