【问题标题】:The correct way to handle invalid form submissions in Rails在 Rails 中处理无效表单提交的正确方法
【发布时间】:2011-02-18 22:10:07
【问题描述】:

我是 Rails 新手,我不确定我是否同意我在一些教程中所做的事情。这个问题与如何处理无效的表单提交有关。做事的标准方式似乎是:

class ThingsController < ApplicationController


  # POST /things
  def create

    @thing = Thing.new(params[:thing])

    if @thing.save
      flash[:notice] = 'Thing created'
      redirect_to(@thing)
    else
      render :action => :new
    end

  end

当@thing.save 失败时,用户会看到相同的表单,其中预先填写了他刚刚输入的值,以及出现的问题。到目前为止一切都很好,除了现在 URL 已从 /things/new 更改为 things/,人们希望它会呈现索引视图。

此外,如果用户刷新页面,他现在正在查看索引视图。如果他点击返回,系统会提示他重新提交表单,而我一直试图避免这种情况。如果我redirect_to(new_thing_path),则用户之前的提交将丢失,错误消息也是如此。

我意识到 RESTful,这种方法可能是“正确的”,因为创建事物对象应该是 POST 到 /things 的结果,但是从用户界面的角度来看,我并不特别关心它。

我可以“手动”将无效的@thing 对象保存在用户的会话中,以便在我将他重定向回 new_thing_path 后显示,但这感觉就像是 hack。似乎应该有一种“轨道方式”来做到这一点。

想法?

【问题讨论】:

  • 我对 Rails 核心也有同样的抱怨,但你的措辞比我做得好:) 好问题。

标签: ruby-on-rails-3


【解决方案1】:

如您所见,默认情况下,当您指定resources :things 时,创建新事物的POST 路径为/things。这是rake routes 的输出:

    things GET    /things(.:format)          {:action=>"index", :controller=>"things"}
           POST   /things(.:format)          {:action=>"create", :controller=>"things"}
 new_thing GET    /things/new(.:format)      {:action=>"new", :controller=>"things"}
edit_thing GET    /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
     thing GET    /things/:id(.:format)      {:action=>"show", :controller=>"things"}
           PUT    /things/:id(.:format)      {:action=>"update", :controller=>"things"}
           DELETE /things/:id(.:format)      {:action=>"destroy", :controller=>"things"}

听起来你想要更像这样的东西:

create_things POST   /things/new(.:format)      {:action=>"create", :controller=>"things"}
       things GET    /things(.:format)          {:action=>"index", :controller=>"things"}
    new_thing GET    /things/new(.:format)      {:action=>"new", :controller=>"things"}
   edit_thing GET    /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
        thing GET    /things/:id(.:format)      {:action=>"show", :controller=>"things"}
              PUT    /things/:id(.:format)      {:action=>"update", :controller=>"things"}
              DELETE /things/:id(.:format)      {:action=>"destroy", :controller=>"things"}

虽然不推荐,但是可以通过以下途径得到这个结果:

resources :things, :except => [ :create ] do
  post "create" => "things#create", :as => :create, :path => 'new', :on => :collection
end

您还需要修改表单以使它们 POST 到正确的路径。

话虽如此,您在问题中对 URL 的描述听起来并不正确。您列出以下内容:提交新的thing 后(在/things/new 提交表单),

  1. URL 从/things/new 更改为/things
  2. 点击返回提示重新提交表单
  3. 刷新节目things#index

不是我在自己的 Rails 3 应用程序中体验到的功能。相反,我发现:在提交新的thing(在/things/new 提交表单)后,

  1. URL 由/things/new 变为/things(同理)
  2. 点击返回会使用户返回到提交的表单(不要求重新发布)
  3. 刷新提示以重新提交表单(我认为符合预期)

【讨论】:

  • 谢谢布兰登。这很有帮助,尽管我仍然不关心默认功能。我想我会尽可能地使用 javascript 验证来避免它。
【解决方案2】:

我知道这是一个老问题,但我最近一直在使用的一种方法是使用 AJAX 提交表单,即使它不需要它。这使您可以将其提交到路由的默认创建/更新操作,但浏览器中的 URL 不会更改。响应可以是简单的 200 表示成功,带有指向 /index 页面的链接或您在成功保存时重定向到的任何位置,或者如果数据无效,则可以是带有错误消息的“400 bad request”。

最大的缺点是错误消息和无效字段的显示现在完全由您的客户端 JavaScript 负责。这变成了一个小得多的问题,一旦您在客户端使用 Backbone 或 KnockoutJS 之类的东西,它甚至可能是一件好事。

【讨论】:

    猜你喜欢
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多