Rails嵌套表单不能保存孩子

时间:2014-01-25 05:09:56

标签: ruby-on-rails nested-forms has-many

我的用户模型has_many响应。我正在尝试创建一个嵌套表单来创建一个具有三个子响应的新用户。我的代码看起来与Rails强制转换相同,但是虽然它会保存用户,但它不会保存它们的响应。任何人都可以看到有什么问题吗?

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+\-.]+@[a-z\d\-.]+\.[a-z]+\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(表单)

<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 %>

编辑:

我已将Users控制器中的强参数更改为:

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

我已将用户模型更新为:

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+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX } ,
            uniqueness: {case_sensitive: false};

  validates_associated :responses, presence: true
end

现在它仍然无法通过我的回复验证,也无法验证用户名和电子邮件的验证。

3 个答案:

答案 0 :(得分:5)

问题出在您的Response类中:

validates_presence_of :user_id, :content

此验证需要user_id的存在,这意味着必须在Response之前创建用户。为了使它工作,你可以尝试几件事:

  • validates_presence_of :user_id更改为validates_presence_of :user,以使其验证User对象而非用户ID。

  • 使用inverse_of选项。请参阅Rails API doc

更新了代码。

<强> 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

答案 1 :(得分:1)

回答RoR v3:

问题是User模型中的以下行:

attr_accessor :responses_attributes

将其替换为:

attr_accessible :responses_attributes

问题Difference between attr_accessor and attr_accessible的答案应该有助于您理解两者之间的区别。

此外,您的验证validates :responses, presence: true需要更新才能使用validates_associated

validates_associated :responses, presence: true

回答RoR v4:

我没有注意到使用强参数更早,为此道歉。一些更改应该可以解决您的问题:

  1. attr_accessor :responses_attributes型号中删除User
  2. validates :responses, presence: true替换为validates_associated :responses, presence: true
  3. 在许可列表中定义responses属性。
  4. 如下所示:

    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
    

答案 2 :(得分:0)

您的代码看起来几乎正确:

<强> 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+\-.]+@[a-z\d\-.]+\.[a-z]+\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