Are default routes broken with Rails 3 engines? - ruby-on-rails

I have a Rails 3 engine gem that is for basic user authentication and authorization. Within that Gem the config/routes.rb defines the following
resources :users
match '/:controller(/:action(/:id))'
When I do a rake routes from the application that requires this gem I get the following routes
rake routes|grep users
users GET /users(.:format) {:controller=>"users", :action=>"index"}
users POST /users(.:format) {:controller=>"users", :action=>"create"}
new_user GET /users/new(.:format) {:controller=>"users", :action=>"new"}
edit_user GET /users/:id/edit(.:format) {:controller=>"users", :action=>"edit"}
user GET /users/:id(.:format) {:controller=>"users", :action=>"show"}
user PUT /users/:id(.:format) {:controller=>"users", :action=>"update"}
user DELETE /users/:id(.:format) {:controller=>"users", :action=>"destroy"}
This is what I expect.
However when I try to access the following routes via a browser
/users/137
/users/137/edit
I get the following error in the logs
AbstractController::ActionNotFound (The action '137' could not be found for UsersController):
actionpack (3.0.0) lib/abstract_controller/base.rb:114:in `process'
actionpack (3.0.0) lib/abstract_controller/rendering.rb:40:in `process'
...
What is interesting is that the following paths do work
/users/show/137
/users/edit/137
Also if I add the following to the routes.rb file in the application that is requiring the gem it all works as expected.
resources :users
Is there something I am missing or is this a bug?
Note that I am also doing the following when I start my application
on the command line when I start the rails I set the following env variable
RAILS_RELATIVE_URL_ROOT="/my_app"
and in config.ru
map '/my_app' do
run MSEL::Application
end

I experienced the same thing with a gem that I was creating. The engine routes are loaded after the application routes and I think this may be your problem. Take a look at rake routes without grepping for user. I suspect that you have a route in your application that takes precedence over the user routes. If you have match '/:controller(/:action(/:id))' in your application routes, then this will take precedence over the gem user route. Might explain why /users/show/137 works and not the RESTful routes. It may be possible to load your routes in the engine initializer to take precedence over the application routes. Post your full rake routes results and that may help us find a solution.

For me in Rails 3.1
root :to => 'ControllerName#Action'
Worked properly.

Related

User Resources Expanded

In order to more clearly understand exactly what "resources" is doing in the Ruby on Rails routes.rb file, I want to write under it the exact code it is replacing.
When I run rake routes I get this:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
Can someone help me fill in the blanks below so I can understand this more clearly:
resources 'users'
# get 'users' => 'users#index"
# post ...
# get ...
# get ...
# patch ...
# put ...
# delete ...
The equivalent code could be expressed as:
get 'users', to: 'users#index'
post 'users', to: 'users#create'
get 'users/new', to: 'users#new', as: 'new_user'
get 'users/:id/edit', to: 'users#edit', as: 'edit_user'
get 'users/:id', to: 'users#show', as: 'user'
patch 'users/:id', to: 'users#update'
put 'users/:id', to: 'users#update'
delete 'users/:id', to: 'users#destroy'
Brad werths answer is what you need.
To give you some more context, you also need to appreciate how the resourceful routing system works in Rails...
Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code.
Basically, each time you call resources, you're telling rails to build a set of routes for a controller designed around the "resourceful" principle.
"Resourceful" actions through the Internet are defined by wikipedia as follows:
HTTP functions as a request-response protocol in the client-server computing model. A web browser, for example, may be the client and an application running on a computer hosting a web site may be the server. The client submits an HTTP request message to the server. The server, which provides resources such as HTML files and other content, or performs other functions on behalf of the client, returns a response message to the client. The response contains completion status information about the request and may also contain requested content in its message body.
All of this make sense when you understand that Ruby/Rails is object orientated. This means everything you do in your application has to resolve around the initialization & maintenance of "objects".
Objects are basically your models - they are created, edited and destroyed (CRUD -- create read update destroy) with your controller actions. Therefore, to give you a set of standardized routes, you'll be able to use the following:
If you want to see your routes like how brad has outlined, you'll want to run rake routes
--
Good resource here: https://softwareengineering.stackexchange.com/questions/120716/difference-between-rest-and-crud

