Rails has_many: через поиск по дополнительным атрибутам в модели соединения

Новичок как в Ruby, так и в Rails, но к настоящему времени я получил книжное образование (что, по-видимому, ничего не значит, ха-ха).

У меня есть две модели: событие и пользователь, объединившиеся через таблицу EventUser.

class User < ActiveRecord::Base
  has_many :event_users
  has_many :events, :through => :event_users
end

class EventUser < ActiveRecord::Base
  belongs_to :event
  belongs_to :user

  #For clarity's sake, EventUser also has a boolean column "active", among others
end

class Event < ActiveRecord::Base
  has_many :event_users
  has_many :users, :through => :event_users
end

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

u = User.find :first
active_events = u.events.find_by_active(true)

Поскольку события на самом деле НЕ ИМЕЮТ этих дополнительных данных, модель EventUser имеет. И пока я мог сделать:

u = User.find :first
active_events = []
u.event_users.find_by_active(true).do |eu|
  active_events << eu.event
end

Это как бы противоречит «рельсовому пути». Может ли кто-нибудь просветить меня, это уже давно меня беспокоит сегодня вечером (сегодня утром)?

Вы также можете создать именованную область, используя предложение Гарета.

arjun 08.01.2009 17:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
70
1
32 373
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Как насчет того, чтобы добавить что-то подобное в вашу модель User?

has_many  :active_events, :through => :event_users, 
          :class_name => "Event", 
          :source => :event, 
          :conditions => ['event_users.active = ?',true]

После этого вы сможете получать активные события для пользователя, просто позвонив:

User.first.active_events

Я пометил вас, но если я не получу лучшего ответа к утру, то он ваш.

Stefan Mai 03.01.2009 14:21

См. Мой ответ ниже, чтобы узнать о более актуальном методе.

msanteler 02.04.2014 17:42

Спасибо, Rails 4 способ: -> { where event_users: { active: true } }

Ivan Black 22.04.2014 21:03

Но нет ли шанса, что условие будет определяться прицелом event_users? Нравится scope :active, where(:active => true)? (с использованием Rails 3.2)

Augustin Riedinger 27.05.2014 17:34

@IvanBlack, не могли бы вы объяснить, как это вписывается в has_many through:? Не могли бы вы включить полный эквивалент Rails 4?

Damien Roche 02.06.2014 14:11

@DamienRoche, ->{where...} вместо :conditions. полная версия

Ivan Black 02.06.2014 22:34

Даже если ваш u.events не является явно, вызывающим таблицу user_events, эта таблица по-прежнему включена в SQL неявно из-за необходимых объединений. Итак, вы все еще можете использовать эту таблицу в своих условиях поиска:

u.events.find(:all, :conditions => ["user_events.active = ?", true])

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

Мне нравится определять все области видимости в одном месте - в модели, даже если я использую их только один раз. Благодаря этому мои контроллеры остаются тонкими, а общий дизайн - более согласованным.

Milan Novota 03.01.2009 23:02

У Milan Novota есть хорошее решение, но :conditions теперь устарел, а бит :conditions => ['event_users.active = ?',true] в любом случае не кажется очень рельсовым. Я предпочитаю что-то вроде этого:

has_many :event_users
has_many :active_event_users, -> { where active: true }, class_name: 'EventUser'
has_many :active_events, :through => :active_event_users, class_name: 'Event', :source => :event

После этого вы все равно сможете получать активные события для пользователя, просто позвонив:

User.first.active_events

Если вы еще не используете Rails 4, вы все равно можете следовать этому отличному примеру, но вам может потребоваться использовать устаревший :conditions => {active: true}. Сработало у меня, спасибо!

monozok 07.04.2014 22:17

Что ж, на модель User возлагается больше ответственности, чем на самом деле нужно, и для этого нет веских причин.

Сначала мы можем определить область видимости в модели EventUser, потому что ее место на самом деле, например:

class EventUser < ActiveRecord::Base
  belongs_to :event
  belongs_to :user

  scope :active,   -> { where(active: true)  }
  scope :inactive, -> { where(active: false) } 
end

Теперь у пользователя могут быть события обоих типов: активные и неактивные, поэтому мы можем определить отношения в модели User следующим образом:

class User < ActiveRecord::Base
  has_many :active_event_users,   -> { active },   class_name: "EventUser"
  has_many :inactive_event_users, -> { inactive }, class_name: "EventUser"

  has_many :inactive_events, through: :inactive_event_user,
                             class_name: "Event",
                             source: :event
  has_many :active_events,   through: :active_event_users,
                             class_name: "Event",
                             source: :event
end

Красота этой техники заключается в том, что функция активного или неактивного события принадлежит модели EventUser, и если в будущем функциональность потребуется изменить, она будет изменена только в одном месте: модель EventUser, и изменения будут отражено во всех остальных моделях.

ваше решение сделало мой день :)

Bilal Maqsood 10.11.2016 19:08

Другие вопросы по теме