如何通过UserForm表单对象加载现有User实例完成编辑操作?
问题根因
你遇到的问题核心有3个:
UserForm没有接收现有User实例的逻辑,也没有将User的属性同步到表单自身的可访问字段上,导致渲染表单时拿不到已有数据- 原有
UserForm的initialize方法存在逻辑缺陷,新建场景下没有user_id会直接抛出查询异常 - 控制器
update动作没有走UserForm的逻辑,表单提交路径也没有区分新建/更新场景
修复方案
1. 修改 UserForm.rb
class UserForm include ActiveModel::Model include ActiveModel::Validations::Callbacks # 补充需要接收的参数 attr_accessor :fname, :lname, :email, :account_id, :user_id, :user before_validation :sync_user_attributes def initialize(params = {}) # 优先处理传入的已有User实例 if params[:user].present? @user = params.delete(:user) # 把已有User的属性赋值给表单字段,渲染时就能拿到值 self.fname = @user.fname self.lname = @user.lname self.email = @user.email self.account_id = @user.account_id self.user_id = @user.id end super(params) @account = Account.find(account_id) end # 新增判断场景的方法,给表单视图用 def persisted? user_id.present? end def sync_user_attributes # 已有用户就更新属性,新用户就初始化 @user ||= User.new @user.attributes = { fname: fname, lname: lname, email: email, account_id: @account.id } end def save # 验证通过后直接保存user即可,属性已经同步完成 return false unless valid? @user.save end end
2. 修改 UsersController.rb
class Admin::UsersController < AdminController # 编辑和更新动作前先加载对应User before_action :load_user, only: [:edit, :update] def new @user_form = UserForm.new(account_id: current_account.id) end def create @user_form = UserForm.new(user_form_params.merge(account_id: current_account.id)) if @user_form.save flash[:success] = "User created" redirect_to admin_user_path(@user_form.user) else render "new" end end def edit # 直接把查到的User传给表单 @user_form = UserForm.new(user: @user) end def update @user_form = UserForm.new(user_form_params.merge(user: @user, account_id: current_account.id)) if @user_form.save flash[:success] = "User updated" redirect_to admin_user_path(@user) else render "edit" end end private def load_user @user = current_account.users.find(params[:id]) end # 补充表单参数白名单 def user_form_params params.require(:user_form).permit(:fname, :lname, :email) end end
3. 修改表单视图 form.html.erb
自动适配新建/更新的提交路径和请求方法:
<%= simple_form_for @user_form, url: @user_form.persisted? ? admin_user_path(@user_form.user) : admin_users_path, method: @user_form.persisted? ? :patch : :post do |f| %> <%= f.input :fname %> <%= f.input :lname %> <%= f.input :email %> <% end %>
内容的提问来源于stack exchange,提问作者pinkfloyd90
相关产品推荐
相关产品推荐

