views:

258

answers:

2

I'm trying to create a simple search form in Rails, but I think I'm missing something.

I have a named route for search:

map.search ":first_name/:last_name", :controller => "home", :action => "search"

I'm trying to use that in my search form:

<% form_tag(search_path, :method => 'get') do %>
  <%= text_field_tag(:first_name) %>
  <%= text_field_tag(:last_name) %>
  <%= submit_tag("Search") %>
<% end %>

But when I load up the search form I get an ActionController::RoutingError:

search_url failed to generate from {:action=>"search", :controller=>"home"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: [:first_name, :last_name] - are they all satisfied?

What am I missing? I thought the fields defined in my form would be automatically linked up with my route parameters. :-/

Update:

I understand that search_path is generated before the form is displayed now, so it can't be updated. Obvious in hindsight!

I changed my routes:

map.search 'search', :controller => "home", :action => "search"
map.name ':first_name/:last_name', :controller => "home", :action => "name"

And now the search action just does:

def search
  redirect_to name_path(params)
end

It all works a treat! The main goal here was getting that URL from the name named route as result of doing a search. Thanks guys!

+2  A: 

First, search_path is actually a method, which takes a hash of options. It is this method which should receive :first_name and :last_name.

Second, a browser can only submit form parameters as the body of a POST request, or as query string parameters (for any kind of request method). So there's unfortunately no way a browser's native submit function can generate that kind of URL.

Another way of thinking of it: What you're doing here is filling the form tag's action attribute with an URL. Rails needs a complete URL as you're building the form. So all parameters in your route need to be specified when the form helper is called, rather than at the next POST request.

So unfortunately, what you're trying to do is not possible in a normal Rails application.

(If you really want to, you might be able to pull it off by writing your own form helpers and a bit of Javascript to replace the browser's native submit function. The Javascript would then construct that URL based on the form fields. I'd argue against it, though.)

Shtééf
It's entirely possible for an HTML form to submit HTTP GET parameters. Take a look at the URL when you search Google, for example.
John Topley
But what he's trying to do are not *query string* parameters, they're part of the URL's path.
Shtééf
Sorry, I misread the question.
John Topley
+1  A: 

form_for generates form and it has to have specified all parameters that are needed to create search_path, so it should look like:

<% form_tag(search_path, :firstname => 'some_text', :lastname => 'some_text', :method => 'get') do %>

or at least something like this. HTML tag form has parameter action='/some/url' and that's why you have to specify all parameters for search_path. But the above example won't work as you expected.

So what you can do?

  1. Create empty form that has action='/' and with js replace it with content of your input text fields before submitting.

  2. Create another route, on example /search that recives parameters from submit and then redirects to correct path.

Probably there is also some better ways to do it ;)

klew
I just got it working with your option #2 -- I created another route and another action. Thanks!
Stewart Johnson
Probably it would be better to do it both ways. So do it 2. way on default and if js is working then change `action` with js - so it can work without redirecting.
klew