I have a standard User controller with the normal set of actions (index, show, new, edit, etc) and I'm trying to add a new action named 'profile'. I added the following code:
def profile
#user = User.find(session[:user_id])
end
I also created a new view for the action (app/views/users/profile.html.erb), but whenever I try to view that page I get an error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with ID=profile
...
Apparently it's hitting the show action. I'm guessing that means I need to add something to my routes to make this work, but I don't know what. So far I just have the two default routes and the map.root line which I uncommented:
map.root :controller => "home"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
So really I have two questions:
What do I have to do in order to enable my new action?
Why don't the existing routes cover this situation? Other urls consisting of just the controller and action work just fine (e.g. http://localhost:3000/users/new). Why not this one? Shouldn't it just evaluate to :controller = users, :action = profile, :id = nil?
Try putting something like this in your routes.rb file:
map.user_profile '/users/:id/profile', :controller => "users", :action => 'profile', :conditions => {:method => :get}
I think possibly the reason it's doing this is because you are not matching either of the defaults, because you are not setting :id (even though it is detecting your action as the id). I don't know what your URL looks like, but I have a feeling that if you tried http://localhost:3000/users/123124124/profile, it MIGHT work, even without the new line in routes.
Are you intentionally trying to get the id from session[:user_id] instead of params[:id]? Is this supposed to be displaying a public profile?
Are you sure, that the session contains the user_id the first time you load the page?
Hard to say without seeing all the code, but my guess is there may be some strangeness because your model and controller have the same name. I'd try renaming the controller before changing anything else (remember to change the name of the views/users directory too).
See also this other stack overflow post: Rails cannot find model with same name as Ruby class
Long shot maybe.
Solution for your problem configure your routes.rb in such a way that id should be passed as the parameter .
configure in routes.rb as below
map.profile '/profile/:id',:controller=>'users',:action=>'profile'
when you want to access your profile page use it with the following URL
http://localhost:3000/profile
Make sure once you login , u handle the session and store the userid in the session variable .
Good luck !
Related
so this is stumping me im not the best when it comes to routes at all, but what i am trying to achieve seems simple. what i have is a feature that is currently only accessible by a superuser and now i would like to extend that functionality to a portal_administrator. now to access the page you need a link_to that looks like this
= link_to('Data', portal_datum_path(current_portal.id), :id => :super_user_data_link)
which is routed with a match
match '/portal_data/:id', :controller => 'portal_data', :action => 'show', :as => 'portal_datum'
now this works just fine you end up with a url that has a id params. which is used in the page that it routes to. in fact there is a before filter that makes sure there is a id.
def load_portal
#portal = Portal.find(params[:id])
end
this would enable the susperuser to see what portal he was in just by looking at the url. now that i am extending this to the users i dont want them to see what portal id they are in, so i thought i would use a singular resource something along the following.
= link_to('Data', portal_data_path, :id => :super_user_data_link)
with a
match '/portal_data' => "portal_data#show"
so it routes to the same place but keeps the url clean. but obviously this dosent work. even if i hard code the before filer to accept the first portal it jsut throws a error
No route matches {:controller=>"portal_data", :action=>"show"}
but if i rake my routes its there?
i am sure what i am doing wrong is obvious any ideas?
All i had to do was make the :id an optional parameter like so...
match '/portal_data(/:id)'
And it works :) then in the controller look for...
def load_portal
#portal = Portal.find(params[:id] || current_portal.id)
end
...an portal id on the account if there wasn't one in the params.
New to rails, so if this is discussed somewhere, just link me off: I had a good search but all I could find were people trying to figure out how to use link_to, not any discussion of this comment:
link_to "Profile", profile_path(#profile)
# => Profile
in place of the older more verbose, non-resource-oriented
link_to "Profile", :controller => "profiles", :action => "show", :id => #profile
# => Profile
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
I get that the latter is more verbose, and thus undesirable, but the former seems like a strange thing to be recommending.
If I have an action at say: /blah/add and I link to it using:
link_to "Link", link_add_path
Then I'm linking to mysite.com/link/add. This is a hard coded url.
If I change the route that this maps to, I have to change every instance of link_to in my code base to point to the new absolute url. This seems crazy.
However, if I link to it using:
link_to "Link", :controller => "thing", :action => "add"
Then the url is dynamically determined. If I have to change the path all I do is edit config/routes.rb and not touch any of my code. This seems like much lower maintenance.
I appreciate it's slightly more complex than that, the blah_path variable is not actually a static route, and actually contains some smarts like the application base url and prevents you from linking to urls that don't exist, but it seems like a step backwards to facilitate a fractionally less verbose syntax.
So, what's up with that?
What technical reason would you choose the former link_to syntax over the latter?
"You're doing it wrong" :P
Seriously though: use named resources, and here's why that's cool:
Example:
you've got this in your routes file:
resources :user_orders
And you are using "user_orders_path" everywhere. Then you do a refactor and decide (because the orders are now generic) that you want the controller to be called "orders" but you don't want to break all your old code. you can do this:
resources :user_orders, controller: "orders"
And your existing links will continue to work! (plus you can add a "orders" resource to move things over to the new scheme)
There's also neat things like named links:
match 'exit' => 'sessions#destroy', :as => :logout
I'd also like to add, if you needed to refactor your controller using the old link syntax - you'd still have to change a pile of controller links!
Then I'm linking to mysite.com/link/add. This is a hard coded url.
No, it's not. link_add_path is a method generated by Rails that points to a specific route in your config/routes.rb. You can see this by running
rake routes | grep link_add
If I change the route that this maps to, I have to change every instance of link_to in my code base to point to the new absolute url. This seems crazy.
No, you don't. Take the following example
get "link/add", as: :link_add, controller: :links, action: :add
If I run the above
rake routes | grep link_add
I get
link_add GET /link/add(.:format) links#add
But what if I change the name of my controller to UrisController? Just change the route in config/routes.rb
get "link/add", as: :link_add, controller: :uris, action: :add
and now you have
link_add GET /link/add(.:format) uris#add
The link_to's don't have to change because the link_add_path method is still mapped to the newly modified line in my config/routes.rb because the route name is the same. With your more explicit way of specifying controllers/actions for every link_to, you have to go through every link and update it manually to reflect the new controller: :uris controller.
Read about Naming Routes in the rails guide.
So I've got a Users controller, and it has (amongst others) a function called details.
The idea is that a user can go to
localhost:3000/user/:user_id/details
and be able to view the details of :user_id.
For example, I have a user called "tester".
When I go to the uri: http://localhost:3000/users/tester/details
I'd want the details function to be called up, to render the details view, and to display the information for the user tester.
But instead I get an error saying that
No action responded to tester. Actions: change_password, create, current_user, details, forgot_password, index, login_required, new, redirect_to_stored, show, and update_attributes
And I understand that to basically mean that if I wanted to access details, I should really be using
http://localhost:3000/users/details
Except that that isn't really working either... >.<
That is instead bringing me to http://localhost:3000/users/details/registries
(which is the default path that I'd stipulated for anybody trying to view users/:user_id, so again, that's working the way I wanted it to)
Point is: Can anybody help and tell me how I can go about getting
users/:user_id/details to work the way I want it to and display the details of :user_id?
Thanks!
Are you using resources? If your routes look like:
map.resources :users
You could make it:
map.resources :users, :member => { :details => :get }
That would allow GET requests for the URL /users/:id/details
More info here: http://guides.rubyonrails.com/routing.html#customizing-resources
I think that your problem is with setting routes in such way, that instead of :user_id you have :login (or whatever) in url /users/tester instead of /users/34. Probably you should take a look at to_param (1st example, 2nd example, 3rd example).
If you want to have another option in routes (besides default REST routes), you can add :member => {:details => :get} if you are using map.resources (#dylanfm answer) or just map it like in #Salil answer.
In order to get routes like "users/:user_id/details" change following in routes.rb
map.users 'users/:user_id/details', :controller => 'users', :action=>'details'
I have some RESTful controllers and have added a custom method to application_controller.
I have not changed anything in the routes to indicate this new method. The method is poll_memos. I have entered the following URL:
/groups/1234/poll_memos
I get the following error:
Unknown action
No action responded to 1234. Actions: create, destroy, edit, index, new, poll_memos, show, and update
Two questions: Since I didn't modify routes how does rails know about poll_memos? Second, since it seems to know about it, why is it not working?
I don't think thats a restful route that rails automatically generates. This means you'll need to add it yourself.
Look at this question and this one.
And its in the actions because its in the controller, the error message is just printing all actions.
The correct url is /groups/poll_memos/1234. In your example rails thinks that you're trying to call controller method named "1234", which is absent, of course.
Rails knows about poll_memos because the code that prints the error message looks at controller code, not to the routing. You may set routes up in such a way that it will say that there is poll_memos method, but you're unable to access it via URL.
This is because you are most likely triggering the default route:
map.connect ':controller/:action/:id'
Your URL
/groups/1234/poll_memos
would map as follows:
{:controller => "groups", :action => "1234", :id => "poll_memos"}
Also, as you are using a restful style you need to configure the route. To get the poll memos working on the items in the collection you'll need to modify your routes to map as follows:
map.resources :groups, :member => {:poll_memos => :get}
Say if I have a controller, profile, which has just two actions. The first one is list, which will just show the list of names. I want these names to be links which will then take you to a page that shows the full profile. So I need a second action, view, which can then bed fed a parameter to indicate which profile to view.
For example: I would access /profile/list, then if I want to view John's profile, I will click on his name which should take me to /profile/view/john. My view action will read the john parameter and then make the appropriate database queries.
What changes do I have to make to routes.rb for this to happen? Cheers.
I'd rather use the default :controller/:action/:id route to protect against cases where there are 2 John's in the list.
To have a custom route like you mentioned
edit Routes.rb to include a new one
map.connect ':controller/:action/:user_name'
Now a request like profile/view/john should reach you as
#params = {:controller => "profile", :action=> "view", :user_name => "john"}
Use the params[:user_name] value to locate and display the relevant record in the controller's view action. You can also want to setup some requirements on the :user_name part of the url, e.g. it has to match /SomeRegexpToValidateNames/
map.connect ':controller/:action/:user_name',
:requirements => {:user_name => /\w+/}
if you want to identify profiles by name, as "/profile/view/john" you can use the permalink_fu plugin
http://www.seoonrails.com/even-better-looking-urls-with-permalink_fu
which will keep you out of trouble when there's name duplication...
If the model is "user" you have to override the to_param method. This will allow you to return the "id-name" of the user instead of the "id". (ex: /profile/view/23-john)
I know, it's not exactly what you asked for but this should be a easy solution.
class User < ActiveRecord::Base
def to_param
"#{id}-#{name.gsub(/\W/, '-').downcase}"
end
end
And just add a simple resource declaration to the routing configuration:
map.resources :users