在Rails中处理无效表单提交的正确方法

时间:2011-02-18 22:10:07

标签: ruby-on-rails-3

我是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到/ thing的结果,但是用户界面方面,我并不特别关心它。

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

想法?

2 个答案:

答案 0 :(得分:3)

正如您所发现的,默认情况下,当您指定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. 网址从/things/new更改为/things
  2. 点击提示重新提交表单
  3. 刷新显示things#index
  4. 这是我在自己的Rails 3应用程序中遇到的功能。相反,我发现:提交新的thing(在/things/new提交表单)后,

    1. 网址从/things/new更改为/things(这是相同的)
    2. 点击返回会将用户带回 - 提交的表单(无请求重新发布)
    3. 刷新提示重新提交表单(我认为正如预期的那样)

答案 1 :(得分:0)

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

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