1 year ago

#363502

test-img

Sumak

Create multiple associated records in a single form

I'd like a User to be able to create an Event and associated Invitations. An Invitation is a join table between User and Event (with an enum for its state, default to pending).

Eligible users are those who are member of the same team.

Here are my models:

class User
  has_many :invitations, dependent: :destroy
  has_many appointments, through: :invitations, source: :event, foreign_key: :event_id
end

class Invitation
  belongs_to :event
  belongs_to :user
end

class Event
  has_many :invitations, dependent: :destroy
  has_many :attendees, through: :invitations, source: :user, foreign_key: :user_id

  accepts_nested_attributes_for :invitations
end

On the controller setting the instance variables for the form I've:

def new
  @current_team = get_current_team
  @attendees    = @current_team.users.select(:id, :pseudonym)
  @new_event    = Event.new
  @new_event.invitations.build
end

Parameters are white listed, though I suspect I made a mistake here:

  def event_params
    :title,
    :start_date,
    # ...
    invitations_attributes: [user_id: []]
  end

And a form, from which a User can select attendees through a collection_check_boxes:

<%= form_with model: Event.new do |form| %>

  <%= form.fields_for :invitations, Event.new.invitations do |invitation_form| %>
    <%= invitation_form.collection_check_boxes :user_id, @attendees, :id, :pseudonym, { include_hidden: false } do |user_check_box| %>
      <li>
        <%= user_check_box.check_box %>
        <%= user_check_box.label %>
      </li>
    <% end %>
  <% end %>

<% end %>

Which generates a collection of <li> containing <input> like:

<li>
  <input type="checkbox" value="1" name="event[invitations_attributes][0][user_id][]" id="event_invitations_attributes_0_user_id_1">
  <label for="event_invitations_attributes_0_user_id_1">Hong Wintheiser III</label>
</li>

event form

However the params are not really convenients:

#<ActionController::Parameters {
  "event" => #<ActionController::Parameters {
    "title" => "Event title",
    "invitations_attributes" => { "0" => { "user_id" => [ "1", "2", "3" ] } }
  } permitted: false >,  
} permitted: false >

In the end, my parameters does not allow the creation of a new Event ("Invitations user must exist").

One way I can think about is to delete the invitations_attributes from params, save it in a variable, create the new Event (validation will succeed), and then iterate each invitations_attributes['0'][:user_id] to create associated Invitations.

Though it looks wrong to me, I believe there's a cleaner pattern to achieve this operation.


Question

How do you create a set of associated records from a `has_many through:` relationship inside a single form ?

Edit:

The EventController#create method:

def create
  @event.new(event_params)

  respond_to do |format|
   if @event.save
     # ...
   end
  end
end

Nothing special here, as I think I'm doing wrong before the creation.


Solution:

Our great savior @max answered this question 6 years ago.

Rails fields_for checkbox to create new record

TLDR:

<%= form_with model: @new_event do |f| %>
  <%= f.collection_check_boxes :attendee_ids, @attendees, :id, :pseudonym %>
<% end %>

def event_params
  # ...
  attendee_ids: []
end

And Invitation are created automagically

ruby-on-rails

forms

nested-attributes

0 Answers

Your Answer

Accepted video resources