Имеет много сквозных ассоциаций с условиями

#ruby-on-rails #ruby #ruby-on-rails-3

#ruby-on-rails #ruby #ruby-on-rails-3

Вопрос:

Я пытаюсь добавить условие к тому, что имеет много сквозных ассоциаций, но безуспешно. Это ассоциация в моей видеомодели:

 has_many :voted_users, :through => :video_votes, :source => :user
  

Я хочу получить только те voted_users , чьи video_votes имеют value значение, равное 1 для этого видео. Как бы я это сделал?

Комментарии:

1. Это votes ассоциация или это имя поля?

2. означает ли ‘чьи голоса имеют значение, равное 1.’ то же самое, что и ‘которые проголосовали только один раз’?

3. Адам, да, я думаю, мы надеемся также увидеть: has_many:video_votes

4. извините… votes я имел в виду video_votes , value это поле в таблице video_votes

5. и у меня есть has_many :video_votes

Ответ №1:

Я бы предложил создать метод модели в классе video model что-то вроде:

 def users_with_one_vote
  self.voted_users, :conditions => ['value = ?', 1]
end
  

Затем в контроллере используйте video.users_with_one_vote

Тогда тестирование тоже проще.

Есть ли шанс, что вы можете изменить это имя столбца на ‘value’. Может вызвать некоторые проблемы (зарезервировано?).

Комментарии:

1. Будет ли это работать, учитывая value , что это поле в таблице video_votes, а не в таблице user…

2. Я не думаю, что значение зарезервировано … значение представляет, является ли оно повышающим или понижающим

3. Это не сработает (я думаю). Разве вам не нужно иметь какой-то запрос, например self.voted_users.all(:conditions => "video_votes.value = '1'") ?

4. для . возможно, все. Но я считаю, что простое использование имени модели во множественном числе может работать, поскольку rails использует соглашение о множественном числе для всех. Я думаю, что у меня есть правильные условия?

Ответ №2:

Я бы сделал это в 2 этапа:

Во-первых, я бы определил has_many :through взаимосвязь между моделями без каких-либо условий.

Во-вторых, я бы добавил «область видимости», которая определяет условие where.

В частности, я бы сделал что-то вроде:

 class User < ActiveRecord::Base
  has_many :video_votes
  has_many :votes, :through=>:video_votes
  def self.voted_users
    self.video_votes.voted
  end
end

class VideoVote
  def self.voted
    where("value = ?", 1)
  end
end

class Video
  has_many :video_votes
  has_many :users, :through=>:video_votes
end
  

Тогда вы могли бы получить пользователей, которые проголосовали, используя:

 VideoVote.voted.collect(amp;:user).uniq
  

что, я полагаю, вернет массив всех проголосовавших пользователей. Это не тот код, который вы бы использовали — это просто фрагменты, но идея та же.

Ответ №3:

Было бы

 has_many :voted_users, :through => :video_votes, :source => :user, :conditions => ['users.votes = ?', 1]
  

Сделать трюк?

Комментарии:

1. нет, я не думаю, что включение этого условия в базовое соединение — хорошая идея.

2. Хотите поделиться больше? Я не могу сказать, что согласен, хотя я не понимаю, почему это было бы плохой идеей.

3. Я думаю, что базовое соединение, как показано, — это то, которое всегда должно быть там, независимо от этого «количества», которое было бы лучше обработано методом модели.

4. @Michael: Я не понимаю, почему это плохая идея или почему она была отклонена.

5. Райан — потому что, как отмечали другие постеры, он сочетает в себе две разные вещи.

Ответ №4:

Я обнаружил, что определение этого метода в моей модели работает:

 def upvoted_users
  self.voted_users.where("value = 1")
end
  

и затем вызов @video.upvoted_users делает свое дело.

Ответ №5:

Лучший способ сделать это, не вмешиваясь в отношения, — создать более сложный запрос. Отношения — не лучшее, что можно использовать для этой конкретной проблемы. Пожалуйста, поймите, что отношения — это скорее «способ определения данных», чем способ «определения правил ведения бизнеса».

Логика бизнеса или правила бизнеса должны быть определены на более конкретном уровне.

Мое предложение для вашей проблемы — создать метод поиска пользователей, которые проголосовали за ваше видео только один раз. что-то вроде:

 class Video < ActiveRecord::Base

  def voted_once()
    User.joins(:video_votes).where("video_votes.value == 1 AND video_votes.video_id == ?", this.id)
  end
  

Rails волшебен для многих вещей, но сложные запросы все равно должны выполняться в стиле «SQL». Не позволяйте иллюзорной объектно-ориентированной метафоре ослепить вас

Ответ №6:

Пока мы разбрасываемся идеями, как насчет использования расширений ассоциаций.

 class VideoVote
  scope :upvotes, where(:value => 1)
end

class Video
  has_many :voted_users, :through => :video_votes, :source => :user do
    def upvoted
      scoped amp; VideoVote.upvotes
    end
  end
end
  

Тогда вы чувствуете себя хорошо, делая вызов абсолютно без аргументов, И вы технически не добавили другой метод в свою видеомодель (это связано с ассоциацией, верно?)

 @video.voted_users.upvoted