Which route matches a fixed controller with variable action? - ruby-on-rails

I have this controller called activities, which contains methods, such as updateweight, displaycalories, etc.
<ul>
<li><%= link_to "Home", "/" %></li>
<li><%= link_to "Update Weight", "/activities/upweight" %></li>
<li><%= link_to "Food Ressources", "/activities/food_res" %></li>
<li><%= link_to "Exercises Technics", "/activities/exercises" %></li>
</ul>
Which route would be able to get to the activities controller and to the method with the name that comes after? I've tried ressources :activities, but I'm getting bizarre results.
Thanks for helping

Handling any arbitrary action in a controller is non-RESTful. Much older rails versions handled this like:
match ':controller(/:action(/:id))(.:format)'
.. and in fact that's still possible with Rails today. You should be careful not to mix RESTful and arbitrary actions in a single controller since actions like 'create' and 'delete' should not respond to GET requests.
Alternatively you could promote 'weight', 'foods' and 'exercises' to their own resources.
Also, you apparently can't spell 'resources' or 'techniques' though I rather like the image of exercising one's technics.

To find the available routes, utilize the command rake routes from command line of your rails app directory. This will show you a list of the potential routes you can use as links. They will typically look like:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
etc...
In your case though, you are making non-default url's, so you need to add them to your config/routes.rb file. So for example add:
get '/activities/upweight' => 'activities#upweight'
This would connect the chosen url to the correct controller#action you desire using a GET http request.
Also note, if you've created your routes for the activities controller in routes.rb using the line resources :activities, then you need to make sure to add the custom routing line above this. resources :activities serves as a catch-all for custom urls, and will route them to the controller's show method.

In your case the route can look like these:
match "/activities/upweight", :as => "activities#upweight"
match "/activities/food_res", :as => "activities#food_res"
match "/activities/exercises", :as => "activities#exercises"
Provided that you have method named as upweight, food_res, exercises

Related

Routing error in R

I'm new to Ruby and Ruby on rails and have hit a problem with routing. I have 3 controllers, application controller, a bike controller and a ride controller. My routing table is as follows:
Rails.application.routes.draw do
get 'cycle_tracker/index'
resources :rides
resources :bikes
root 'cycle_tracker#index'
When I run rails routes it brings the following:
Prefix Verb URI Pattern Controller#Action
cycle_tracker_index GET /cycle_tracker/index(.:format) cycle_tracker#index
rides GET /rides(.:format) rides#index
POST /rides(.:format) rides#create
new_ride GET /rides/new(.:format) rides#new
edit_ride GET /rides/:id/edit(.:format) rides#edit
ride GET /rides/:id(.:format) rides#show
PATCH /rides/:id(.:format) rides#update
PUT /rides/:id(.:format) rides#update
DELETE /rides/:id(.:format) rides#destroy
bikes GET /bikes(.:format) bikes#index
POST /bikes(.:format) bikes#create
new_bike GET /bikes/new(.:format) bikes#new
edit_bike GET /bikes/:id/edit(.:format) bikes#edit
bike GET /bikes/:id(.:format) bikes#show
PATCH /bikes/:id(.:format) bikes#update
PUT /bikes/:id(.:format) bikes#update
DELETE /bikes/:id(.:format) bikes#destroy
root GET / cycle_tracker#index
In my main view I have the following (I'm simply trying to create a link from my main page to rides/new.
<%= link_to 'rides', :controller => new_ride_path %>
If I try and access http://127.0.0.1:3000/rides/new then it works as expected. However, if I simply try and access http://127.0.0.1:3000 then I get the following:
showing D:/Dev/CycleTracker/app/views/cycle_tracker/index.html.erb where line #2 raised:
No route matches {:action=>"index", :controller=>"rides/new"}
If I try to use new_ride_url instead of path I get the following:
Showing D:/Dev/CycleTracker/app/views/cycle_tracker/index.html.erb where line #2 raised:
No route matches {:action=>"index", :controller=>"http://127.0.0.1:3000/rides/new"}
I imagine this is probably a fairly straightforward issue, but any help appreciated.
<%= link_to 'rides', new_ride_path %>
Try that - you don't need the :controller => part
if you want to use the controller-action style you need to do this:
<%= link_to "Rides" , controller: "rides", action: "new" %>

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'.

Rails 3 - Nested Resources Routing

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).

Nested Route link_to helper working in one place but not another

I have a nested routes problem that I can not figure out. I have an app that has nested routes like so:
resources :events do
resources :sessions
end
I am trying to use the following link_to in my code:
<%= link_to "New Session", new_event_session_path %>
When I run rake routes, it will show the proper URL with a GET method existing:
new_event_session GET /events/:event_id/sessions/new(.:format) {:action=>"new", :controller=>"sessions"}
When I try to use the link_to in one place it works, when I try to use it in another place it does not, it instead will give me this error:
No route matches {:controller=>"sessions", :action=>"new"}
The only difference between the two files is the location of the files in the app (one is under views/events the other is under views/sessions and the url being called:
/events/1 --vs-- /events/1/sessions
I am still a noob with rails, so this is probably a stupid question, but I have hit a bit of a wall. Any help is appreciated.
You just need to pass event object to path helper:
new_event_session_path(#event)

Is there a way to automatically create a plural route for index and singular for everything else?

When dealing with a collection resource, I like to use the plural for the index (ie. list) page (viewing many objects), and singular for the other pages (create/update/delete one object).
In order to do so, I seem to have to create my routes like so:
map.objects 'objects.:format', :controller => :object, :action => :index, :conditions => { :method => :get }
map.resources :object, :controller => :object, :except => :index
This creates routes like so:
objects GET /objects(.:format) {:action=>"index", :controller=>"object"}
object_index POST /object(.:format) {:action=>"create", :controller=>"object"}
new_object GET /object/new(.:format) {:action=>"new", :controller=>"object"}
edit_object GET /object/:id/edit(.:format) {:action=>"edit", :controller=>"object"}
object GET /object/:id(.:format) {:action=>"show", :controller=>"object"}
PUT /object/:id(.:format) {:action=>"update", :controller=>"object"}
DELETE /object/:id(.:format) {:action=>"destroy", :controller=>"object"}
It works, but it seems like I'm using an extra line in my routes file (to explicitly specify the index route) when I shouldn't have to. Is there a way to do what I want in one route? Or, alternately, is there a reason not to route this way?
The only reason other than "normal REST says don't" to not have the "object" be a resource under "objects" is search engines.
Google will notice that you have "recipes" and then recipes under "recipes", and give you those cool sitelinks:
Google's Webmaster Guidelines say, in
the first item under design and
content guidelines, "Make a site with
a clear hierarchy and text links."
RESTful routing is designed in such a way that you're scoping down what it is you want to do. Say you go to http://example.com/objects. Here, you're telling the site you want a list objects.
Now when you go to http://example.com/objects/2 you're telling it you want to see the object with identifier of 2 in that list (or resource) of objects.
Finally, when you go to http://example.com/objects/2/edit you're saying you want to find the object again with identifier of 2 but this time you would like to edit it rather than view it.
By going against the grain like you have suggested in routing helpers you will be causing a tremendous amount of unnecessary pain for yourself and for anybody else reading your code.
However if you do choose to go this path (again, I advise against it) then yes, defining two routes is the only way.

Resources