принадлежит_ через ассоциации - PullRequest
125 голосов
/ 26 октября 2010

Учитывая следующие ассоциации, мне нужно сослаться на Question, к которому Choice присоединен из модели Choice Я пытался использовать 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

Я, наверное, упускаю из виду что-то простое. Любая помощь будет оценена.

Ответы [ 7 ]

341 голосов
/ 12 июля 2012

Вы также можете делегировать:

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
97 голосов
/ 27 марта 2013

Просто используйте has_one вместо belongs_to в вашем :though, например:

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

Не имеет отношения, но я бы не решился использовать validates_uniqueness_of вместо использования правильного уникального ограничения в вашей базе данных. Когда вы делаете это в рубине, у вас есть условия гонки.

57 голосов
/ 27 октября 2010
Ассоциация

A belongs_to не может иметь опцию :through.Вам лучше кэшировать question_id на Choice и добавлять уникальный индекс в таблицу (особенно потому, что validates_uniqueness_of подвержен условиям гонки).

Если вы параноик, добавьте пользовательскийпроверка на Choice, которая подтверждает, что ответ question_id совпадает, но похоже, что конечному пользователю никогда не должна быть предоставлена ​​возможность представить данные, которые могут привести к этому несоответствию.

4 голосов
/ 10 февраля 2012

Мой подход заключался в создании виртуального атрибута вместо добавления столбцов базы данных.

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 загрузил answer из БД, а затем question. Позже это можно оптимизировать, если загружать нужные вам ассоциации (т. Е. c = Choice.first(include: {answer: :question})), однако, если такая оптимизация необходима, то ответ Стефенселиса, вероятно, является лучшим решением для повышения производительности.

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

1 голос
/ 07 июня 2017

Таким образом, вы не можете вести себя так, как вам хочется, но вы можете делать что-то вроде этого.Вы хотите, чтобы вы могли 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

, так что теперь вы можете вызывать вопрос на Выбор

1 голос
/ 27 октября 2010

Звучит так, будто вы хотите, чтобы у пользователя было много вопросов.
На вопрос есть много ответов, один из которых - выбор пользователя.

Это то, что вы после?

Я бы смоделировал что-то подобное этому:

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
0 голосов
/ 27 октября 2010

has_many :choices создает ассоциацию с именем choices, а не choice. Попробуйте использовать current_user.choices.

Информацию о магии has_many см. В документации ActiveRecord :: Associations .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...