Routes stopped working when upgrading Rails 3.0 to 3.1

I am using Ruby 1.8.7 with Rails 3.1. My application worked fine in Rails 3.0 but when I bumped it up to Rails 3.1.4, all my url helpers broke!
After Googling like a mad man the past 2 days, I have given up and the time has come to seek help. I don't believe the problem is with my routes.rb file but something more on the view/helper side.
I have the following in my routes.rb:
resources :sessions
In my homepage view I have the following link_to, which errors out:
<%= link_to "Login", new_session_path %>
When I do rake routes, I get the following output, so the path exists:
sessions GET /sessions(.:format) {:controller=>"sessions", :action=>"index"}
POST /sessions(.:format) {:controller=>"sessions", :action=>"create"}
new_session GET /sessions/new(.:format) {:controller=>"sessions", :action=>"new"}
edit_session GET /sessions/:id/edit(.:format) {:controller=>"sessions", :action=>"edit"}
session GET /sessions/:id(.:format) {:controller=>"sessions", :action=>"show"}
PUT /sessions/:id(.:format) {:controller=>"sessions", :action=>"update"}
DELETE /sessions/:id(.:format) {:controller=>"sessions", :action=>"destroy"}
When I go to /sessions/new in my browser, the page loads so again, the route exists, but it errors out on a _path based url:
<%= form_tag sessions_path, :method => :post do -%>
The error I get is as follows:
ActionView::Template::Error (undefined local variable or method `sessions_path' for #<#<Class:0x109cb8900>:0x109cab840>):
It has to be something with the url_for helper as the routes do exist. What else should I look for?
UPDATE 1:
I added the following inside application_helper.rb:
include Rails.application.routes.url_helpers
Now when I get the following error:
In order to use #url_for, you must include routing helpers explicitly. For instance, `include Rails.application.routes.url_helpers
Isn't that is what I just did?
Update 2:
The following worked as MrYoshiji suggested:
Rails.application.routes.url_helpers.sessions_path
Update 3:
I got sessions_path working again by removing some old Rails 2 plugins in vendor directory.
Removed some Rails 2 plugins in vendor/plugins did the trick.

difference between resource and controller generators

when I do
rails g model user name:string
rails g controller users index create new destroy show
and edit config/routes.rb to add:
resource :users
bundle exec rake routes gives:
users POST /users(.:format) {:action=>"create", :controller=>"users"}
new_users GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_users GET /users/edit(.:format) {:action=>"edit", :controller=>"users"}
GET /users(.:format) {:action=>"show", :controller=>"users"}
PUT /users(.:format) {:action=>"update", :controller=>"users"}
DELETE /users(.:format) {:action=>"destroy", :controller=>"users"}
however, when I do
rails g resource users name:string
(which automatically adds resources :users to config/routes.rb)
bundle exec rake routes
I get
users GET /users(.:format) {:action=>"index", :controller=>"users"}
POST /users(.:format) {:action=>"create", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"}
So my question is,
when I generate a controller how can I get the correct helper methods to make
link_to 'Destroy', instance, :method=> :delete
work?
Because currently it gives an error user_path is not defined.
You should call
rails g controller user index create new destroy show
instead of
rails g controller users index create new destroy show
in order to get resources :users to give you the helpers you want.
The latter causes Rails to assume that users is a singular object, and that resources :users should create what is called a singular resource:
http://guides.rubyonrails.org/routing.html#singular-resources
as a result, user_path is undefined, whereas users_path is defined.
When you use rails g controller and specify the method names, the generator only maps specific routes to the routes file. rails g resource assumes that you want the whole resource functionality and will map resources.
In order to fix this, just go into your routes file and replace the specific mappings with a resources call.
resources :users
What I really wanted was a way of creating a working (with correct delete/show paths) controller for an existing model (as described in the question) but just adding "resource :x" and generating the controller wasn't enough.
I ended up using the scaffold_controller generator. It doesn't create any migrations or models, but it does generate a resource with views and rake paths command shows the correct paths for delete and show to work.
You can run following commands in the console:
$rails g model user name:string
$rails g scaffold_controller User
And add this code line to the file routes.rb:
resources :users

Rails namespaced routes work in development but not production

I'm trying to nest some routes under the namespace, account.
I want user management under account like /account/users and /account/users/5/edit
In routes.rb:
namespace :account do
resources :users do
member do
put 'generate_api_key'
end
collection do
post 'api_key'
end
end
end
My controllers are not namespaced or put them in any different directory.
/app
/controllers
accounts_controller.rb
users_controller.rb
In my development environment this is working fine, but in production I get 404 responses to any of the /account/users... paths (which, by the way, are all still generated correctly: new_account_users_path, edit_account_user_path, etc).
rake routes generates the same output in both environments. Here is the relevant bit:
generate_api_key_account_user PUT /account/users/:id/generate_api_key(.:format) {:action=>"generate_api_key", :controller=>"account/users"}
api_key_account_users POST /account/users/api_key(.:format) {:action=>"api_key", :controller=>"account/users"}
account_users GET /account/users(.:format) {:action=>"index", :controller=>"account/users"}
POST /account/users(.:format) {:action=>"create", :controller=>"account/users"}
new_account_user GET /account/users/new(.:format) {:action=>"new", :controller=>"account/users"}
edit_account_user GET /account/users/:id/edit(.:format) {:action=>"edit", :controller=>"account/users"}
account_user GET /account/users/:id(.:format) {:action=>"show", :controller=>"account/users"}
PUT /account/users/:id(.:format) {:action=>"update", :controller=>"account/users"}
DELETE /account/users/:id(.:format) {:action=>"destroy", :controller=>"account/users"}
Given that the routes seem to look for the Users controller in the /account subdirectory, I suppose my question is why does this work in development?
Production is:
Rails 3.0.7
Passenger
Apache
Development is:
Rails 3.0.7
Mongrel
Thanks for your thoughts on this one.
If you're namespacing like this, Rails requires the controllers to be at their correct paths, such as app/controllers/account/users_controller.rb. If you don't want to do this, then use scope instead:
scope :path => "account" do
resources :users
end

Rails resourceful routes all point to index action?

I'm runnng Rails 2.3.8.
I set up map.resources :users in my routes.rb file.
When I run rake routes it shows:
users GET /users(.:format) {:action=>"index", :controller=>"users"}
GET /users(.:format) {:action=>"index", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"index", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"index", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"index", :controller=>"users"}
GET /users/:id(.:format) {:action=>"index", :controller=>"users"}
GET /users/:id(.:format) {:action=>"index", :controller=>"users"}
/:controller/:action/:id
/:controller/:action/:id(.:format)
Sorry about the formatting. But the point is... 1) where are my "PUT", "POST", etc. routes?, 2) Why does everything point to index??
Any help would be much appreciated... Thanks!
UPDATE: Full routes file:
ActionController::Routing::Routes.draw do |map|
map.login "login", :controller => "user_sessions", :action => "new"
map.logout "logout", :controller => "user_sessions", :action => "destroy"
map.resources :users
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
And my users_controller has all the usual new, create, show, edit, update methods...
I think you have one of two problems: either the output from rake routes has been mangled by your terminal screen, or your routes are being overridden by something else you installed, like a rails engine.
The first is easy to check for. it sounds like you have a basic user scaffold setup (and not much else) so fire up script/server, go to http://localhost:3000/users/new. If you see the new user page, you have a terminal display issue, but your routes are fine. If you see the users index page, however, proceed to the next step.
Double-check that the routes file you posted above is indeed the file for your app. This sounds ridiculous, but in some editors it's easy to open the wrong file. In TextMate for example, if you have some gems vendored and open the routes file via command-T, you can have multiple routes.rb files to choose from.
If you're sure you're viewing the correct routes file, the next step is to check your application for any other routes.rb files that may be overriding your main file. From terminal, you can run find ./ -name routes.rb and this will list any other routes files. This is especially likely if you have any rails engines installed.
Let me know how this goes - if you're still having problems, you can zip your application and e-mail it to me, and I'll take a look.

Resources