Ruby on rails paths and routes - ruby-on-rails

I'm trying to get the hang of basic Rails routing.
I have a model called page which I generated with a scaffold.
I have added a method called addchild which I would like to access through
'pages/addchild/:id'
So far so good. However, I want to set up a link to this method like so:
<%= link_to 'Add child page', addchild_page_path(page) %>
Passing the ID of the current page as a parameter.
When I load my index view (where the link is), I get the following message:
undefined local variable or method `addchild_page_path' for #<ActionView::Base:0xb67797d0>
Have I misunderstood how the path/link_to method works?
My routes file looks like this:
map.resources :pages
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
Any advice would be greatly appreciated.
Thanks.

You need to add a route to it to be able to use the named path methods.
Since you mentioned you used scaffolding, you probably have the route setup as a resource, so all that you need to do is add the method:
map.resources :pages, :member => {:addchild => :get}
Would give you an addchild_pages_path (and the actual created path would look like /pages/:id/addchild
You then use it like this: addchild_pages_path page, don't call the id method directly since it is not resourceful (you won't use the to_param in the page class, which you might want to do later).
If you really want the url to show up as /pages/addchild/:id (which I don't recommend) you can add
map.addchild_page "/pages/addchild/:id", :controller => :pages, :method => :addchild
before the map.resources :pages row in your routes.rb, and then use the path method as above.

Related

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

Why is link_to with an absolute url considered technically superior to targetting controller action?

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.

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

Rails 2.3.5: routes names for members action to be different from the action name

I have a rails 2.3.5 application where an action acb is changed to pqr and modified so that it works only for "get" method.
To achive this I have used resource route with options like
map.resources :controller, :member => {:pqr => :get}
The original view file has acb_controller_path link in many places. If I change the path in view file as pqr_controller_path it works fine.
Is there a way I can refer acb_controller_path to controller/:id/pqr ?
You're better off changing the view paths to point to your new route, and I think I'm misunderstanding your question a little but depending which way you're trying to do it, you can try something like this I guess?
map.acb_controller '/controller/:id/pqr', :controller => "controller", :action => "pqr"

rails routing problem

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}

Resources