Ryan Oliver Lanham
Ryan Oliver Lanham

Reputation: 461

Not sure which method of model associations my app requires

What I Have So Far:

class Organization < ActiveRecord::Base
    belongs_to :user
    has_many :events
    has_many :vips
end

class Event < ActiveRecord::Base
  belongs_to :organization
  has_many :vips
end

class Vip < ActiveRecord::Base
    belongs_to :organization
    belongs_to :event
end

My form for New Events:

<%= form_for [@organization, @event] do |f| %>
    <p>
        <%= f.label :when %>
        <%= f.date_select :when %>
    </p>
    <p>
        <%= f.label :name %>
        <%= f.text_field :name %>
    </p>
    <p>
        <%= f.label :vip %>
        <%= f.select :vip_id, options_for_select(@organization.vips.all.map {|v| [v.name, v.id]}) %>
    </p>
    <p>
        <%= f.submit %>
    </p>
<% end %>

What my Models look like in the Console:

<Organization id: 1, name: "Test Org", created_at: "2015-08-25 04:46:03", updated_at: "2015-08-25 04:46:03", user_id: 1>

<Event id: 1, when: "2015-08-25 00:00:00", organization_id: 1, created_at: "2015-08-25 04:47:43", updated_at: "2015-08-25 04:47:43", name: "John's Event", vip_id: 1>

<Vip id: 1, name: "Captain", created_at: "2015-08-25 04:46:23", updated_at: "2015-08-25 06:51:47", organization_id: 1>

Note: I ran "rails generate migration add_vip_id_to_events vip:references" I did this because I want my handful of vips per organization able to be attached to a large amount of events. I was hoping that each event would know which vips were attached to it based on the vip_id column.

What I'm trying to Accomplish:

In my app I have Organization, Event, and Vip models. On my 'organization#show' page, I want to have all events for a given organization such that there would be a single date (e.g. "Mon, Sep 1 2015," "Tue, Sep 2 2015," and "Wed, Sep 3 2015") as a table header, and then all events on that date would be listed as "Event name, given by, Event Vip, at Event location, at Event time."

In the organization, I also want there to be Vips, that have their own 'Vip#Show' page within the organization. And, when you're filling out the event form, you'd be able to select the vip/vips that will be associated with that event (along with many other events) from the existing organization vips.

The Problem:

If I go to console, and attempt to find a vip attached to an event, I'll do the following:

@organization = Organization.find(1)
@event = @organization.events.first
@event.vips.first

and it returns => nil

Ok, so now I run a rails migration that adds an event_id column to vips, and manually populate it in console, so that it's pointing to the organizations first event (event_id = 1), and when I run the same code, I get:

@organization = Organization.find(1)
@event = @organization.events.first
@event.vips.first
=> #<Vip id: 1, name: "John", created_at: "2015-08-25 04:46:23", updated_at: "2015-08-25 06:51:47", organization_id: 1, event_id: 1>

This is a problem because I can't have my vips associated with only one event. I need them able to be associated with dozens of events, so that I can access them through block code, such as

<% @events = @organization.events.all %>
<% @events.each do |event| %>
  <%= event.name %>
  <% event.vips.each do |vip| %>
    <%= vip.name %>
  <% end %>
<% end %>

Upvotes: 1

Views: 43

Answers (2)

Mangesh Tamhankar
Mangesh Tamhankar

Reputation: 178

Sounds like you're trying to create a many-to-many relationship and not a one-to-many as you currently have. If you take a look at the rails guides they explain this in detail here. The basic idea is to have a third table to define all of the relations between events and vip's. This table generally has a column for event_id and a column for vip_id. Each row in the table is a single association, so you can list multiple associations for the same vip or event.

This will allow you to call event.vips or even vip.events.

There's actually two options to get a many-to-many relation, you could use has_and_belongs_to_many, or has_many :through. The differences are also outlined in the guides, but to summarize the general idea is that you can use the has_many :through if you need to attach additional information or methods to the relation itself. In this case, it is treated as its own separate entity or model. If you have no ned for this and are only interested in relating the two models that you already have then a has_and_belongs_to_many is simpler to use and just requires the table in the database.

has_and_belongs_to_many

class Event < ActiveRecord::Base
  has_and_belongs_to_many :vips
end

class VIP < ActiveRecord::Base
  has_and_belongs_to_many :events
end

has_many :through

class Event < ActiveRecord::Base
  has_many :event_vip_list
  has_many :vips, through: :event_vip_list
end

class Vip < ActiveRecord::Base
  has_many :event_vip_list
  has_many :events, through: :event_vip_list
end

class EventVipList < ActiveRecord::Base
  belongs_to :event
  belongs_to :vip
end

Upvotes: 0

Mark Swardstrom
Mark Swardstrom

Reputation: 18070

It sounds like you may want

class Organization < ActiveRecord::Base
  has_many :vips

class Event
  has_many :event_vips
  has_many :vips, :through => :event_vips

class EventVip < ActiveRecord::Base
  belongs_to :event
  belongs_to :vip

class Vip < ActiveRecord::Base
  belongs_to :organization
  has_many :events_vips
  has_many :events, :through => :event_vips

This will make the vips a child of a single organization, and have the ability to connect with multiple events.

Upvotes: 1

Related Questions