Rails中未持久化的表单对象如何适配User的new与edit操作?
出现该错误的核心原因是:自定义表单对象UserForm没有实现Rails表单辅助方法依赖的persisted?约定,Rails始终将其识别为未持久化的新对象,因此表单永远生成POST请求。而Rails默认的更新路由仅接受PATCH请求,POST请求访问/admin/users/xxx自然会报路由不匹配错误。
步骤1:修改UserForm类适配Rails约定
需要补充属性声明、持久化状态代理、编辑场景的原有属性同步逻辑:
class UserForm include ActiveModel::Model include ActiveModel::Validations::Callbacks # 补充缺失的属性声明 attr_accessor :fname, :lname, :email, :account_id, :existing_user # 代理用户对象的id和持久化状态,让表单可以自动识别创建/更新场景 delegate :id, :persisted?, to: :@user def initialize(params = {}) super(params) @account = Account.find(account_id) @user = existing_user || User.new # 初始化时同步现有用户的属性到表单对象,编辑场景可以自动填充表单 unless new_record? self.fname = @user.fname self.lname = @user.lname self.email = @user.email end end # 统一提交时的属性赋值逻辑,兼容创建和更新场景 def save @user.assign_attributes(fname: fname, lname: lname, email: email) @user.save @user end private def new_record? !persisted? end end
步骤2:修改表单模板,解耦对@user变量的依赖
直接用表单对象自身的persisted?判断路由,不需要额外依赖控制器的@user变量,simple_form会自动根据持久化状态为更新场景生成符合要求的PATCH请求:
<%= simple_form_for @user_form, url: (@user_form.persisted? ? admin_user_path(@user_form) : admin_users_path) do |f| %> <%= f.input :fname %> <%= f.input :lname %> <%= f.input :email %> <%= f.submit %> <% end %>
步骤3:修改控制器逻辑,统一走表单对象流程
你当前的update动作没有走UserForm的逻辑,直接更新@user会导致表单的校验、数据处理逻辑失效,建议和create逻辑统一:
class Admin::UsersController < AdminController # 前置查询编辑/更新场景的用户对象 before_action :find_user, only: [:edit, :update, :show] 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 = @user_form.save flash[:success] = "User created" redirect_to admin_user_path(@user) else render "new" end end def edit @user_form = UserForm.new(existing_user: @user, account_id: current_account.id) end def update @user_form = UserForm.new(user_form_params.merge(existing_user: @user, account_id: current_account.id)) if @user = @user_form.save flash[:success] = "User saved" redirect_to admin_user_path(@user) else render "edit" end end private def find_user @user = User.find(params[:id]) end # 补充参数白名单配置,注意表单对象参数根键为user_form def user_form_params params.require(:user_form).permit(:fname, :lname, :email) end end
内容的提问来源于stack exchange,提问作者pinkfloyd90
相关产品推荐
相关产品推荐

