Rails重定向或渲染以显示错误

时间:2018-07-10 15:21:40

标签: ruby-on-rails

当用户对资源进行无效的创建请求时,我想将其发送回表单并向他们显示错误。据我所知,调用render "new"是实现此目的的标准方法。

这对我来说似乎是个坏主意,因为创建请求已将用户带到/ resources,而我的“新”表单则位于/ resources / new。如果我使用render "new",则地址栏中的URL不会反映用户看到的内容。如果他们在那里提出GET请求,那么他们将进入另一个页面。

我认为可以使用redirect_to new_[resource]_path解决此问题,但是如果这样做,我将无法访问表单数据和错误。当然,这不是一个罕见的问题。有没有更好的方法来解决它?

编辑/更新和其他表单/提交操作对存在相同的问题。

2 个答案:

答案 0 :(得分:1)

您可能想得太多。 get /resources索引页与post /resources的create操作怎么样?地址栏中的网址相同!

这不是问题。既不是技术问题也不是美学问题。

render "new"的意思是:渲染此模板,而不是:转到此路线。尽管模板通常具有相应操作的名称,但这不是必需的。

答案 1 :(得分:1)

TL; DR:

class ResourcesController < ApplicationController
  def new
    @resource = Resource.new(resource_params)

    if resource_params.present?
      @resource.validate
    end
  end

  def create
    @resource = Resource.new(resource_params)
    if @resource.save
      redirect_to @resource, notice: 'Resource has been created'
    else
      redirect_to new_resource_url(resource: resource_params)
    end
  end

  private

  def resource_params
    params.fetch(:resource, {}).permit(...)
  end
end

我也很早就问自己这个问题,为什么Rails脚手架生成器会在保存失败时向def create生成render :new动作,而不是像上面那样重定向到正确的URL,这会使用户感到困惑,因为即使他们仍然在页面上看到完全相同的“资源”表单,他们的URL也会从/resources/new变为/resources,因此他们将无法重新加载页面或复制此/resources URL(例如,如果他们想与其他人共享此URL),因为他们应该共享此/resources URL,其他人将在页面上看到资源列表,而不是原始用户希望从复制的URL:表单页面中看到。

用户提交表单后,他们在地址栏上看到的URL应该已更改为POST http://localhost:3000/resources,而不仅仅是http://localhost:3000/resources。浏览器隐藏了正在使用的HTTP方法,这就是为什么这可能导致他们混淆/resources有时有时是这样的原因:表单页面,有时是资源列表页面。但是,说到UX,每当有人输入任何内容或在浏览器的URL地址栏中粘贴一些内容时,总是会自动暗示它正在执行GET请求。因此,对于浏览器开发人员来说,仅向用户隐藏HTTP方法(特别是GET)就很有意义,以免混淆他们。

根据我上面的回答,我以前只使用过一次这样的操作(因为有某些操作要求我不要从引荐来源网址表单页面更改网址)。但是,我通常是render :new而不是redirect_to new_resources_url,仅仅是因为:

  • redirect_to new_resource_url(resource_params)所花费的时间和数据传输量比仅渲染:new所花费的时间要多一倍。为什么?因为无论如何您使用完全相同的参数重定向(打开一个新请求)。试想一下,如果您的表单页面太大,并且有很多输入字段。

  • ,而且URL的长度是有限制的,如果您使用非常大的表单且文本字段很长,则不能保证可以正常使用。看到这个SO

已更新:

尽管您已经说过,为什么在提交表单时不只是POST /resources/new而不是POST /resources,对吗?这将解决我上面显示的redirect_to new_resource_url(resource_params)问题,因为提交表单后的URL将会是相同的,然后您只需简单地render :new即可。我实际上对此表示同意,并且很久以前我也使用过类似的方法。我不使用它的主要原因是它不符合REST标准。也就是说:POST /resources/new意味着您正在resources/new位置“内部”创建一个资源对象,这意味着通过REST,在提交表单之后,我将并且应该能够访问此新创建的对象通过执行GET /resources/new/the_newly_created_record之类的资源,除了...您做不到。

但是您仍然可以使用POST /resources/new,尽管我不建议在像您这样的普通Rails应用程序上使用它,但是严格建议不要在基于API的Rails应用程序上使用它。