Rails 3 - Nested Resources Routing - ruby-on-rails

In my application I have users, and then each user has one mailbox where they're delivered messages. My routes.rb looks something like:
resources :users do
resources :mailboxes
end
If I do a rake route, I see this route available to me:
user_mailbox GET /users/:user_id/mailboxes/:id(.:format) {:action=>"show", :controller=>"mailboxes"}
I wanted to link to this path in my application layout, in a sort of toolbar the user finds at the top of the screen.
My view code is:
<%= link_to image_tag("mail_icon.png", :id => 'mail_notice'), user_mailbox_path(current_user)%>
The problem I'm having is that I get a routing error for this path if I'm nothing withing users/* - So anywhere else in my application besides the resource my mailbox is nested under. If I'm on, lets say my user's index page, the path does work without issue.
No route matches {:action=>"show", :controller=>"mailboxes",
Is there something I could be missing with this route? Anything related to users works, it's just the mailbox that I'm having issues with.
Thanks

It sounds like mailbox should be a singleton resource.
resources :users do
resource :mailbox
end
Otherwise it would expect that a user has multiple mailboxes and you'd have to provide the mailbox_id to user_mailbox_path as well.
user_mailbox_path(current_user, #mailbox)

As you can see from the route:
user_mailbox GET /users/:user_id/mailboxes/:id(.:format)
you need to provide two ids, the :user_id and the :id of the mailbox. This makes sense if the user can have several mailboxes.
<%= link_to image_tag("mail_icon.png", :id => 'mail_notice'),
user_mailbox_path(current_user, current_user.mailboxes.first) %>
If you intend the user to have only one mailbox, then I would change the routes.rb like this:
resources :users do
get :mailbox, :on => :member
end
and you would get a route like:
mailbox_user GET /users/:id/mailbox(.:format)
which would be handled by the mailbox method on UsersController, and you can get the path to it in your views with mailbox_user_path(current_user).

Related

rename rails route

I have a route/path using CcpaAcknowledgmentsController
/ccpa_acknowledgments
I would like the route to be, BUT I would still like it to use the CcpaAcknowledgmentsController
/customers/ccpa_acknowledgments
Since I have these two routes...
resources :customers
resources :ccpa_acknowledgments
match '/customers/ccpa_acknowledgments', to: 'ccpa_acknowledgments#index', via: [:get]
I keep getting a conflict stating
NoMethodError in CustomersController.
Is there a way to get the desired route I want without putting the method/code in the CustomersController?
This is the way to do that
resources :customers do
get :ccpa_acknowledgments, to: 'ccpa_acknowledgments#index', on: :collection
end
Inside the customers block for two reasons:
we are fine with the beginning of the path /customers
we don't want to mess with the other customers' routes. In this way your route inside the block is before the customers default routes and it's not seen as you are calling customers/:id with ccpa_acknowledgments as id because rails takes care of that for you defining that route before the show
Then
get :ccpa_acknowledgments
because we need the second part of the path /ccpa_acknowledgments
to: 'ccpa_acknowledgments#index'
we want to specify the controller and action pair, because we want to use the CcpaAcknowledgmentsController even though we're inside the customers block
on: :collection
because we don't want any :id inside our route. It's a route defined on the customers collection
alternative using resources as asked in the comment. Try
scope :customers do
resources :ccpa_acknowledgments, only: :index
end
but you need to put this before the resources :customers

rails link_to using get instead of post

I'm making a website for a class and I'm trying to implement a friend request function with a model called 'Users' and a join model called 'Relationships'. I have a button on the user#show page that should add a friend by using the create method in the Relationships controller. Here is the code for the button:
<%= link_to "Add as Friend", relationships_path(:friend_id => #user), method: :post %>
When I press the link, however, it tries to access the index method instead. After looking in the console, it looks like the link is sending a GET request, which routes to the index method, instead of a POST request, which routes to the create method. Can someone explain why this error is occurring and how I can fix it?
Edit: As requested, here is what I have in my routes:
Rails.application.routes.draw do
resources :interests
get 'interests/create'
get 'interests/destroy'
get 'home/index'
get 'sessions/create'
get 'sessions/destroy'
resources :users
resources :relationships
resources :subscriptions
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
root 'home#index'
get "/auth/:provider/callback" => "sessions#create"
get "/signout" => "sessions#destroy", :as => :signout
Using a link_to helper indicates to Rails that you'd like to produce an a tag in your HTML. No element of the HTML specification regarding a tags allows for producing POST requests. Because Rails understands the utility of allowing for POST and DELETE requests to be issued using links, however, it provides those options in the link_to helper. It's implementation, though, must use JavaScript under the hood in order to appropriately function.
Check that jquery-ujs is installed, and that your asset pipeline is working correctly in order to use the helper in this way.
You may also evaluate whether using a form_for and a button is better, since that will automatically POST.
I'm pretty sure you are matching the wrong route. Run rake routes and see the route that links to the Relationships#create.
Using 'url' instead of 'path' with the route helper solved the problem for me. So instead of 'relationships_path' use 'relationships_url'.

How should I route to actions that are not nested that are in a controller that is nested?

I have a resource - activities, that is nested under provider. everything is working great for all my restful resources.
I'd like to add a new action to list all activities regardless of provider. So I think that should not be nested.
I tried to do this like so:
resources :activities, only: [:list]
But this doesn't create a route when i rake routes, and I get the error:
No route matches [GET] "/activities/list"
How do I do this? Is this the right way to go about what I want to do - show a list of all providers activities with a different view / layout than the nested provider#activities action.
OK. I (re) read the manual and did what it said, and that worked. Go figure.
resources :activities do
get 'list', :on => :collection
end
So that adds the list action to the routes with path & url methods & the nested resources still work.

Rails always routes an action to show action, and the action it self becomes the id

There's a strange behavior in rails I found recently related to routes and actions, specifically, it's on rails 2.3.5. I have a controller, let's call it Users. In the routes, I declare Users as a resources.
map.resources :users
And within the controller, I have the standard action: index, show, edit, update & destroy. Also, I added other action to fullfil certain requirements.
def generated_pdf_report
# do something
end
The problem is, when I go to page /users/generated_pdf_report, I get this on the console:
Processing UsersController#show (some timestamps) [GET]
Parameters: {"action"=>"show", "id"=>"generated_pdf_report", "controller"=>"users"}
As you can see, the server route the request to method show rather than to method generated_pdf_report. What's interesting, is that I have other controllers having similar action and is working fine.
The solution to the above problem is easy enough, make sure the added feed is above the resources:
map.feed 'users/generated_pdf_report', :controller => 'users', :action => 'generated_pdf_report'
map.resources :users
My question is: Anyone knows why rails behaves like that? The above solution is kind of sloppy, what do you think the best practices for such problem like one mentioned above.
As outlined in the Rails 2 routing guide, you can add collection routes like so:
map.resources :users, :collection => { :generated_pdf_report => :get }
When rails looks at
/users/generate_report
That is exactly the path it would use to show a user whose id was generate_report, so that is what it does, assuming you haven't told it otherwise.
A shorter alternative to what you wrote is
resources :users, :collection => {:generate_report => :get}
Which tells rails to map a GET to /users/generate_report to your generate_report action

How can I substitute a named route for a resource path in Rails 3?

I have a named route to the user's inbox, which is maintained by the messages resource. I want to make sure that the users can only access their inbox from my named path, and remove "/messages" as an option.
resources :messages
match "/u/:nickname/inbox" => "messages#index", :as=>:inbox
Is there a simple way of doing that? Do I have to just create a matching path for "/messages"?
Solution 1:
I'd create a path for messages and remove resources :messages
This approach will delete all the normal routes for messages and you'll have to re-add the ones you want available.
Solution 2:
Only remove the index option for the routes and allow all other standards routes to be the same.
resources :messages, :except => :index
match "/u/:nickname/inbox" => "messages#index", :as=>:inbox

Resources