tkrajcar
tkrajcar

Reputation: 1712

Rails POST forms to pretty URL

Having one of those 'I'm clearly doing something wrong' moments. It feels like I'm trying to do something basic, and fighting the framework, so I'm appealing for help!

I'm using Rails 3 and am a bit confused about how to make a search form that results in pages with clean URLs.

My application allows you to search from routes from any location to another location.

For example, a valid URL would be /routes/A/to/B/, or /routes/B

My routes.rb:

match 'routes/:from/to/:to' => 'finder#find', :as => :find
match 'routes/find' => 'finder#find'

My search form:

<% form_tag('/routes, :method => 'post') do %>
  <%= label_tag(:from, "From:") %>
  <%= text_field_tag(:from) %>
  <%= label_tag(:to, "To:") %>
  <%= text_field_tag(:to) %>
  <%= submit_tag("Go") %>
<% end %>

Controller:

class FinderController < ApplicationController
  def index
  end

  def find
    if params[:from].blank? or params[:to].blank?
      render :action => "invalid_results" and return
    end
    @from = Location.find_by_code(params[:from].upcase)
    @to = Location.find_by_code(params[:to].upcase)
    if @from.nil? or @to.nil?
      render :action => "invalid_results" and return
    end

    @routes = Route.find_all_by_from_location_id_and_to_location_id(@from, @to)

  end
end

When I use :method => 'get' in my form_tag, the application works, but the URL is hideous. And, of course, with :method => 'post', the variables are no longer visible which is bad for bookmarking. How do I tell Rails to use my pretty URLs after POSTing the form?

I am VERY new at Rails so your patience is appreciated.

Upvotes: 2

Views: 3707

Answers (1)

Dex
Dex

Reputation: 12749

Your routes are given an automatic named path that you can see by typing rake routes. For example:

new_flag GET    /flags/new(.:format)      {:action=>"new", :controller=>"flags"}

You can refer to the path by using new_flag_path or new_flag_url

Your form_tag entry is kinda screwy. Instead of having a separate find method you could also use the index method, but that's your choice.

You may find it easier to use a standard redirect_to to redirect to a prettier URL based on inputs. If you don't want the redirect, then you'll need to use jQuery to change your form's action method dynamically. Searches typically use ugly GET parameters.

So I would change your code to look like this:

routes.rb

get 'routes/:from/to/:to' => 'finder#routes', :as => :find_from_to
post 'routes/find' => 'finder#find', :as => :find

_form.html.erb

<% form_tag find_path, :method => :post do %>
  <%= label_tag(:from, "From:") %>
  <%= text_field_tag(:from) %>
  <%= label_tag(:to, "To:") %>
  <%= text_field_tag(:to) %>
  <%= submit_tag("Go") %>
<% end %>

finder_controller.rb

class FinderController < ApplicationController
  def index
  end

  def find
    if params[:from].blank? or params[:to].blank?
      render :action => "invalid_results" and return
    end
    @from = Location.find_by_code(params[:from].upcase)
    @to = Location.find_by_code(params[:to].upcase)
    if @from.nil? or @to.nil?
      render :action => "invalid_results" and return
    end

    redirect_to find_from_to_path(@from, @to)

  end

  def routes
     @routes = Route.find_all_by_from_location_id_and_to_location_id(params[:from], params[:to])
  end
end

Upvotes: 5

Related Questions