Rails Devise:更新表单上的嵌套属性时出现“外键设置为nil”错误

时间:2018-12-20 08:06:44

标签: ruby-on-rails devise

我正在创建一个表单,以使用Devise更新我的Rails应用中的用户。

我已经将我的用户数据分为一个用于电子邮件和密码的用户模型,以及一个用于所有其他数据的配置文件表。

创建了一个表单来更新这些详细信息。表单呈现良好,并且正在发送参数,但是当我尝试更新嵌套记录的first_name时出现此错误。

  

ActiveRecord :: RecordNotSaved已保存在Devise :: RegistrationsController#update

中      

无法删除现有的关联配置文件。记录的外键设置为nil后,保存失败。

     

提取的来源(第93行附近):

  if target.persisted? && owner.persisted? && !target.save
    set_owner_attributes(target)
    raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " 
        "The record failed to save after its foreign key was set to nil."
  end

模型看起来像

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :profile
  after_create :create_profile

  accepts_nested_attributes_for :profile

end

class Profile < ApplicationRecord
  belongs_to :user
end

控制器看起来像

class ApplicationController < ActionController::Base

  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up) { |u|
        u.permit(:email, :password, [profile_attributes: [:id, :first_name, :last_name]])
      }
      devise_parameter_sanitizer.permit(:account_update) { |u|
        u.permit(:email, :password, [profile_attributes: [:id, :first_name, :last_name]])
      }

    end 
end

class UsersController < Devise::RegistrationsController

  def create
    super
  end

  def show
    @user = current_user
  end

  def edit
    @user = current_user
    super
  end

  def update
    @user = current_user  
    super
  end   
end

视图看起来像

<h1>Account Details</h1>

<p><strong>Email Address:</strong>    <%= @user.email %></p>
<p><strong>First Name:</strong> <%= @user.profile.first_name %></p>
<p><strong>Last Name:</strong> <%= @user.profile.last_name %></p>
<p><strong>Description:</strong> <%= @user.profile.description %></p>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= devise_error_messages! %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <%= f.fields_for :profile_attributes, {html: { method: :put}} do |p| %>
    <div class="field">
      <%= p.label :first_name %><br />
      <%= p.text_field :first_name %>
    </div>
  <% end %>

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
  <% end %>

  <div class="field">
    <%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
    <% if @minimum_password_length %>
      <br />
      <em><%= @minimum_password_length %> characters minimum</em>
    <% end %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "current-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Update" %>
  </div>
<% end %>
<br><br>
<%= button_to "Delete Account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>

我该如何解决?

1 个答案:

答案 0 :(得分:1)

您需要在表单内使用现有用户的个人资料。将fields_for的行更改为:

<%= f.fields_for resource.profile do |p| %>

请注意,由于它不是单独的表格,因此在这里不需要method