Rails: ActiveRecord:: HasManyThroughSourceAssociationNotFoundError: Не удалось найти исходную (-е)
У меня есть следующий код (несколько упрощенный...
create_table :signatures do |t|
t.integer :signer_id
t.integer :card_id
t.timestamps
end
С похожими моделями...
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
Я вижу следующую ошибку, используя консоль rails...
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>'
Я получаю то же самое, когда добавляю source => :card/:user
(должен быть: card в этом случае, я считаю).
Любые идеи, что я делаю неправильно здесь?
Отображение частичного решения, потому что я хотел очистить
несколько вещей. Миграция осталась такой же, как и в предыдущей версии. я сейчас
видя ошибку SQL (см. ниже), где он не может найти user_id в Signature. я
ненавижу это говорить, но в основном я вставляю: foreign_key whereever, я думаю
они могут помочь безрезультатно.
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
С ошибкой (минус трассировка стека)
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
возвращает пустой массив, как ожидалось.
Ищем какую-то помощь в этом вопросе. Я не смог найти много способов простого и простого объяснения этого, когда вы не используете одни и те же имена (т.е. Вам нужна foreign_key и source.
Ответы
Ответ 1
Пользователь должен быть определен следующим образом:
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
Если ваше имя ассоциации отличается от имени, используемого в : через, вам необходимо определить параметр source. Если вы посмотрите сообщение об исключении, оно явно попросит вас сделать это.
Ответ 2
Хорошо, так как мне было так тяжело с этим, я хотел показать всем, что
окончательная версия выглядела. Хорошая часть причины, по которой мне было так тяжело
Это было связано с тем, что консоль рельсов, похоже, не была
правильно перегружая вещи, когда я вносил изменения. Я этого не понимал до тех пор, пока я
отказались от одной ночи, вернулись на следующее утро, и случай, который был
работа предыдущей ночи не была, и дело, которое не работало, было.
Миграция такая же, но я повторю ее ради полноты.
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
Класс Signature имеет два атрибута принадлежность к карте, если
обычно отображается в примерах, а подписывающий пользователь типа.
class Signature < ActiveRecord::Base
belongs_to :card
belongs_to :signer, :class_name => "User"
end
Пользователь имеет много подписей (необходимо, даже если вы не используете их напрямую)
dmany signed_cards через подписи с источником карты (рассказывая Rails
какой тип класса имеет signed_cards.
class User < ActiveRecord::Base
has_many :signatures, :foreign_key => "signer_id"
has_many :signed_cards, :through => :signatures, :source => :card
end
Наконец, у Карты много подписей (еще раз необходимо) и многих подписчиков
через подписи и foreign_key для подписывающего лица signer_id.
class Card < ActiveRecord::Base
has_many :signatures
has_many :signers, :through => :signatures, :foreign_key => 'signer_id'
end
Надеюсь, это поможет другим, имеющим схожие проблемы.