hackrnaut
hackrnaut

Reputation: 583

Querying From :through Association

I am creating a rails app to learn has_many :through associations... I know I didn't follow rails conventions, but that's because I want to learn all the different options Active Record has to offer.

My problem is, I think I have the relationships created, but I have no idea how to build invites and query them to get attendees, and attended_events. Do I have to create an invite first? If so, how do I associate it with an event? Then, how do I make it so that many users can attend the event? These questions may be pretty obvious for some of you, but I'm having trouble wrapping my head around it. Would anyone be kind enough to give me a basic run down? Did I even set up my code correctly to get the results I want? Here is my set up so far:

class Invite < ActiveRecord::Base
    belongs_to :attending_guest, :class_name => "User"
    belongs_to :attending_event, :class_name => "Event"
end

class User < ActiveRecord::Base
    has_many :created_events, :foreign_key => "creator_id", :class_name => "Event"
    has_many :invites, :foreign_key => :attending_guest_id
    has_many :attended_events, through: :invites, source: :attending_event
end

class Event < ActiveRecord::Base
    belongs_to :creator, :class_name => "User"
    has_many :invites, :foreign_key => :attending_event_id
    has_many :attendees, :through => :invites, :source => :attending_guest
end

Basically, an event has a creator, I think I have done that part correctly. Next, I want to be able to get a list of users that are attending the event. Also, I want to be able to see what events a user is going to. But how do I even build an invite and have one event be associated with a bunch of users, how does rails handle this? If anyone can please explain how I can go about doing these things and just give me some clarifications/tips, I would greatly appreciate it. Thanks you!

Upvotes: 3

Views: 67

Answers (2)

Brozorec
Brozorec

Reputation: 1183

Using belongs_to, has_many etc. puts at your disposal some very handy methods for associating objects between each other. For example belongs_to comes with:

 1. association
 2. association=(associate)  
 3. build_association(attributes = {})
 4. create_association(attributes = {})
 5. create_association!(attributes = {})

So far your question is how to build invites and have them associated with events and users, here's my suggestion:

Since in model Invite you define 2 associations by using belongs_to, you can use method No.5 of the above list as follows:

invite = Invite.create!
invite.create_attending_guest!(<the necessary attributes and respective values for creating a new user>)
invite.create_attending_event!(<the necessary attributes and respective values for creating a new event>)

or the other way around:

guest = User.create!(<attrs>)
event = Event.create!(<attrs>)
invite = Invite.create!(attending_guest: guest, attending_event: event)

I want to be able to see what events a user is going to

You can access them just like this:

u = User.find(5)
events = u.attended_events

how do I have one event be associated with a bunch of users

In this case you can use the method << added by has_many (see here for the others):

u1 = User.create!(<attrs>)
u2 = User.create!(<attrs>)
u3 = User.create!(<attrs>)
event = Event.create!(<attrs>)
event.attendees << u1
event.attendees << u2
event.attendees << u3

Upvotes: 1

Marcin Bilski
Marcin Bilski

Reputation: 611

Are you able to create an instance of each ActiveModel individually and save it? Make sure you got the foreign keys right.

Provided the relations etc. are correct, I believe the (pseudo-) code should look like this:

creator = User.where(...
event = Event.new
event.save! # You need to save before adding to association
user = User.where(...
user.invites.create!(creator_id: creator) 

This should be more-or-less it unless I missed something. Do wrap it in a transaction though.

Update: You should be able to do it without transaction I think:

creator = User.where(...
event = Event.new
user = User.where(...
user.invites.build(creator_id: creator) 
event.save!

This should work and is way better because lets you use validators in Event that check if the required associations are there.

Upvotes: 1

Related Questions