#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_votes5. и у меня есть
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