2013-06-30 3 views
4

Я хочу моделировать такую ​​взаимосвязь между моделями User и Event.Множественный охват has_many через отношения в Rails 4

Поэтому я начал со следующими классами:

class User < ActiveRecord::Base 
... 
end 

class Attendance < ActiveRecord::Base 
# with columns user_id and event_id 
... 
end 

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

До сих пор все в порядке: я могу назначить пользователей и посещаемости доступа. Но теперь я хочу привести государство в игру, чтобы я мог различать, например. между «посещением», «отсутствием отсутствия», ... пользователями. Моя первая попытка была:

class Event < ActiveRecord::Base 
    has_many :attendances 
    has_many :users, :through => :attendances 
    has_many :unexcused_absent_users, -> { where :state => 'unexcused' }, 
            :through => :attendances, 
            :source => :user 
    ... 
end 

(: источник должен быть указан, так как в противном случае он будет искать а принадлежит ассоциации под названием «unexcused_absent_users») Проблема здесь в том, что где-предикат оценивается по таблице " пользователи.

Я не знаю, как решить эту проблему «правильно», не вводя новые таблицы/модели соединений для каждого состояния. Тем более, что каждый пользователь может быть как раз в одном состоянии для каждого события, я думаю, что решение с одной моделью Attendance имеет смысл.

У вас есть идея, как это сделать правильно?

ответ

1

Я нашел обходное решение, но я все еще думаю, что это уродливо.

class Event < ActiveRecord::Base 
    has_many :user_attendances, :class_name => 'Attendance' 
    has_many :users, :through => :user_attendances, :source => :user 

    has_many :unexcued_absent_user_attendances, -> { where :state => 'unexcused'}, :class_name => 'Attendance' 
    has_many :unexcused_absent_users, :through => :unexcued_absent_user_attendances, :source => :user 
end 

В общем: Для каждого государства, которое я хочу, я должен ввести новый has_many отношения с областью и на вершине, что и по has_many-через отношения.

+0

Я столкнулся с очень похожими проблемами и с тех пор зарегистрировал проблему в проекте Rails (https://github.com/rails/rails/issues/10945). Я не на 100% уверен, что это настоящая проблема или ошибка пользователя с моей стороны, но я закончил тем же способом, что и вы. Используя этот обходной путь, я столкнулся с некоторыми странными вещами. Например, я бы поспорил, что делал что-то вроде этого: 'Event.create! (Title: 'foo', unexcused_absent_user_ids: [1,2,3])' приводит к тому, что атрибут 'state' устанавливается на' nil'. Если вы хотите поднять мою проблему на github или получить дополнительную информацию о своем подходе, я бы хотел ее услышать. –

+0

Я забыл упомянуть, что я использовал этот пример создания «Event», потому что я думаю, что он очень похож на то, что «EventController # create» может получать как POST со страницы, где пользователь добавляет событие и одновременно помещает людей, которые неисключенные. (т. е. как набор флажков с именами учеников) –

1

это может сработать для вас?

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

    def unexcused_absent_users 
    User.joins(:attendances) 
     .where(:state => 'unexcused') 
     .where(:event_id => self.id) 
    end 
end 

в рельсах 3+ методы в основном такие же, как и областей, просто менее запутанным (на мой взгляд), они цепной

event = Event.find(xxxx) 
event.unexcused_absent_users.where("name LIKE ?", "Smi%") 
+0

Это имеет недостаток, что это невозможно для записи.И добавление другого метода 'unexcused_abent_users = array' не так, как мне кажется,« railsy »: \ – contradictioned

+0

метод' unexcused_abent_users' выше возвращает объект 'ActiveRelation', а не массив; наличие коллекции «stateful» для записи может показаться мне не лучшей идеей? вы можете использовать определенные методы для изменения состояния, то есть 'event.absent_but_not_excused! (user)' или 'user.not_excused_from (event)' - предположим, что это сводится к личным предпочтениям – house9

3

Вы можете просто сузить область, чтобы посмотреть на правильную таблицу :

has_many :unexcused_absent_users, -> { where(attendances: {state: 'unexcused'}) }, 
           :through => :attendances, 
           :source => :user 

Evem лучше, добавьте эту область модели посещаемости и объединить его в:

class Attendance < ActiveRecord::Base 
    def self.unexcused 
    where state: 'unexcused' 
    end 
end 

class Event < ActiveRecord::Base 
    has_many :unexcused_absent_users, -> { merge(Attendance.unexcused) }, 
           :through => :attendances, 
           :source => :user  
end 
+0

Использование слияния с именованным методом в классе 'Attendance' чистый. К сожалению, это не сработает. В классе 'Event' отсутствует ассоциация с именем' attendances', и по какой-то причине ассоциация будет только для чтения. Я понятия не имею, почему, но при сохранении через него «состояние», установленное в области, теряется/игнорируется/ноль. –

+0

@MarioZigliotto: «В классе Event отсутствует ассоциация с именем посещаемости ...» - OP записал в исходном коде, что 'Event' содержит строку' has_many: attendances'. Можете ли вы объяснить, что вы имеете в виду? В решении, заданном OP, он ссылается на ': user_attendances' - возможно, имя ассоциации было изменено? – PinnyM

Смежные вопросы