glapworth
glapworth

Reputation: 163

Rails 4 Nested Form

I have three models:

class Item < ActiveRecord::Base
   has_many :item_points
   has_many :groups,  through: :item_points
   accepts_nested_attributes_for :item_points
end

class ItemPoint < ActiveRecord::Base
  belongs_to :group
  belongs_to :item
  accepts_nested_attributes_for :group
end

class Group < ActiveRecord::Base
  has_many :item_points
  has_many :items, through: :item_points
end

The schema for items

create_table "items", force: :cascade do |t|
  t.string   "name",       null: false
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

The schema for item_points

create_table "item_points", force: :cascade do |t|
  t.decimal  "points",          null: false
  t.integer  "item_id",         null: false
  t.integer  "group_id",   null: false
  t.datetime "created_at",      null: false
  t.datetime "updated_at",      null: false
end

The schema for groups

create_table "groups", force: :cascade do |t|
    t.string   "name",       null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
end

In my groups table, I've created a number of rows, e.g. group 1 and group 2.

In the form for creating items I'd really like to see a field each for group 1 and group 2, so that I might be able to enter the points for that item. e.g. In item X, group 1 is worth 10 points, and group 2 is worth 5 points.

EDIT Added the form

The form:

 <%= form_for(@item) do |item_form| %>

      <div class="form-group">
        <%= item_form.label :name %>
        <%= item_form.text_field :name, :class => 'form-control' %>
      </div>

      <%= item_form.fields_for(:groups) do |groups_form| %>
        <% group = groups_form.object_id.to_s%>
        <%= groups_form.hidden_field :id %>
        <%= groups_form.fields_for(:item_point) do |entity_form| %>
          <%= entity_form.text_field :points %>
        <% end %>
      <% end %>

This provides me with a form, which contains one extra entry box, called item[groups][item_point][points], and has no label.

What I'd like to know is how do I get all of the rows I've added into groups as fields into a Rails Form? And when I do, how do I save the associated item_points data using strong parameters?

I've spent quite some time looking for an answer, and I can't seem to find anything other than a series of StackOverflow questions, which don't quite seem to have the same problem as me.

All help is wonderfully appreciated.

Upvotes: 0

Views: 74

Answers (1)

Coenwulf
Coenwulf

Reputation: 1937

There's a helpful post with some examples at: https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through. It specifically talks about adding inverse_of on your associations.

In your view you'll need to use fields_for. You could (for example) put that in a table or a list and have each entry be a row.

If you share what you've tried in your view so far you may be able to get a more detailed response if you need it.

As for permitted_params in your controller, you can nest them something like:

def permitted_params
  params.permit(item: [
    :name,
    item_points_attributes: [
      :id,
      :points,
      :group_id,
    ]
  )
end

Update:

Rather than fields_for(:groups) I think you want your controller to build the models for all the item_points (@item_points = Group.all.collect {|group| ItemPoint.new({group_id: group.id, item_id: @item.id}). Then you can use a fields_for(:item_points, @item_points).

You can add a label for the field so it's not just an unlabeled field using the HTML label tag.

Upvotes: 1

Related Questions