Rails routing confusion due to :id - ruby-on-rails

I am using devise for authentication. When signing up users create a profile name that I would like to use as their profile route. So, it might look like this: www.myapp.com/profile-name. The problem I'm running into is with the routes not going to the right place.
routes.rb
resources :majors do
resources :reviews
end
devise_for :users
...
match '/:id' => 'users#show', as: :user_profile
I've placed the :user_profile route at the bottom of my routes file. Part of my rake routes looks like this:
major GET /majors/:id(.:format) majors#show
user_profile GET /:id(.:format) users#show
On the profile page (myapp.com/my-custom-profile-name) there are no problems. But on the majors show page I use the user_profile_path to link to a user's profile and the url is www.myapp.com/:id - with the :id being the major :id. So, the :id of the major is getting mixed in with the user_profile :id.
My users controller looks like this:
def show
#user = User.find_by_profile_name(params[:id])
#reviews = #user.reviews
end
I have changed the url around, tested it on different areas, changed the order of my routes file, searched and tested this all day long. I cannot figure out what I'm missing. I think it's really simple but it's eluding me. Any ideas?
SOLUTION:
The solution was first get the routes correct. Since I've created a custom, dynamic url (myapp.com/user-profile-name) I needed to call the id in the route:
get '/:id' => 'users#show', as: :id
That changed my routes to look like this:
id GET /:id(.:format) users#show
Users share reviews and their name is posted next to their review. I was having trouble linking to their profile from their name on their review. I was able to do that on the view like this:
<%= link_to review.user.profile_name, id_path(review.user.profile_name) %>

