This project is archived and is in readonly mode.
assert_generates expects unexpected generated_path
Reported by Frederik Vollert | September 23rd, 2010 @ 12:17 PM
The following difficulty concerning assert_generates (defined in actionpack-3.0.0/lib/action_dispatch/testing/assertions/routing.rb:94) occured while using RSpec2 and was discussed as "ruby-related issue" in November '09 (https://rspec.lighthouseapp.com/projects/5645/tickets/907-the-gener....
Perhaps this is not a malfunction, but a misunderstanding of the usage of this assertion as illustrated in http://apidock.com/rails/v3.0.0/ActionDispatch/Assertions/RoutingAs... .
Given I have set up the following routes in Rails 3.0.0 (Ruby 1.9.2):
MyApp::Application.routes.draw do
match 'logout1' => 'user_sessions#destroy', :as => 'logout1'
match 'logout2' => 'user_sessions#destroy', :as => 'logout2'
match 'logout3' => 'user_sessions#destroy'
match 'login' => 'user_sessions#new', :as => 'login'
resources :user_sessions
end
The following assertions (excerpt from routing spec) ...
assert_generates "/logout1", :controller => "user_sessions", :action => "new"
assert_generates "/logout2", :controller => "user_sessions", :action => "new"
assert_generates "/logout3", :controller => "user_sessions", :action => "new"
assert_generates "/login", :controller => "user_sessions", :action => "new"
... used e.g. in RSpec produce the following results:
Failures:
1) General routing recognizes /logout2
Failure/Error: { :get => "/logout2" }.should route_to(:controller => "user_sessions", :action => "destroy")
The generated path <"/logout1"> did not match <"/logout2">.
2) General routing recognizes /logout3
Failure/Error: { :get => "/logout3" }.should route_to(:controller => "user_sessions", :action => "destroy")
The generated path <"/logout1"> did not match <"/logout3">.
3) General routing recognizes /login
Failure/Error: { :get => "/login" }.should route_to(:controller => "user_sessions", :action => "new")
The generated path <"/user_sessions/new"> did not match <"/login">.
The first named route is accepted as generated_path and expected_path both have the value "/logout1". The following two are not recognized, but work fine as does the "login"-route.
In [...]action_dispatch/testing/assertions/routing.rb:86 @routes.generate_extras seems to return the "unexpected" route.
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
if expected_path =~ %r{://}
begin
uri = URI.parse(expected_path)
expected_path = uri.path.to_s.empty? ? "/" : uri.path
rescue URI::InvalidURIError => e
raise ActionController::RoutingError, e.message
end
else
expected_path = "/#{expected_path}" unless expected_path.first == '/'
end
# Load routes.rb if it hasn't been loaded.
generated_path, extra_keys = @routes.generate_extras(options, defaults)
found_extras = options.reject {|k, v| ! extra_keys.include? k}
msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
assert_block(msg) { found_extras == extras }
msg = build_message(message, "The generated path <?> did not match <?>", generated_path,
expected_path)
assert_block(msg) { expected_path == generated_path }
end
Though they are all four existing as in "rake routes":
logout1 /logout1(.:format) {:action=>"destroy", :controller=>"user_sessions"}
logout2 /logout2(.:format) {:action=>"destroy", :controller=>"user_sessions"}
logout3 /logout3(.:format) {:action=>"destroy", :controller=>"user_sessions"}
login /login(.:format) {:action=>"new", :controller=>"user_sessions"}
[...]
user_sessions GET /user_sessions(.:format) {:action=>"index", :controller=>"user_sessions"}
user_sessions POST /user_sessions(.:format) {:action=>"create", :controller=>"user_sessions"}
new_user_session GET /user_sessions/new(.:format) {:action=>"new", :controller=>"user_sessions"}
edit_user_session GET /user_sessions/:id/edit(.:format) {:action=>"edit", :controller=>"user_sessions"}
user_session GET /user_sessions/:id(.:format) {:action=>"show", :controller=>"user_sessions"}
user_session PUT /user_sessions/:id(.:format) {:action=>"update", :controller=>"user_sessions"}
user_session DELETE /user_sessions/:id(.:format) {:action=>"destroy", :controller=>"user_sessions"}
I haven't found a ticket concerning assert_generates and saw that Josh worked on this bit of code, so I figured to create a ticket to clarify this issue.
Comments and changes to this ticket
-
Frederik Vollert September 23rd, 2010 @ 12:18 PM
- Tag changed from routing assert_generates, generate_extras to routing assert_generates, generate_extras, rails3.0.0
-
Andrew White September 23rd, 2010 @ 02:16 PM
- State changed from new to invalid
- Assigned user cleared.
- Importance changed from to Low
The assert_generate code tries to generate a url from a set of options - in your case these options are the same so it always generates the first logout route. In the login case the get method constraint of the /user_sessions/new path provides a more specific match so overrides the the /login route.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>