Trilhos has_many: through Encontrar por atributos extras em Junte Modelo
-
03-07-2019 - |
Pergunta
Novo para Ruby e Rails, mas estou livro educado por agora (que, aparentemente, não significa nada, haha).
Eu tenho dois modelos, eventos e usuário se juntou através de uma tabela 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
Este projeto é um calendário, no qual eu tenho que manter o controle de pessoas se inscrever e arranhando seu nome para um determinado evento. Eu acho que a muitos para muitos é uma boa abordagem, mas eu não posso fazer algo como isto:
u = User.find :first
active_events = u.events.find_by_active(true)
Como os eventos não têm realmente que os dados extras, o modelo EventUser faz. E enquanto eu poderia fazer:
u = User.find :first
active_events = []
u.event_users.find_by_active(true).do |eu|
active_events << eu.event
end
Este parece ser contrário à "o caminho trilhos". Alguém pode me esclarecer, este foi me incomodando há muito esta noite (esta manhã) tempo?
Solução
Como sobre a adição de algo como isto em seu modelo de usuário?
has_many :active_events, :through => :event_users,
:class_name => "Event",
:source => :event,
:conditions => ['event_users.active = ?',true]
Depois que você deve ser capaz de obter eventos ativos para um usuário apenas chamando:
User.first.active_events
Outras dicas
Milão Novota tem uma boa solução - mas :conditions
agora está obsoleto e o :conditions => ['event_users.active = ?',true]
mordeu simplesmente não parece muito trilhos de qualquer maneira. Eu prefiro algo como isto:
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
Depois que você ainda deve ser capaz de obter eventos ativos para um usuário apenas chamando:
User.first.active_events
Mesmo que seus u.events não é explicitamente de chamar a mesa de user_events, que a tabela está ainda incluído no SQL implicitamente por causa da necessária junta. Então, você ainda pode usar essa tabela em suas condições de encontrar:
u.events.find(:all, :conditions => ["user_events.active = ?", true])
Claro que, se você pretende fazer essa pesquisa muito, então a certeza, dar-lhe uma associação separada, como Milan Novota sugere, mas não há nenhuma exigência para você fazer isso dessa maneira
Bem, mais responsabilidade está sendo colocado no modelo User
do que realmente necessário, e não há nenhuma boa razão para fazê-lo.
Podemos primeiro definir o escopo no modelo EventUser
porque onde ele realmente pertence, como:
class EventUser < ActiveRecord::Base
belongs_to :event
belongs_to :user
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
end
Agora, um usuário pode ter ambos os tipos de eventos: eventos ativos, bem como eventos inativos, assim podemos definir a relação no modelo User
da seguinte forma:
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
A beleza desta técnica é que a funcionalidade de ser um ativo ou um evento inativa pertence a modelo EventUser
, e se, no futuro, a funcionalidade tem de ser modificado, seria modificado apenas em um lugar: Modelo EventUser
, eo alterações serão refletidas em todos os outros modelos.