Rails: ActiveRecord :: HasManyThroughSourceAssociationNotFoundError: Не удалось найти исходную ассоциацию - PullRequest
12 голосов
/ 24 декабря 2011

У меня есть следующий код (несколько упрощенно ...

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 (должно быть: в этом случае карта, как мне кажется).

Есть идеи, что я здесь не так делаю?


Показывает частичное решение, потому что я хотел очистить несколько вещей. Миграция осталась такой же, как и в предыдущей версии. я сейчас увидев ошибку SQL (см. ниже), где он не может найти user_id в подписи. я Ненавижу это говорить, но в основном я добавляю: foreign_key везде, где я думаю они могут помочь безрезультатно.

    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 возвращает пустой массив, как и ожидалось.

Все еще ищите помощь в этом. Мне не удалось найти много простых и простых объяснений этого, когда вы не используете одни и те же имена (т. Е. Вам нужен иностранный ключ и источник.

Ответы [ 2 ]

9 голосов
/ 24 декабря 2011

Пользователь должен быть определен следующим образом:

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

Когда имя вашей ассоциации отличается от имени, используемого в : через , вы должны определить источник параметр.Если вы посмотрите на сообщение об исключении, оно явно попросит вас сделать это.

5 голосов
/ 25 декабря 2011

ОК, так как мне было так тяжело, я хотел показать всем, как выглядит финальная версия.Хорошая часть причины, по которой мне было так тяжело разобраться в этом, заключалась в том, что консоль рельсов, похоже, неправильно загружала вещи, когда я вносил изменения.Я не осознавал этого, пока не отказался от одной ночи, не вернулся на следующее утро, и дело, которое работало прошлой ночью, не было, и дело, которое не работало, было.

Миграция та же, но я повторю ее для полноты картины.

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 есть два own_to с карточкой, которая обычно показывается в примерахи подписывающее лицо типа user.

class Signature < ActiveRecord::Base
    belongs_to :card
    belongs_to :signer, :class_name => "User"
end

Пользователь имеет много подписей (необходимо, даже если вы их не используете напрямую) и dmany signature_cards через подписи с источником карты (сообщающим Rails, какой тип классаподписанные карты:

class User < ActiveRecord::Base
    has_many :signatures, :foreign_key => "signer_id"
    has_many :signed_cards, :through => :signatures, :source => :card 
end

Наконец, на Карте имеется много подписей (еще раз необходимо) и много подписавших через подписи и внешний ключ для подписавшего signer_id.

class Card < ActiveRecord::Base
    has_many :signatures
    has_many :signers, :through => :signatures, :foreign_key => 'signer_id'
end

Надеемся,это поможет другим людям, имеющим схожие проблемы.

...