ruby-on-rails - tutorial - rails has_one through



Rails:ActiveRecord:: HasManyThroughSourceAssociationNotFoundError:ソースの関連付けが見つかりませんでした (2)

OK、これで苦労したので、最終版がどのようなものかをみんなに見せたいと思いました。 私がこれを解決するのにとても苦労した理由の大部分は、私が変更を加えたときにレールコンソールが物事を正しくリロードしていないようだったという事実でした。 私は私がある夜をあきらめ、翌朝戻って来、そして前の夜に働いていた事件がうまくいかなかった事件がそうでなかった事件ではないまで私はこれに気づかなかった。

移行は同じですが、完全を期すために繰り返します。

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クラスは2つのbelongs_toを持っています。cardは例で普通に見られるケースで、署名者はuserタイプです。

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

Userは多くの署名を持っています(直接使わなくても必要です)dmany signed_cardsとcardのソースを持つ署名(signed_cardsがどのクラス型かをRailsに伝えます)。

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

最後に、このカードには多くの署名があり(これもまた必要です)、署名とsigner_idの署名者のforeign_keyによる署名者が多数います。

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

うまくいけば、これは他の人が同様の問題を抱えているのに役立ちます。

https://ffff65535.com

私は次のようなコードを持っています(多少単純化されています...

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

レールコンソールを使用していると、次のようなエラーメッセージが表示されます。

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追加しても同じことが言えsource => :card/:user (この場合はcardにすべきです)。

ここで私が間違っていることについて何か考えはありますか?

私はいくつかのことを片付けたいので、部分的な解決策を示しています。 移行は以前のバージョンと同じままでした。 署名でuser_idが見つからないというSQLエラー(下記参照)が発生しています。 私はそれを言うのは嫌いですが、ほとんどの場合私は次のものを入れています: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は予想通り空の配列を返します。

まだこれについて何か手助けを探しています。 私はあなたが同じ名前を使っていないところでこれについての単純で直接的な説明の方法で多くを見つけることができませんでした(すなわち、foreign_keyとsourceが必要です)。


ユーザーはこのように定義されるべきです:

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パラメータを定義する必要があります。 あなたが例外メッセージを見ればそれはそれをするようにあなたに明白に頼みます。





has-many-through