Eric Hu
Eric Hu

Reputation: 18208

Specifying order of resources

I'm trying to add a path to my application. I have code that functions as I'd like, but I'd like to group it differently so that it's more intuitive to read. Here's the code:

get 'posts/search' => 'posts#search',
  :as => :search_posts

put 'posts/search_result' => 'posts#search_result',
  :as => :search_posts_result

resources :posts do

end

but I'd like to do something like this:

resources :posts do
  get 'posts/search' => 'posts#search',
    :as => :search_posts

  put 'posts/search_result' => 'posts#search_result',
    :as => :search_posts_result
end

It's a really small difference, but doing it the latter way defines runs resources :posts first. As a result, Rails tries to match /posts/search to /posts/:id (for show) and gives an error as it can't find a post with id 'search'. Is there a way I can tell rails to run the get and put definitions before running resources :posts?

Upvotes: 0

Views: 123

Answers (2)

coreyward
coreyward

Reputation: 80051

The reason your routes aren't working is because they are defined on each member of posts, so /posts/1/posts/search. You should run rake routes to check where your routes are going.

To fix your problem, you would probably want to fix those route paths and make sure you're defining the search route on the entire collection. If this is confusing, check the guide.

resources :posts do
  get :search, :on => :collection
end

You don't need all that other stuff you had, either. This will create all of the following routes for you:

search_posts GET    /posts/search(.:format)    {:action=>"search", :controller=>"posts"}
       posts GET    /posts(.:format)           {:action=>"index", :controller=>"posts"}
             POST   /posts(.:format)           {:action=>"create", :controller=>"posts"}
    new_post GET    /posts/new(.:format)       {:action=>"new", :controller=>"posts"}
   edit_post GET    /posts/:id/edit(.:format)  {:action=>"edit", :controller=>"posts"}
        post GET    /posts/:id(.:format)       {:action=>"show", :controller=>"posts"}
             PUT    /posts/:id(.:format)       {:action=>"update", :controller=>"posts"}
             DELETE /posts/:id(.:format)       {:action=>"destroy", :controller=>"posts"}

Rails defines the routes on the entire collection before the default resourceful routes (as you can see above) so that your routes take precedence.

And as far as your PUT posts#search_result method, well, that's really confusing — you want to update a search result manually?


Per the comments: I'd recommend something like this instead of having a separate action for search results. Typically a search page looks the same with or without results, except the error message if you do a search and nothing turns up. Gracefully handling the case that a search page is shown without a query being present lets you nix a redundant action.

def search
  @query == params[:q] || ''

  # search logic

  flash[:error] = 'Nothing found message' if @results.empty? unless @query.blank?
end

Upvotes: 1

Dinatih
Dinatih

Reputation: 2476

resources :posts do
  collection do
    get :search, :as => :search_posts
    put :search_result, :as => :search_posts_result
  end 
end

Upvotes: 1

Related Questions