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
希望这对您有所帮助。
对我有什么帮助:
- 在
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
- 在注册表中:
<%= 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 %>
- 注册控制器:
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, address_attributes: [:id]])
end
参考文献:
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
希望这对您有所帮助。
对我有什么帮助:
- 在
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
- 在注册表中:
<%= 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 %>
- 注册控制器:
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, address_attributes: [:id]])
end
参考文献: