I'm having some trouble with using creating my own actions inside a controller I generated using the scaffold.
I understand everything maps to the restful actions but I'm building a user controller where users can login/logout, etc but when I created the action and declared it in the routes.rb I get this error when I visit users/login
Couldn't find User with id=login
It tries to use login as a ID parameter instead of using it as an action.
Routes.rb
match 'users/login' => 'users#login'
I think I'm doing something wrong with the routes so if anybody could help me that would be great.
Thanks
I assume your routes.rb looks like this:
resources :users
match 'users/login' => 'users#login'
The problem is that Rails uses the first route that matches. From the documentation:
Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action’s route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.
So either define your custom route before resources :users:
match 'users/login' => 'users#login'
resources :users
…or use this syntax for adding more RESTful actions:
resources :users do
collection do
match 'login'
end
end
To see the existing routes (and their order) run rake routes from the command line.
Related
I am creating a custom route like:
namespace :admin do
root 'users#index'
resources :users do
get 'admin_login' => 'users#admin_login'
end
end
But when I see with rake routes:
admin_user_admin_login GET /admin/users/:user_id/admin_login(.:format) admin/users#admin_login
Why :user_id is added here?
I just want it without :user_id.
Because you are creating a custom route within the users resource. Rails is doing exactly what you are telling it to do. You would like to show the "admin_login" route for a specified user (that's what you're currently telling rails to do).
Move the:
get 'admin_login' => 'users#admin_login'
Line of code outside of the resources block and you'll be able to create your custom route.
You need to specify an on option to tell Rails that it works on a collection and not a member resource. According to the official Rails routing guide
You can leave out the :on option, this will create the same member
route except that the resource id value will be available in
params[:photo_id] instead of params[:id].
You can also remove the => 'users#admin_login' part as that is the default behavior.
So the solution to your problem is to add on: :collection or place it inside a block like
namespace :admin do
root 'users#index'
resources :users do
collection do
get 'admin_login'
end
end
end
Feel like I'm doing this right, but apparently not.
I have a restful resource, Posts, with index, show, new, update, edit, etc actions in the controller. In routes, I have
resources :posts
I wanted to make the index action occur at the URL '/archive' instead of '/posts'
So I added this line in the routes.rb file, after the resources one:
match '/archive', to: "posts#index"
But when I click on a link to posts_path, it still goes to /post (though if I type in /archive as a url, it works -- not ideal, though). Confused. Could this have to do with my having installed friendly_id?
resources :posts, except: [:index]
get 'archive' => 'posts#index', as: :posts
You need to use something like match '/archive', :to => 'posts#index', :as => 'archived'. Then you will have a new route to the tune of archived_posts_path. The method posts_path does not dynamically changed based on custom matchers. You can always run rake routes to see a list of routes for your site.
I have created a route in the routes.rb file like this:
match ':controller/:action/:id'
I tried invoking add_posts_path() and add_post_path() from my view and in both cases I got similar error messages like this one:
undefined method `add_post_path' for ...
I have tried declaring my match route both before and after the resources :posts declaration.
Are any route helpers created for such a route? I am unsure what helper methods can be used with such a match rule.
You can name routes with :as parameter
match '/foo/bar', to: 'foo#bar', as: 'foo_bar'
and then use foo_bar_path in your view
http://guides.rubyonrails.org/routing.html#naming-routes
If you have resources :posts, you have a helper new_post_path to add new posts. Run rake routes to see your apps routes.
add_post_path does't follow Rails routes convention for resources and if you need it, must add a custom method:
resources :posts do
get :add, :on => :collection
end
You can read more about this in this Rails guide.
When you define match ':controller/:action/:id', you set the format of your app's urls and their params, but this do not magically will define routes helpers.
I'm new with RoR so this is a newbie question:
if I have a controller users_controller.rb and I add a method foo, shouldn't it create this route?
http://www.localhost:3000/users/foo
because when I did that, I got this error:
Couldn't find User with id=foo
I of course added a view foo.html.erb
EDIT:
I added to routes.rb this code but I get the same error:
resources :users do
get "signup"
end
This doesn't work automatically in rails 3. You'll need to add
resource :users do
get "foo"
end
to your routes.rb
You'll definitely want to have a look at http://guides.rubyonrails.org/routing.html, it explains routing pretty well.
Rails is directing you to the show controller and thinks that you're providing foo as :id param to the show action.
You need to set a route that will be dispatched prior to being matched as /users/:id in users#show
You can accomplish this by modifying config/routes.rb by adding the following to replace your existing resource describing :users
resource :users do
get "foo"
end
Just to add to the other answers, in earlier versions of Rails there used to be a default route
match ':controller(/:action(/:id))(.:format)'
which gave the behaviour you describe where a request of the form controller/action would call the given method on the given controller. This line is still in routes.rb but is commented out by default. You can uncomment it to enable this behaviour but the comment above it explains why this is not recommended:
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
At the schema ':controller/:action(.:format)', you can also easily do the following
resources :users do
get "foo", on: :collection
end
or
resources :users do
collection do
get 'foo'
end
end
http://guides.rubyonrails.org/routing.html#adding-collection-routes
My homecontroller has:
def about()
end
And I have a rspec test that does GET 'about' and it fails saying that there is no route that matches.
doesn't this map all actions in the controller:
resources :home
or do I have to explicitly state each action in the home controller?
resources :home sets up the default RESTful routes - index, show, new, create, edit, update, and destroy. Any additional routes have to be specified. It looks like you're adding a simple collection route, so you'd specify it like this:
resources :home
collection do
get 'about'
end
end
This will give your the route '/home/about'. I assume this is Rails 3. If you're in Rails 2.x, do it like so:
map.resources :home, :collection => {:about => :get}
And from the command line, you can always see what routes you have available with this command:
rake routes
I hope this helps!
EDIT: If you want a default route, you can add this:
match ':controller(/:action(/:id))'
This is a default route that will match any generic requests.
FULL ARTICLE: Routing in Rails 3 is its own beast. There have been a lot of questions about it lately, so I've created a very detailed article with code samples to help others:
Routing in Ruby on Rails 3
I created a companion Rails 3 app that can be downloaded to play around with, as well:
https://github.com/kconrails/rails3_routing
If you have any questions, please hit up my site and ask. Thanks!
resources will give you the 7 CRUD methods for a controller, if you want additional actions, you need to do something like the following:
resources :homes do
collection do
match "about" => "homes#about", :as => "about"
end
end
Then you'll also have an additional about_homes_path/url helper available.