Reputation: 6408
I am having a problem with restful routes and singular resources, originally I had this code in the show view on my account resource.
<%= link_to book.title, book_path(:search => book.title) %>
and it worked fine, then I changed account to be a singular resource, e.g
from
map.resources :accounts
to
map.resource :account
and now I get the error ...
book_url failed to generate from {:search=>"Dracula", :controller=>"books", :action=>"show"}, expected: {:controller=>"books", :action=>"show"}, diff: {:search=>"Dracula"}
remove the view line of code, and everything works fine. Also changing it to
<%= link_to book.title, :controller => "books", :action => "show", :search => book.title %>
makes it work.
I have created a standalone rails application demonstrate my problem in isolation http://github.com/jowls/singular_resource_bug
Is this a bug? brought about through some combination of singular resources and restful routes?
This was on rails 2.3.10
thanks
Upvotes: 3
Views: 1049
Reputation: 385
The account singleton resource is a red herring. Your problem is just that you're missing the :id
parameter of books_url (which is always the first argument). You can pass in additional arguments like so:
book_url(book, :search => 'Dracula') # book.id would also work here
But there must be a book. That's just how Rails's resource routes work.
It's strange if this worked before, because you should have been getting this error on your books
resource the whole time.
An easy way to refactor your code to work around this would be to add a line to your controller's show action:
class BooksController < ActionController::Base
def show
# If :search is blank, populate it with :id's value
params[:search] ||= params[:id]
# your code ...
end
end
Then just pass the search/title string in as the first argument to book_url
/book_path
:
# "Dracula" will be passed to your controller as params[:id]
book_path("Dracula")
Alternatively you can override the default/generated route like this:
map.resources :books
# Explicit named routes take precedence over generated ones
map.book '/books/:search', :controller => 'books', :action => 'show'
One caution against the latter idea is that it prevents you from using an :id parameter instead—it makes :search the default REST identifier, so if you tried using :id you'd have your original error, just with a different param.
I've tested these solutions in the example app you posted and they all seem to work.
Upvotes: 3