Rails nested childless form

My user model has_many Answers. I am trying to create a nested form to create a new user with three child answers. My code looks the same as Rails, but although it saves the user, it will not save the answers. Can anyone understand what is wrong?

users_controller.rb

class UsersController < ApplicationController def new @user = User.new 3.times{@user.responses.build} @responses = @user.responses end def create @user = User.new(user_params) if @user.save redirect_to @user #todo: where do we want to redirect? else render 'new' end end def show @user = User.find(params[:id]) @responses = @user.responses end def index @users = User.all end private def user_params params.require(:user).permit(:username, :email, :responses) end end 

user.rb

 class User < ActiveRecord::Base attr_accessor :responses_attributes has_many :responses, :dependent => :destroy accepts_nested_attributes_for :responses#, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true before_save { self.email = email.downcase } validates :username, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.] +@ [az\d\-.]+\.[az]+\z/i validates :email, presence: true, format: { with: VALID_EMAIL_REGEX } , uniqueness: {case_sensitive: false}; validates :responses, presence: true end 

response.rb

 class Response < ActiveRecord::Base belongs_to :user validates_presence_of :user_id, :content end 

users / new.html.erb (form)

 <h1>This is a test form for adding Users with child Responses</h1> <%= form_for @user do |f| %> <%= render 'shared/error_messages' %> <%= f.label :username %> <%= f.text_field :username %> <%= f.label :email %> <%= f.text_field :email %> <p> <%= f.fields_for :responses do |builder| %> <%= builder.label :content, "Response" %> <%= builder.text_field :content %> <% end %> </p> <%= f.submit "Submit" %> <% end %> 

Edit:

I changed the strong settings in the Users controller to:

 def user_params params.require(:user).permit(:username, :email, responses_attributes: [:content]) end 

And I updated the User model to:

 class User < ActiveRecord::Base has_many :responses, :dependent => :destroy accepts_nested_attributes_for :responses#, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true before_save { self.email = email.downcase } validates :username, presence: true, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.] +@ [az\d\-.]+\.[az]+\z/i validates :email, presence: true, format: { with: VALID_EMAIL_REGEX } , uniqueness: {case_sensitive: false}; validates_associated :responses, presence: true end 

Now it continues to fail in my responses to the responses, and also fails to complete my checks for username and email.

+7
ruby-on-rails nested-forms has-many
source share
3 answers

The problem is in your Response class:

 validates_presence_of :user_id, :content 

This check requires the existence of user_id , which means that the user must be created before the response. To make it work, you can try several things:

  • Change validates_presence_of :user_id to validates_presence_of :user so that it validates_presence_of :user User object instead of the user ID.

  • Use the inverse_of option. See the Rails API doc .

Updated code.

user.rb

 class User < ActiveRecord::Base attr_accessible :responses_attributes has_many :responses, :dependent => :destroy, :inverse_of => :user accepts_nested_attributes_for :responses # ... end 

response.rb

 class Response < ActiveRecord::Base belongs_to :user, :inverse_of => :responses validates_presence_of :user, :content end 
+5
source share

Answer for RoR v3:

The problem is the following line in your User model:

 attr_accessor :responses_attributes 

Replace it:

 attr_accessible :responses_attributes 

The answer to the question Difference between attr_accessor and attr_accessible should help you understand the differences between them.

You also need to update your validates :responses, presence: true check to use validates_associated :

 validates_associated :responses, presence: true 

Answer for RoR v4:

I did not notice the use of strong ealier parameters, sorry for that. A couple of changes should fix your problem:

  • Remove attr_accessor :responses_attributes from the User model.
  • Replace validates :responses, presence: true with validates_associated :responses, presence: true
  • Define responses attributes in the permission list.

Something like the following:

 class User < ActiveRecord::Base # attr_accessor :responses_attributes # Remove this line has_many :responses, :dependent => :destroy accepts_nested_attributes_for :responses#, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true ... validates_associated :responses, presence: true # Update here end #Users Controller class UsersController < ApplicationController ... private def user_params params.require(:user).permit(:username, :email, :responses_attributes[:content]) end end 
+1
source share

Your code looks almost correct:

user.rb

 class User < ActiveRecord::Base has_many :responses, :dependent => :destroy accepts_nested_attributes_for :responses before_save { self.email = email.downcase } validates :username, length: { maximum: 50 } VALID_EMAIL_REGEX = /\A[\w+\-.] +@ [az\d\-.]+\.[az]+\z/i validates :email, presence: true, format: { with: VALID_EMAIL_REGEX } , uniqueness: {case_sensitive: false}; end 

users_controller.rb

 private def user_params params.require(:user).permit(:username, :email, responses_attributes: [:content]) end 
0
source share

All Articles