To get to a specific user profile, you need to pass the user profile ID into the user_profile named route:
user_profile_path(#user)

Related

route works one place, not others

This is kind of difficult to communicate but I'll try without pasting all my code. I have Members who have one Mailbox which has many Receipts. In the header layout I have a nav that calls
<%= link_to "Message Center", member_mailbox_path(current_user.member_id) %>
It works on most pages like trails/# , the resource pages for various models
But on other pages, seems like custom route pages, I get this error
No route matches {:action=>"show", :controller=>"mailbox", :member_id=>16}
Running rake routes shows this:
member_mailbox GET /members/:member_id/mailbox/:id(.:format) mailbox#show
Routes are confusing to me, here are my routes for this problem (show message isn't tested yet) ...
resources :members do
resources :mailbox do
resources :receipts do
member do
get :show_message
end
end
end
end
The routes for the pages that are showing the error are similar to this one
match '/my_plays', :to => "trails#my_plays"
match '/my_creations', :to => "trails#my_creations"
So not sure if my routes are right. I wonder if resources :mailbox is correct since I don't have a bunch of resources for that, it's a has_one .... THX
----EDIT--- after changing route per advice:
member_mailbox POST /members/:member_id/mailbox(.:format) mailboxes#create
new_member_mailbox GET /members/:member_id/mailbox/new(.:format) mailboxes#new
edit_member_mailbox GET /members/:member_id/mailbox/edit(.:format) mailboxes#edit
GET /members/:member_id/mailbox(.:format) mailboxes#show
PUT /members/:member_id/mailbox(.:format) mailboxes#update
DELETE /members/:member_id/mailbox(.:format) mailboxes#destroy
You may want to define a mailbox as a singular resource in your routes. Otherwise, Rails will expect you to pass in both the user id and the mailbox id for member_mailbox_path to route to mailbox#show. I believe this is why you're getting a routing error. Since each user has one mailbox, there's no need to make this extra lookup part of the route. So instead of resources :mailbox, you can do resource :mailbox:
resources :members do
resource :mailbox do
resources :receipts do
member do
get :show_message
end
end
end
end
I believe this would generate the following routes:
member_mailbox POST /members/:member_id/mailbox(.:format) mailboxes#create
new_member_mailbox GET /members/:member_id/mailbox/new(.:format) mailboxes#new
edit_member_mailbox GET /members/:member_id/mailbox/edit(.:format) mailboxes#edit
GET /members/:member_id/mailbox(.:format) mailboxes#show
PUT /members/:member_id/mailbox(.:format) mailboxes#update
DELETE /members/:member_id/mailbox(.:format) mailboxes#destroy
Notice that the lack of path names next to GET, PUT, and DELETE doesn't mean they don't exist; they're just repeats of the POST path, but each responds to different HTTP methods.
To render mailboxes#show, you'll need to add a MailboxesController with a show route, which might do a look up for the member:
class MailboxesController < ApplicationController
def show
#member = Member.find(params[:member_id])
# other mailbox code...
end
end
And you'll also create a template at app/views/mailboxes/show.html.erb to render the mailbox show page.
Also, I would recommend against deeply nesting your routes, as in third level :receipts.

Conflict routes and params name in Ruby on Rails

In my website, users can visit category via example.com/category1, example.com/category2, etc. So I write the route rule as below:
match '/:category' => 'home#category', :constraints => ShowCategory.new
ShowCategory is a Class that make sure the category user visited is exist. At the same time, users can specify their personal domain name, then his/her profile page can be visited via url like example.com/peter. So There is another route rule:
match '/:user_domain' => 'Profiles#show'
Because I use the :constraints for category route, the routes didn't conflict. However, in the Profiles#show action I always get the parameters {'category' => 'peter'}, not {'user_domain' => 'peter'}.
How can I correct the parameter name? I don't want a parameter named category in the profiles controller.
Thanks.
Well, the way you're naming your routes doesn't make much sense; it's making the routing engine confused. It should be categories/1 rather than category1.
As for the profiles, I guess the first rule and the to_param method should be enough.
# routes.rb
profile '/:user_domain', controller: 'profiles', action: 'show'
resources :profiles
resources :categories
# profile.rb
def to_param
self.user_domain
end

How do you navigate to a users show page with devise?

Like the title says, I am using devise. I want to navigate to /users/1 or whatever the current_users path is. When I try link_to(current_user.name, user_path) I just get an error.
undefined local variable or method `user' for #<#:0x00000101d2dfc8>
Am I not using the right path? Do I need to route it or something?
Also, this goes with the first, how would i navigate to a different users show page(not the current user)
You will need to to three things to get the view you want because devise doesn't provide the standard user routes.
1) Create a route in config/routes.rb. Devise doesn't provide a standard route, and in my experience rake routes just confirms this. I've used:
match '/users/:id', :to => 'users#show', :as => :user, :via => :get
with mixed success
2) Create a user controller with the show section appropriately filled out
3) create a view file: user/show and add the parts you want to show.
I am not familiar with devise, but I'd be surprised if devise differed from Rails conventions. You need to pass in the user to the route helper: link_to(current_user.name, user_path(current_user))
What helped for me was to add the # before user in "routes.rb":
"match 'users/:id' => 'users#show', :as => #user"

Editing the current User in Rails 3

Users can be edited from a normal resourceful URI like:
/users/1/edit
The issue is that in my application, the edit user page is the home page or root route.
# routes.rb
root :to => "users#edit"
So, I tried to set #user to the current user in the absence of params[:id].
# app/controllers/users_controller.rb
def edit
#user = (params[:id]) ? User.find_by_id(params[:id]) : #current_user
end
Unfortunately, I'm having trouble getting the form to point properly.
# app/views/shared/_manage_users.rb
<%= form_tag follow_user_path, :id => 'update-following-form' %>
I'm getting:
No route matches {:action=>"follow", :controller=>"users"}
follow is a member route of the user resource and has a corresponding controller method. If I access the page via the URI at the top of this question, /users/1/edit, everything works fine and no error is thrown.
I'm not sure whether I'm going about this completely the wrong way or if I'm just not using the right form helper or something silly. How can I fix this issue, or what steps can I follow to debug it?
A member route expects the member to be passed as an argument. You route is expecting a User, like so:
follow_user_path(#user)
in your routes do this
resource :user
instead of
resources :users
now the id param is notin the url. you just need to ensure the user is logged in
I think you need to actually define follow_user in your routes.rb.
Example:
post "user/follow" => "users#follow", :as => :follow_user

custom action in rails 3

I'm trying to make a simple link that will toggle my "status" attribute in my model from "pending" to "active". For example, when I first create a user, I set the status to "pending". Then when I show the list of users, I add a button that should change that user's status to "active". I tried this via a custom action (is this a good approach?) but I'm having trouble with the auto-generated named route.
in my user index.html.haml:
button_to "Manually Activate", activate_user_path
in routes.rb:
resources :users do
get :activate, :on => :member
in users_controller.rb:
def activate
#user = User.find(params[:id])
#user.update_attribute(:status, 'Active')
redirect_to #user
end
this seems to work when I go to say, /users/1/activate, as the status will update. However, the /users page doesn't show and gives me error:
ActionController::RoutingError in Users#index
No route matches {:action=>"activate", :controller=>"users"}
ie, it is having a problem with the activate_user_path I specified in my view. (However if I use another named-routes-style path that I haven't specified in my routes.rb to test it out, I get
NameError in Users#index
undefined local variable or method `blahblah_user_url' for #<#<Class:0x00000102bd5d50>:0x00000102bb9588>
so it seems that it knows it's in the routes.rb but something else is wrong? I'm really new to rails and would appreciate the help!
thanks!
Your link should look like this:
button_to "Manually Activate", activate_user_path(#user)
You need to add what user you want to activate.
A number of problems, I can see.
Firstly you should NOT update the database using a GET request.
Secondly button_to will provide you with an inplace form which when clicked will POST to your app.
Thirdly, the way you have your routes setup, you need to provide the user in the path (you've tested it by forming the url in the browser already).
run
rake routes
on the command prompt to see how your routes look and the name you can use to generate those routes.
I suspect you need to use
button_to "Manually Activate", activate_user_path(user)
(user or #user or whatever is the user object). In your button_to call and change the "get" to "post" in the routes file.
resources :users do
member do
post :activate
end
end

Resources