You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails创建Booking时无法获取嵌套profile参数更新用户资料

问题描述

现有3个Rails ActiveRecord模型,需求为完成Booking创建操作后,若用户提交的资料有变更,同步更新对应用户的Profile信息。当前提交表单后booking_params仅返回:poi_id、:owner_id、:user_id三个参数,无法获取Profile相关字段,无法完成Profile更新。

现有模型定义

  • user.rb
class User < ApplicationRecord
  has_one :profile, inverse_of: :user, dependent: :destroy
  accepts_nested_attributes_for :profile
  has_many :bookings, inverse_of: :user, dependent: :destroy
  has_many :owner_bookings, foreign_key: 'owner_id', class_name: 'Booking'
end
  • profile.rb
class Profile < ApplicationRecord
  # mount_uploader :avatar, AvatarUploader
  belongs_to :user, inverse_of: :profile
  accepts_nested_attributes_for :user
end
  • booking.rb
class Booking < ApplicationRecord
  belongs_to :user
  belongs_to :owner, class_name: :User
  belongs_to :poi
end

原有问题代码

表单代码

<%= simple_form_for [@poi.poitable, @booking] do |f| %>
  <%= f.simple_fields_for @user.profile do |profile| %>
    <%= profile.input :first_name,
                      input_html: { value: @user.profile.first_name } %>
    <%= profile.input :last_name, input_html: { value: @user.profile.last_name } %>
  <% end  %>
  <%= f.input :owner_id, input_html: { value: @poi.user.id } %>
  <%= f.input :poi_id, input_html: { value: @poi.id } %>
  <%= f.input :user_id, input_html: { value: @user.id } %>
  <%= f.submit %>  
<% end %> 

控制器代码

def new
  @user = current_user
  @poi = Sleep.friendly.find(params[:sleep_id]).poi
  @booking = Booking.new
end

def create
  @user = current_user
  @poi = Sleep.friendly.find(params[:sleep_id]).poi
  @booking = Booking.new(booking_params)
  if @booking.save
    @booking.user.profile.update_attribute(booking_params[:user_profile_attributes])
end

private

def booking_params
  params.require(:booking).permit(
    :poi_id,
    :owner_id,
    :user_id,
    user_profile_attributes: [:user_id, :first_name, :first_name],
  )
end

修复方案

问题由三处写法错误导致,按以下步骤修改即可:

  1. 修正表单嵌套字段写法
    直接给simple_fields_for传@user.profile对象时,生成的表单字段name属性会自动生成为booking[profile][xxx],和控制器里许可的user_profile_attributes键名不匹配,同时不需要手动给input加value属性,表单构建器会自动绑定值。另外需要加hidden类型的id字段,否则更新时无法定位到现有Profile记录。
    将表单内嵌套字段部分替换为:
<%= f.simple_fields_for :user_profile_attributes, @user.profile do |profile| %>
  <%= profile.input :first_name %>
  <%= profile.input :last_name %>
  <%= profile.input :id, as: :hidden %>
<% end %>
  1. 修正控制器参数许可与更新逻辑
    首先删除参数许可里重复声明的:first_name,补充Profile的:id字段;创建Booking实例时需要剔除user_profile_attributes参数,避免Booking模型无对应属性报批量赋值错误;update_attribute是单字段更新方法,批量更新字段需要用update方法。
    修改后的控制器相关代码如下:
def create
  @user = current_user
  @poi = Sleep.friendly.find(params[:sleep_id]).poi
  @booking = Booking.new(booking_params.except(:user_profile_attributes))
  if @booking.save
    @booking.user.profile.update(booking_params[:user_profile_attributes])
    # 补充保存成功后的跳转逻辑
  else
    # 补充校验失败的渲染逻辑
  end
end

private

def booking_params
  params.require(:booking).permit(
    :poi_id,
    :owner_id,
    :user_id,
    user_profile_attributes: [:id, :first_name, :last_name]
  )
end

修改完成后重启服务,即可正常拿到Profile相关参数完成更新。


内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 18:18:27