Rails Forms for Has_Many Through Association with Additional Attributes

Rails forms for has_many through association with additional attributes?

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.

Rails 4 nested attributes and has_many :through associaton in a form

When employing a has_many :through relationship, you need to pass the nested_attributes through the different models, like this:

Models

class Goal < ActiveRecord::Base
has_many :milestones, inverse_of: :goal, dependent: :destroy
accepts_nested_attributes_for :milestones, :allow_destroy => true

def self.build
goal = self.new
goal.milestones.build.milestone_programs.build_program
end
end

class Milestone < ActiveRecord::Base
belongs_to :goal, inverse_of: :milestones

has_many :milestone_programs
has_many :programs, through: :milestone_programs

accepts_nested_attributes_for :milestone_programs
end

class MilestoneProgram < ActiveRecord::Base
belongs_to :milestone
belongs_to :program

accepts_nested_attributes_for :program
end

class Program
has_many :milestone_programs
has_many :milestones, through: :milestone_programs
end

Controller

#app/controllers/goals_controller.rb
def new
@goal = Goal.build
end

def create
@goal = Goal.new(goal_params)
@goal.save
end

private

def goal_params
params.require(:goal).permit(milestones_attributes: [milestone_programs_attributes: [program_attributes:[]]])
end

Form

#app/views/goals/new.html.erb
<%= form_for @goal do |f| %>
<%= f.fields_for :milestones do |m| %>
<%= m.fields_for :milestone_programs do |mp| %>
<%= mp.fields_for :program do |p| %>
<%= p.text_field :name %>
<% end %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>

I appreciate this might not be exactly what you're looking for, but tbh I didn't read all your prose. I just gathered you needed help passing nested_attributes through a has_many :through relationship

Rails form with nested attributes in has_many through relationship

Try setting the inverse_of option on the has_many associations

  has_many :admin_host_users, class_name: 'Admin::HostUser', foreign_key: 'admin_host_id', dependent: :destroy, inverse_of: 'Admin::Host'
has_many :users, through: :admin_host_users, inverse_of: 'Admin::Host'

has_many through form and adding attribute to join table

Account model:

class Account < ActiveRecord::Base
attr_accessible :name, :description, :user_accounts_attributes
has_many :user_accounts, :dependent => :destroy
has_many :users, :through => :user_accounts
has_many :user_without_accounts, :class_name => 'User', :finder_sql => Proc.new {
%Q{
SELECT *
FROM users where id NOT IN (Select user_id from user_accounts where account_id = #{id})
}
}

accepts_nested_attributes_for :user_accounts, reject_if: proc { |attributes| attributes['user_id'] == '0' }

def without_accounts
new_record? ? User.all : user_without_accounts
end
end

In form:

= simple_form_for @account do |f|
= f.input :name
= f.input :description
- @account.user_accounts.each do |user_account|
= f.simple_fields_for :user_accounts, user_account do |assignment|
= assignment.check_box :user_id
= assignment.label :user_id, user_account.user.name rescue raise user_account.inspect
= assignment.input :account_admin
%hr
- @account.without_accounts.each do |user|
= f.simple_fields_for :user_accounts, @account.user_accounts.build do |assignment|
= assignment.check_box :user_id
= assignment.label :user_id, user.name
= assignment.input :account_admin
%hr
= f.button :submit

How to use has_many through association with additional attributes

It's absolutely not beside the point to declare attr_accessible. That's what you're missing.

Keep in mind attr_accessor is something else. For more on this, check: Difference between attr_accessor and attr_accessible

Also keep in mind that attr_accessible has been deprecated in Rails 4 in favor of Strong Parameters, effectively moving all whitelisting of attributes from the models to the controllers.



Related Topics



Leave a reply



Submit