Rails 设计 - 创建用户并更新关联记录

Rails Devise - Create user and update associated record

Ruby版本:2.6.3

Rails版本:6.0

我有 2 个模型

1) 用户

has_one :address, dependent: :destroy
accept_nested_attributes :address

2) 地址

belongs_to :user, optional: true

我为用户模型使用了设计。地址模型已经有一些记录,但它们与用户无关。 当用户来注册时,我必须显示与任何用户无关的可用地址列表。

我想针对这种情况使用嵌套表单。我重写了设计注册控制器,但参数中的属性不正确。

这是我的注册表代码

  <%= f.fields_for :address do |sc| %>
    <%= sc.label :address %>
    <%= sc.select :address, options_for_select(Address.available_addresses&.map{ |i| [i.address, i.id] }), class: 'form-control' %>
  <% end %>

参数

Parameters: {"authenticity_token"=>"MN6zE3Z7B7zhQupa6kvbqGN4kmc8pAHRrdqtKipDclki3f6H5M919YCe9O7b+M8X49wuD3UczzpRJDl0Fmx0SQ==", "user"=>{"first"=>"daa", "last"=>"dasa", "email"=>"aa@g.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "address_attributes"=>{"address"=>"1"}, "commit"=>"Sign up"}

application_controller.rb

before_action :configure_permitted_parameters, if: :devise_controller?

def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:first, :last, address_attributes: [:id, :address]] )
  end

主要是它不作为属性传递。它仅作为 address: [:address] 传递。如果我写 f.fields_for :address 它不会显示在视图中。但是如果我写 fields_for :address 而不是它只显示在表格中。 很奇怪为什么它没有按预期工作。

我不必创建新的地址记录。如何将 has one 的现有记录关联到用户?

更新

当我使用地址属性时,它只是为地址创建一条新记录,而不是为用户更新地址记录。我很奇怪为什么它不更新记录并插入新记录。我只想更新地址记录的用户 ID。我不想创建地址模型的新记录。

更新 我用下面的代码解决了我的问题

new.html.erb

  <%= fields_for :address do |sc| %>
    <%= sc.label :address %>
    <%= sc.select :address, options_for_select(Address.available_addresses&.map{ |i| [i.address, i.id] }), class: 'form-control' %>
  <% end %>

users/registrations_controller.rb
if resource.persisted?
  if resource.active_for_authentication?
     address = Address.find(params[:address][:address])
     address.update_column(:user_id, resource.id)

我真的很想知道为什么会这样,我使用了嵌套属性,但它只是创建新记录,而不是创建新用户和更新地址。这是一个非常小的问题,我想弄清楚幕后发生的事情。

您需要生成设计控制器并配置 registrations_controller.rb Configure devise controllers 因为您需要在创建新用户后构建地址。

rails g devise:controllers users -c=registrations

并将控制器添加到 devise_for 路线: 例如: devise_for :users, controllers: { registrations: 'users/registrations' }

然后您可以编辑 sign_up_params 以包含 address_parameters

def sign_up_params
  params.require(:user).permit(:first, :last, address_attributes: [:your_address_attributes])
end

您还需要覆盖 registrations_controller 中的 new 以包含构建地址

def new
  super { resource.build_address }
end

要了解其工作原理,您需要查看 registerations_controller

对于视图部分,您仍然需要 f.fields_for :address

希望这对您有所帮助。

对我有什么帮助:

  1. user.rb 中,覆盖 address_attributes= 方法:
def address_attributes=(address_attrs)
  self.address = Address.find_or_initialize_by(id: address_attrs[:id])
  self.address.attributes = address_attrs
end
  1. 在注册表中:
<%= f.fields_for :address, resource.address ? resource.address : resource.build_address do |address_form| %>
    <%= address_form.label :id, "Address" %>
    <%= address_form.collection_select :id, Address.where(user_id: nil), :id, :address, include_blank: "Choose address", class: "form-control" %>
<% end %>
  1. 注册控制器:
def configure_sign_up_params
  devise_parameter_sanitizer.permit(:sign_up, keys: [:name, address_attributes: [:id]])
end

参考文献: