アソシエーションによるbelongs_to


141

以下の関連付けを前提として、Questiona ChoiceChoiceモデルから接続されていることを参照する必要があります。を使用belongs_to :question, through: :answerしてこのアクションを実行しようとしています。

class User
  has_many :questions
  has_many :choices
end

class Question
  belongs_to :user
  has_many :answers
  has_one :choice, :through => :answer
end

class Answer
  belongs_to :question
end

class Choice
  belongs_to :user
  belongs_to :answer
  belongs_to :question, :through => :answer

  validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
end

私は得ています

NameError初期化されていない定数 User::Choice

私がやろうとしたとき current_user.choices

含めない場合、それは正常に動作します

belongs_to :question, :through => :answer

しかし、私はできるようになりたいのでそれを使いたいです validates_uniqueness_of

私はおそらく単純なものを見落としているでしょう。任意の助けいただければ幸いです。


1
受理された回答を委任者の回答に変更する価値はあるでしょうか?
23inhouse

回答:


60

belongs_to関連は持つことができない:throughオプションを選択します。あなたはキャッシング方がいいでしょうquestion_idChoice(特にので、テーブルに一意のインデックスを追加するvalidates_uniqueness_of競合状態になりやすいです)。

偏執狂の場合はChoice、回答のquestion_id一致を確認するカスタム検証を追加しますが、この種の不一致を引き起こすデータを送信する機会をエンドユーザーに与えてはならないようです。


Stephenに感謝します。question_idと直接関連付ける必要は本当にありませんでしたが、最も簡単な方法だと思います。「答え」は「問い」に属しているので、いつでも「答え」をたどって「問い」にたどり着くことが当初の考えでした。しかし、それは簡単ではないと思いますか、それとも単に悪いスキーマだと思いますか?
vinhboy

一意の制約/検証が必要な場合は、スコープフィールドが同じテーブルに存在する必要があります。競合状態があることに注意してください。
stephencelis

1
>>エンドユーザーには、この種の不一致を引き起こすデータを送信する機会を与えてはならないようです。-サーバー側で明示的にチェックしない限り、ユーザーが「何かをする機会がない」ことを保証することはできません。
コンスタンティン

376

委任することもできます。

class Company < ActiveRecord::Base
  has_many :employees
  has_many :dogs, :through => :employees
end

class Employee < ActiveRescord::Base
  belongs_to :company
  has_many :dogs
end

class Dog < ActiveRecord::Base
  belongs_to :employee

  delegate :company, :to => :employee, :allow_nil => true
end

27
+1、これはこれを行う最もクリーンな方法です。(少なくとも私が考えることができること)
オーランド

9
JOINでこれを実行して、あまり多くのクエリを使用しないようにする方法はありますか?
Tallboy 2013年

1
自分のことを知りたいのですが。私が試したすべてが3つの選択を解雇しました。関連付けに "-> {joins:something}"ラムダを指定できます。結合が発生しますが、その後別の選択がとにかく発生します。これを調整することができませんでした。
Renra 2013年

2
@Tallboy主キーに対する完全にインデックス化されたいくつかの選択クエリは、ほとんどの場合、単一のJOINクエリよりも優れています。結合により、データベースが正常に動作します。
Ryan McGeary 14

1
allow_nilは何をしますか?従業員は常に会社を持つべきではありませんか?
aaron-coding 2014

115

次のようhas_oneに、の代わりにを使用belongs_toしてください:through

class Choice
  belongs_to :user
  belongs_to :answer
  has_one :question, :through => :answer
end

無関係ですが、データベースで適切な一意制約を使用するのではなく、validates_uniqueness_ofを使用するのをためらいます。ルビでこれを行うと、競合状態になります。


38
このソリューションに関する大きな警告。を保存すると、autosave: falseが設定されていない限り、常にQuestionが保存されます。
Chris Nicola、

@ChrisNicolaあなたが何を意味しているか説明してもらえますか、私はあなたが何を意味しているのか理解できませんでした。
18年

私はどこを意味しましたか?適切な一意性制約を意味する場合は、データベース内で一意でなければならないUNIQUEインデックスを列/フィールドに追加することを意味します。
Chris Nicola

4

私のアプローチは、データベース列を追加する代わりに仮想属性を作成することでした。

class Choice
  belongs_to :user
  belongs_to :answer

  # ------- Helpers -------
  def question
    answer.question
  end

  # extra sugar
  def question_id
    answer.question_id
  end
end

このアプローチは非常に単純ですが、トレードオフが伴います。Railsがanswerdb からロードする必要がありますquestion。これは、必要な関連付け(つまりc = Choice.first(include: {answer: :question}))を積極的にロードすることで後で最適化できますが、この最適化が必要な場合は、おそらくstephencelisの答えがパフォーマンスの決定に適しています。

特定の選択には時間と場所があり、プロトタイプを作成するときはこの選択の方が良いと思います。まれなユースケースであることを知らない限り、本番コードには使用しません。


1

あなたが欲しいのは、多くの質問を持つユーザーです。
質問には多くの回答があり、そのうちの1つはユーザーの選択です。

これはあなたが求めているものですか?

私はこれらの線に沿ってそのようなものをモデル化します:

class User
  has_many :questions
end

class Question
  belongs_to :user
  has_many   :answers
  has_one    :choice, :class_name => "Answer"

  validates_inclusion_of :choice, :in => lambda { answers }
end

class Answer
  belongs_to :question
end

1

したがって、あなたはあなたが望む振る舞いを持つことはできませんが、あなたはそれのように感じる何かをすることができます。できるようになりたいChoice.first.question

私が過去にやったことはこのようなものです

class Choice
  belongs_to :user
  belongs_to :answer
  validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
  ...
  def question
    answer.question
  end
end

このようにして、Choiceで質問を呼び出すことができます


-1

has_many :choices名前の関連を作成choices、ありませんchoicecurrent_user.choices代わりに使用してみてください。

マジックの詳細については、ActiveRecord :: Associationsのドキュメントを参照してくださいhas_many


1
あなたの助けをありがとうマイケル、しかし、それは私の側のタイプミスです。私はすでにcurrent_user.choicesをやっています。このエラーは、ユーザーと質問にbelongs_toを割り当てたいと思っています。
vinhboy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.