Search code examples
ruby-on-railsrails-activerecordmodel-associations

Multiple has many to the same Model


I have a model Event with a nested model Attendee. Each attendee can be 1 of 3 roles (:guide, :marshal and :organizer).

class Event < ApplicationRecord

  has_many :attendees, dependent: :destroy
  has_many :guides, -> { Attendee.guide }
  has_many :marshals, -> { Attendee.marshal }
  has_many :organizers, -> { Attendee.organizer }
end

_

class Attendee < ApplicationRecord

  belongs_to :event

  validates :name, presence: true
  validates :role, presence: true
  validates :email, email: true

  enum role: %i[guide marshal organizer]

  scope :guide, -> { where(role: :guide) }
  scope :marshal, -> { where(role: :marshal) }
  scope :organizer, -> { where(role: :organizer) }
end

I would like my event registration form to have nested forms for each of the role types. I am trying something like this.

<%= form_for @event, url: event_create_path(@event.handle) do |f| %>

    <%= f.fields_for :organizers do |f| %>
        <%= render partial: "attendee_fields", locals: {f: f} %>
    <% end %>

    <%= f.fields_for :guides do |f| %>
        <%= render partial: "attendee_fields", locals: {f: f} %>
    <% end %>

    <%= f.fields_for :marshals do |f| %>
        <%= render partial: "attendee_fields", locals: {f: f} %>
    <% end %>
<% end %>

When a submit I receive the following error.

uninitialized constant Event::Guide

Any ideas on how to get around this?


Solution

  • Your Event model needs to look more like this:

    class Event < ApplicationRecord
      has_many :attendees, dependent: :destroy
      has_many :guides, -> { guide }, class_name: "Attendee"
      has_many :marshals, -> { marshal }, class_name: "Attendee"
      has_many :organizers, -> { organizer }, class_name: "Attendee"
    end
    

    The extra associations need to know which model they're linking with -- as the error shows, they're currently guessing that e.g. guides is associated with some model named Guide.

    (You also shouldn't need those scopes in Attendee, I don't think... I believe enum defines identical ones for you automatically.)