How can I generate form fields for a has_many :through
association that has additional attributes?
The has_many :through
relationship has an additional column called weight
.
Here's the migration file for the join table:
create_table :users_widgets do |t|
t.integer :user_id
t.integer :widget_id
t.integer :weight
t.timestamps
end
The models look like this:
User
has_many :widgets, :through => :users_widgets,
:class_name => 'Widget',
:source => :widget
has_many :users_widgets
accepts_nested_attributes_for :widgets # not sure if this is necessary
Widget
has_many :users, :through => :users_widgets,
:class_name => 'User',
:source => :user
has_many :users_widgets
accepts_nested_attributes_for :users # not sure if this is necessary
UsersWidget
belongs_to :user
belongs_to :widget
For the sake of simplicity, Widget and User only have one field of their own called name
, ergo User.first.name
and Widget.first.name
Questions:
How would I append a dropdown selection for Widgets with the corresponding weight to the User create/edit form?
How can I dynamically add additional Widget forms to Users or User forms to Widgets to easily add or remove these relationships? The nested_form_for
gem seems to be the perfect solution but I haven't been able to get it working.
Apart from the models and the form partials, are there any changes that need to be made to my controller?
Quick note.. I'm not interested in creating new Widgets in the User form or new Users in the Widget form, I only want the ability to select from existing objects.
I'm running Rails 3.1 and simple_form 2.0.0dev for generating my forms.
I will be solving your problem using cocoon, a gem I created to handle dynamically nested forms. I also have an example project to show examples of different types of relationships.
Yours is not literally included, but is not that hard to derive from it. In your model you should write:
class User
has_many :users_widgets
has_many :widgets, :through -> :user_widgets
accepts_nested_attributes_for :user_widgets, :reject_if => :all_blank, :allow_destroy => true
#...
end
Then you need to create a partial view which will list your linked UserWidgets
. Place this partial in a file called users/_user_widget_fields.html.haml
:
.nested-fields
= f.association :widget, :collection => Widget.all, :prompt => 'Choose an existing widget'
= f.input :weight, :hint => 'The weight will determine the order of the widgets'
= link_to_remove_association "remove tag", f
In your users/edit.html.haml
you can then write:
= simple_form_for @user do |f|
= f.input :name
= f.simple_fields_for :user_widgets do |user_widget|
= render 'user_widget_fields', :f => user_widget
.links
= link_to_add_association 'add widget', f, :user_widgets
Hope this helps.
base your question. I made a simple App. source is here: https://github.com/yakjuly/nest_form_example I deployed it to heroku, you can open page: http://glowing-lightning-1954.heroku.com/users/new
answers
you want user form can select widget with weight, need do more work.dropdown selection can not satisfy your requirement.
I mix "nested_form" in a "bootstrap-rails" plugin, you can add the nested_fields easier
in my example, you need add a action calls select, and make WidgetsController#create can responsed_with :js
the code is based simple_form, you can have a try.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With