0

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.

2
  • Not an answer, but just wanted to point out that you either need to change group_id to item_group_id in the item_points table or add foreign_key: group_id to the belongs_to :item_group Commented Feb 24, 2015 at 15:57
  • Thanks. That's a typo on my part :) Commented Feb 24, 2015 at 16:05

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

7 Comments

I've added part of the offending form. Thanks for your help so far.
Rather than fields_for(:groups) I think you want your controller to build the models for all the item_points (@item_points = Groups.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.
Thanks, but I can't apply collect onto the ActiveRecord model. It needs to be applied to a scope iirc.
That's better :) but I still have a problem with the following code in the view just isn't working at all: <%= fields_for(:item_points, @item_points) do |points_form| %> <%= points_form.label :points, "#{@item_points.group.name}" %> <% end %>
Oh, silly me! It's working, wonderfully well. I've changed the view: <%= item_form.fields_for(:item_points, @item_points) do |points_form| %> <%= points_form.label :points, "#{points_form.object.group.name }"%> <%= points_form.text_field :points %> <%= points_form.hidden_field :group_id %> <% end %>
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.