Question

I have a Rails 3.2 project where:

Product has_many Descriptions

These Descriptions have a description_type and a language_code. Different types of Products can have different types and numbers of Descriptions, so that a Product of type 'Catalogwill have 4 different Descriptions, where a product of typeWholesale` will have only 2.

Upon the creation of a Product, an after_create method creates the different descriptions for the product, filling in only the description_type. The idea is that the user then goes in and fills in the different description values.

Now I am in the situation where I have to dynamically build some complex form with a different number of descriptions, then pass all those description values via the controller to some class method on either Product or Description to persist the data, and it just ends up as spaghetti everywhere.

I am convinced that I'm thinking of the problem wrong. I can't unthink it though, as this is one box I seem to put myself in over and over.

Is there some pattern that I can apply to the problem domain of nesting these child attributes in an existing form? I have to do it on Edit, because I don't know how many fields to create until the product_type is chosen. Again, I'm open to doing this completely differently.

I always run into this problem, and it ties me in knots. I am convinced that I am approachin

Was it helpful?

Solution

Just today I had to rebuild a Member form in our app, where a Member belongs to a User which has many PhoneNumbers.

The Member model accepts_nested_attributes_for :user and the User model accepts_nested_attributes_for :phone_numbers

Using the cocoon gem, I am able to do the following in my Member form:

# phone number fields in members/_form.html.haml
# if you do use this on a new (know you said edit but just in case) ... be sure to instantiate the association
# in my case: @member.user.phone_numbers.build 
# u represents the User part of the form ... typically 'f'
= u.simple_fields_for :phone_numbers do |phone|
  = render 'users/phone_number_fields', f: phone
.add-phone-link-wrapper.pull-right
  = link_to_add_association 'Add Phone', u, :phone_numbers, class: 'btn btn-orange btn-mini add-remove-links', partial: 'users/phone_number_fields', render_options: { wrapper: 'bootstrap' }

# 'users/phone_number_fields' partial
.nested-fields
  = f.input :phone
  = f.input :phone_label, as: :select, collection: PhoneNumber::LABELS
  = f.input :display_number, as: :boolean
  = link_to_remove_association 'Remove Phone', f, class: 'btn btn-red btn-mini add-remove-links pull-right', render_options: { wrapper: 'bootstrap' }

Note: I use SimpleForm and cocoon has some differences in implementation depending on your form builder (all on their github page/wiki).

For our needs, this fit perfectly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top