【问题标题】:How do I create a Rails form that submits to a RESTful action?如何创建提交到 RESTful 操作的 Rails 表单?
【发布时间】:2018-01-29 19:38:28
【问题描述】:

使用 Rails 5,我如何创建提交到 RESTful 操作的表单?

在我的路线文件中,我有:

  resources :people do
    collection do
      get 'image/:id', :to => "people#image", :as => 'image'
      get 'ranks', :to => "people#ranks", :as => 'ranks'
      get 'search/:search(.:format)', to: 'people#search'
    end
  end

所以我想知道如何构造一个提交给“搜索”操作的表单。

我尝试了以下方法:

<%= form_tag(people_search_path) do %>
  <%= text_field_tag :search %>
  <%= submit_tag 'Search' %>
<% end %>

但这会导致以下错误:

undefined local variable or method `people_search_path' for #<#<Class:0x00007ff2afc59168>:0x00007ff2afc50f68>

【问题讨论】:

    标签: ruby-on-rails forms rest routes ruby-on-rails-5


    【解决方案1】:

    如果您执行rake routes,您会看到您的搜索路径没有名称:

    image_people GET    /people/image/:id(.:format)        people#image
    ranks_people GET    /people/ranks(.:format)            people#ranks
                 GET    /people/search/:search(.:format)   people#search
          people GET    /people(.:format)                  people#index
                 POST   /people(.:format)                  people#create
      new_person GET    /people/new(.:format)              people#new
     edit_person GET    /people/:id/edit(.:format)         people#edit
          person GET    /people/:id(.:format)              people#show
                 PATCH  /people/:id(.:format)              people#update
                 PUT    /people/:id(.:format)              people#update
                 DELETE /people/:id(.:format)              people#destroy
    

    如果你这样做:

    resources :people do
      collection do
        get  'image/:id', :to => "people#image", :as => 'image'
        get  'ranks', :to => "people#ranks", :as => 'ranks'
        get  'search/:search(.:format)', to: 'people#search', as: :search
      end
    end
    

    您会看到您的路径现在有了一个名称:

      image_people GET    /people/image/:id(.:format)         people#image
      ranks_people GET    /people/ranks(.:format)             people#ranks
     search_people GET    /people/search/:search(.:format)    people#search
            people GET    /people(.:format)                   people#index
                   POST   /people(.:format)                   people#create
        new_person GET    /people/new(.:format)               people#new
       edit_person GET    /people/:id/edit(.:format)          people#edit
            person GET    /people/:id(.:format)               people#show
                   PATCH  /people/:id(.:format)               people#update
                   PUT    /people/:id(.:format)               people#update
                   DELETE /people/:id(.:format)               people#destroy
    

    您可以将其用作search_people_path。

    顺便说一句,我认为(.:format) 位是不必要的,您可以简单地这样做:

    post 'search/:search', to: 'people#search', as: :search
    

    如果我是你,我会这样做:

    resources :people do
      collection do
        get  'image/:id', :to => "people#image", :as => 'image'
        get  'ranks', :to => "people#ranks", :as => 'ranks'
        get  :search, to: 'people#search', as: :search
      end
    end
    

    这会给你:

      image_people GET    /people/image/:id(.:format)         people#image
      ranks_people GET    /people/ranks(.:format)             people#ranks
     search_people GET    /people/search(.:format)            people#search
            people GET    /people(.:format)                   people#index
                   POST   /people(.:format)                   people#create
        new_person GET    /people/new(.:format)               people#new
       edit_person GET    /people/:id/edit(.:format)          people#edit
            person GET    /people/:id(.:format)               people#show
                   PATCH  /people/:id(.:format)               people#update
                   PUT    /people/:id(.:format)               people#update
                   DELETE /people/:id(.:format)               people#destroy
    

    然后,我会按照 Anees Muhammed 的建议更新您的表单(我使用 :terms 而不是 :search):

    <%= form_tag search_people_path, method: :get do %>
      <%= text_field_tag :terms %>
      <%= submit_tag 'Search' %>
    <% end %>
    

    然后,当你提交时,你应该得到类似的东西:

    Started GET "/people/search?terms=foo" for ::1 at 2018-01-29 13:49:40 -0800
    Processing by People#search as HTML
      Parameters: {"utf8"=>"✓", "terms"=>"foo", "commit"=>"Search"}
    

    您可以通过params[:terms] 访问您的条款。

    顺便说一句,没有关于此的“非 RESTful”。 IMO 完全一致 the Guide 添加 RESTful 操作。

    【讨论】:

    • 为了让它工作,我需要将我的表单更改为“”吗?当我这样做并提交表单时,我猜答案是否定的 b/c 我收到错误消息“没有路线匹配 [POST]“/people/search/abc”。
    • 更新为使用POST 动词。以前,您使用的是 GET 动词,这就是您收到 "No route matches [POST] ..." 消息的原因。
    • 谢谢,但我希望将其保留为“GET”提交,以便人们可以通过电子邮件发送链接。我在我的表单标签中添加了一个“,方法::get”,正如我对另一个答案的评论所揭示的那样,当我提交我的表单时,它添加了“&search=str”而不是作为 RESTful 操作提交(例如 /搜索/str)
    • 我明白你在说什么,以及为什么你会得到你正在得到的行为。但是,IMO,你试图做的事情违背了惯例。 可能有一种方法,但我建议您采用更传统的方法,通过查询字符串访问您的搜索字词,正如另一个答案所暗示的那样。
    • 好的,谢谢。我想尽可能地使用约定。我仍然对为什么人们使用诸如“/path/param_value”而不是“/path?param=param_value”之类的 RESTful URL 感到困惑。
    【解决方案2】:

    您应该使用search_people_path 而不是people_search_path。但我不认为这种改变会让你达到你想要达到的目标。由于您的路线是
    get 'search/:search(.:format)', to: 'people#search'
    ,rails 会期望您为关键字 :search 提供一个值,以使用类似 search_people_path(yoursearchterm) 的内容构建一个类似 /people/search/yoursearchterm 的 URL。为了使您的功能正常工作,请将表单更改为

    <%= form_tag search_people_path, method: :get do %>
      <%= text_field_tag :search %>
      <%= submit_tag 'Search' %>
    <% end %>
    

    然后在您的控制器中

    def search
      params[:search]
    end
    


    还有前往

    的路线
    get 'search', to: 'people#search'
    

    更新

    由于您尝试将表单直接提交到 search/:search 这样的休息路线,我相信没有直接的 rails 方法可以实现相同的目标,因为这就是表单的工作方式。但是,如果您在提交表单时只想要一条像yourwebsite.com/search/yoursearchterm 这样的休息路线,那么有一些解决方法可以实现这一点。要么您必须在提交表单时写一段 js 并将请求转发到您的带有输入值的路由,或者您可以在控制器中执行重定向到路由,如下所示。
    路线:

    resources :people do
        collection do
          get 'search', to: 'people#search_people'
          get 'search/:search', to: 'people#search'
        end
      end
    

    因此,首先将表单提交到search_people 操作,然后重定向到使用参数进行搜索。在控制器中

    def search_people
        redirect_to search_people_path(params[:search])
    end
    

    这将为您提供一个 URL yoursite.com/people/search/searchterm,然后在您的 search 操作中,您可以使用搜索参数。

    希望这会有所帮助。

    【讨论】:

    • 谢谢,但这不是很有效。当我根据您的建议更改内容并在我的搜索表单中输入“spo”时,它会提交到 URL“localhost:3000/people/search/…”。在后端,“sss”仍被用作搜索参数的值,而不是我在文本框中输入的“spo”。
    • 嗨,@Natalia。我已经更新了答案。如果有什么我可以帮助你的,请告诉我。谢谢
    猜你喜欢
    • 1970-01-01
    • 2017-04-05
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-03
    • 1970-01-01
    • 2013-09-12
    相关资源
    最近更新 更多