Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

grouping and fields_for

I'm trying to create a form which allows me to submit new records for an association where the association inputs are grouped.

   class Product < AR::Base
     has_many :properties
     accepts_nested_attributes_for :properties
   end

Note that in the controller a series of properties are built for the product, so @product.properties.empty? # => false.

The below fields_for gives me the correct inputs with names such as product[properties_attributes][0][value].

= form.fields_for :properties do |pform|                                                                                                                               
  = pform.input :value

But as soon as I try and group the association it no longer generates inputs with the correct names:

- @product.properties.group_by(&:group_name).each do |group_name, properties|
  %h3= group_name                                                       
  = form.fields_for properties do |pform|                                                                                                                               
    = pform.input :value

This create inputs which the name attribute like product[product_property][value] when in fact it should be product[property_attributes][0][value] as per the first example.

The Rails documentation suggests you can do this:

= form.fields_for :properties_attributes, properties do |pform|

But this gives an error "undefined method value for Array".

like image 396
Kris Avatar asked Aug 10 '12 13:08

Kris


2 Answers

You need to set up like this:

- @product.properties.group_by(&:group_name).each do |group_name, properties|
  %h3= group_name
  = form.fields_for :properties, properties do |pform|
    = pform.text_field :value

It should work fine, since you have accepts_nested_attributes_for :properties rails know that it's supposed to create fields for properties_attributes. Moreover you may want to add attr_accessible :properties_attributes if you are using one of newest Rails and if you didn't add it to your model yet ;)

Also, if you want to make some decision base on single property you may use the following form as well:

- @product.properties.group_by(&:group_name).each do |group_name, properties|
  %h3= group_name
  - properties.each do |property|
    = form.fields_for :properties, property do |pform|
      = pform.text_field :value

Both of them are nicely described here: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for under One-To-Many section

like image 192
Piotr Jakubowski Avatar answered Nov 30 '22 22:11

Piotr Jakubowski


I don't know of a clean 'Rails' solution to this sort of thing, but I often handle these types of situations more manually. eg - Loop through the groups and conditionally show only those properties that are in a particular group.

class Product < AR::Base
  has_many :properties
  accepts_nested_attributes_for :properties

  def group_names
    properties.map(&:group_name).uniq.sort
  end
end

In the view

- for group_name in product.group_names
  = form.fields_for :properties do |pform|
    %h3= group_name
    - if pform.object.group_name.eql?(group_name)
      = pform.input :value

There may be a little overhead with this, getting the list of properties from product repeatedly. You may be able to modify your has_many :properties association to retrieve the properties in group_name order - then you could add the %h3 when it's a new group.

- previous_group_name = nil
= form.fields_for :properties do |pform|
  - if pform.object.group_name != previous_group_name
    %h3= pform.object.group_name
  = pform.input :value
  - previous_group_name = pform.object.group_name

Some ideas for you...

like image 41
Mark Swardstrom Avatar answered Nov 30 '22 23:11

Mark Swardstrom