Reputation:
With Rails 5, how do I create a form that submits to a RESTful action?
In my routes file I have:
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
So I'm wondering how to construct a form that submits to the "search" action.
I tried the following:
<%= form_tag(people_search_path) do %>
<%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
But this results in the following error:
undefined local variable or method `people_search_path' for #<#<Class:0x00007ff2afc59168>:0x00007ff2afc50f68>
Upvotes: 1
Views: 166
Reputation: 1850
You should use search_people_path
instead of people_search_path
. But I don't think that change will take you to what you are trying to achieve. Since your route is get 'search/:search(.:format)', to: 'people#search'
rails will expect you to provide a value for the keyword :search
to build a url like /people/search/yoursearchterm
with something like search_people_path(yoursearchterm)
. For your functionality to work, change the form to
<%= form_tag search_people_path, method: :get do %>
<%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
and then in your controller
def search
params[:search]
end
Also the routes to
get 'search', to: 'people#search'
Updated
Since you are trying to submit the form directly to a rest route like search/:search
, I believe there is no direct rails way to achieve the same because that's how forms work. But if all you want is just a rest route like yourwebsite.com/search/yoursearchterm
when you submit the form, there are some workarounds to achieve this. Either you have to write a piece of js
on submitting the form and forward the request to your route with the input value or you can perform a redirect in the controller to the route, like this.
Routes:
resources :people do
collection do
get 'search', to: 'people#search_people'
get 'search/:search', to: 'people#search'
end
end
So, first the form will be submitted to search_people
action and then redirect to search with params. In controller
def search_people
redirect_to search_people_path(params[:search])
end
This will then give you a url yoursite.com/people/search/searchterm
and then in your search
action, you can use the search params.
Hope this helps.
Upvotes: 0
Reputation: 20263
If you do rake routes
, you'll see that your search path has no name:
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
If, instead, you do:
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
You'll see your path now has a name:
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
Which you can use as search_people_path
.
BTW, I believe that (.:format)
bit is unnecessary and you can simply do:
post 'search/:search', to: 'people#search', as: :search
If I were you, however, I would do:
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
Which will give you:
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
Then, I would update your form as Anees Muhammed suggests (I used :terms
instead of :search
):
<%= form_tag search_people_path, method: :get do %>
<%= text_field_tag :terms %>
<%= submit_tag 'Search' %>
<% end %>
Then, when you submit, you should get something like:
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"}
And you can access your terms by doing params[:terms]
.
There is, BTW, nothing "non-RESTful" about this. It is, IMO, completely consistent the Guide for adding RESTful actions.
Upvotes: 2