如何在从更新操作呈现编辑操作时阻止rails更改路径

tom*_*all 7 ruby-on-rails

据我所知,这是用于编辑和更新资源的标准rails模式.

我有一个用于编辑操作的GET路由/users/:id/edit以及用于更新操作的PUT和PATCH路由/users/:id.

这是我的控制器动作:

def edit
  @user = User.find params[:id]
end

def update
  @user = User.find params[:id]

  if @user.update_attributes(user_params)
    redirect_to @user, success: "Changes saved"
  else
    flash.now.alert = "Unable to change account details"
    render :edit
  end
end
Run Code Online (Sandbox Code Playgroud)

我在我的表单部分中使用默认的form_for:

<%= form_for @user do |f| %>
Run Code Online (Sandbox Code Playgroud)

这是在html中创建以下表单:

<form accept-charset="UTF-8" action="/users/1" id="edit_user_1" method="post">
  ...
  <input name="_method" type="hidden" value="patch">
Run Code Online (Sandbox Code Playgroud)

update_attributes正确重定向用户调用时,无论何时调用失败(由于ActiveRecord验证),渲染操作都会正确显示编辑视图,但用户浏览器中的路径将更/users/1/edit改为/users/1.

根据我的阅读,这似乎是rails的预期行为,但这似乎让我感到困惑,因为我认为REST背后的核心思想是URL是指资源的规范视图?

如果我redirect_to对编辑操作而不是render那个url是应该的,但是我丢失了表单上的错误消息.

在使用redirect_to之前,是否有更明智的方法来保留URL和错误消息,而不是将错误转储到会话中?如果可以,我想避免这样做.

更新:

我希望URL保持(以及错误)的原因是因为我正在使用current_page?在导航中设置活动状态.因此,如果表单提交错误,菜单中的"编辑"操作将失去突出显示.

Bil*_*han 1

您所在的原因/users/1是该视图是由 呈现的#update,而不是#edit

默认资源的路径#update与 相同,但#show请求方式不同。因此,当渲染 HTML 响应时,它与.GETPUT#update#show

我认为结果是可以接受的,无论你走哪条路,结果都是预期的。正如您已经发现的,如果使用redirect@user实例将更改为新分支,从而丢失错误和之前的填充。

路径上有解决方法,例如使用会话传递实例变量,但我认为这不值得付出努力。目前的结果已经足够好了。

添加

操纵活动状态很容易。我不喜欢current_page?需要太多代码。使用controller_pathandaction_name代替。

  if controller_path == 'users' && (action_name == 'edit' || 'update') 
     # add active class
  end      
Run Code Online (Sandbox Code Playgroud)

  • 想要保留 /edit 后缀的一个很好的理由是,如果用户在没有 /edit 的情况下重新加载页面,它将获得显示视图而不是编辑视图。不完全符合用户的期望。但是,如果页面是通过更新呈现的,您将不会在 URL 中看到 /edit 。您可能希望通过为这些动词创建路由并检查操作代码中的动词来对编辑操作进行 PUT/PATCH。 (2认同)