Say I have an object called invoice. In routes.rb I have
resources :invoices do
get "pay"
end
When I run rake routes, the route is generated as
invoice_pay GET /invoices/:invoice_id/pay(.:format) invoices#pay
and the parameter is :invoices_id instead of :id
If I use a match statement:
match "invoices/:id/pay" => "invoices#pay", :via => :get
I get:
GET /invoices/:id/pay(.:format) invoices#pay
It seems to me that the route should be pay_invoice_path(#invoice), however, I have not found suitable documentation on this. Any suggestions?
i think what you are trying to do is
resources :invoices do
get "pay", :on => :member
end
have a look at the guides: http://guides.rubyonrails.org/routing.html
I am using kaminari pagination on custom page but it generates /assets based url:
http://localhost:3000/assets?action=my&controller=blogs&page=2
I need:
http://localhost:3000/blogs/my?page=2
Error:
No route matches [GET] "/assets"
Any suggestions?
I was having exactly the same problem trying to set-up pagination with either Kaminari or Will_paginate for a custom action. It turned out that the problem was in my routes.rb file.
As an example, my custom action is called 'all_credit' in the 'cards' controller. Previously in routes.rb I had:
match '/cards_credit' => 'Cards#all_credit'
This was giving me the same behaviour you describe above and generating assets/ based urls.
By changing the line in routes.rb to:
match '/cards_credit(/:page)', :controller => 'cards', :action => 'all_credit'
I was able to solve this and the paginated links are now being generated correctly.
I have resolved by add controller params.
<%= paginate #blog , :params => {:controller => "GoogleUsers"} %>
I now this has been asked a thousand times but that doesn't help me heh :) I've been at this an hour. My form:
= form_for #comment, :url_for => { :action => "create", :controller => "comments"}, :method => :post
my rake routes:
POST /t/:trunk_id/r/:root_id/comments(.:format) {:action=>"create", :controller=>"comments"}
trunk_root_comment GET /t/:trunk_id/r/:root_id/comments/:id(.:format) {:action=>"show", :controller=>"comments"}
The error:
undefined method `comments_path' for #<#<Class:0x007fed2c713128>:0x007fed2c71cc78>
If I name space the form to:
= form_for [:trunk_root, #comment], :url_for => { :action => "create", :controller => "comments"}, :method => :post do |f|
which should make the route trunk_root_comments_path.. which is correct according to the rake routes.. I get:
No route matches {:controller=>"comments", :format=>nil}
Help is very much appreciated.. been looking at this for hours..
UPDATE:
Thank you Ryan for such a great answer! A very clear explanation of something I was just sort of 'throwing things' at, now at least I understand better. I actually already had 'trunk_root_comments_path' available in my rake routes, and I had tried a couple of the combinations you mentioned, but I wasn't really grocking what I was missing, so you helped. I'm using Mongo and I don't actually have a Trunk model, I just have an attribute on roots called #root.trunk, though I have a trunk controller and therefore its a part of my routes(maybe a bad idea idk).
So I tried your TLDR and it said error:
Undefined method 'root_comments_path'
.. cause no Trunk model exists, I assume?.. so I made #trunk just equal the correct id with
= form_for [#trunk, #root, #comment] do |f|
<- and I got 'undefined method `politics_root_comments_path''.. I figured well.. that probably makes sense.. since I'm failing I must as well try your most explicit version:
= form_for #comment, :url => (trunk_root_comments_path(:trunk_id => #root.trunk, :root_id => #root.id)) do |f|
and sure enough that worked... so I'm not quite sure how to do it shorter then this.. the odd thing for me is I have another nested resource "photos" at the same level of depth in the routes and I was able to get that to work with = form_for [:trunk_root, #photo], :html => { :class => 'root_form' } do |f|.. but here for some reason I couldn't.. anyways I'd say you gave me enough to understand 100% but I think I went from 20% understanding to 50% understanding.. I know now that id's ARE important to routes, and the named helpers need access to them. I got an introduction to how the url_helper works, but would need to read more on it to really grock it fully I think. I'm also now able to construct proper routes in their longer form at least to get through tricky situations like this. So thank you :)
TL;DR You need to specify both a :trunk_id and a root_id in your URL or use form_for like this:
<%= form_for [#trunk, #root, #comment] do |f| %>
Rails is attempting to build a URL from the hash you're giving it, but that hash doesn't match anything in its routing table. You could do this:
{ :controller => "comments", :action => "create", :trunk_id => trunk.id, :root_id => root.id }
But that's really a bit tl;dr.
The cooler way to do it is this:
trunk_root_comments_path(trunk, root)
Where trunk and root are Trunk and Root instances respectively.
Now, if you want to be super-wicked-cool, do it like this:
<%= form_for [trunk, root, comment] do |f| %>
Science!
So how does this work? Elementary, my dear:
Rails first recognises that we're using form_for using an Array and that we mean business. Rails uses this array passed in and builds a URL out of it. It does this by using the routing helpers that are defined by the routes. Unfortunately, you've defined your routes in a funny way that don't play nice with this, but don't fear! We can fix this.
The way you can do it is this where you have this in config/routes.rb:
post '/t/:trunk_id/r/:root_id/comments'
Instead put this:
post '/t/:trunk_id/r/:root_id/comments', :as => "trunk_root_comments"
You may alternatively already have this:
match '/t/:trunk_id/r/:root_id/comments', :via => :post
Which should become this:
match '/t/:trunk_id/r/:root_id/comments', :via => :post, :as => "trunk_root_comments"
Either way, you've now got not one, but two(!!) path helpers defined by the routes. These aretrunk_root_comments_path and trunk_root_comments_url respectively. The names of these methods are super important for what I am about to explain to you. Pay attention!
So, back to our little form_for call:
<%= form_for [trunk, root, comment] do |f| %>
Rails knows that we're using an Array because it can see it. What it does with this Array may seem like magic, but isn't really.
Rails will take each element of this array and build a routing helper method name up from the different parts. This isn't actually part of form_for, but another method called url_for that you can use by itself:
url_for([trunk, root, comment])
In the beginning, this routing helper method name generated by url_for is simply an empty array ([]). Nothing special at all.
But then what happens is special!
The first element is going to be a persisted instance of the Trunk class. By "persisted" I mean that it's an object that maps directly to a record in the database. Yay ORMs!
Rails will know this, and so will turn the routing helper into this: [:trunk].
The second element is going to be a persisted instance of the Root class. Rails also knows this (damn, Rails is smart!) and will then append this to the array, turning it into [:trunk, :root]. Awesome.
The third (and final) element is then checked by Rails. It sees that (in this case) it's a non-persisted element, i.e. it's not been saved to the database.. yet. Rails treats this differently and will instead append [:comments] to the array, turning it into this:
[:trunk, :root, :comments]
See where I'm going with this now?
Now that Rails has done it's thing (or thang, if you like) it will join these three parts together like this: trunk_root_comments, and just for good measure it'll put _path on the end of it, turning it into the final trunk_root_comments_path helper.
And then! Man, and then... Rails calls this method and passes it arguments! Just like this:
trunk_root_comments_path(:trunk_id => trunk.id, :root_id => root_id)
This generates a full path to the resource like this:
/t/:trunk_id/r/:root_id/comments
And bam! Full circle! That's how Rails will know to generate the URL and you don't have to use ugly hashes anymore.
Success!
Not sure if you have this route set up but try:
= form_for #comment, :url => trunk_root_comments_path
I'm using a Rails 3 App with Kaminari for Pagination. Because of my language, SEO and friendly URLs I want to change my URLs looks like. But it seems I have to decide between friendly pagination links and or displaying the correct method names. But first things first:
I have a model, which is called "pages" and contains some pages which can't be applied to only one model or don't contain any model. The following is a snippet of my "routes.rb":
match'/neugikeiten', :to => 'pages#neuigkeiten'
scope(:path_names => { :new => "neu", :edit => "bearbeiten", :delete => "loeschen", :index => "index", :page => "seite" }) do
resources :news, :path => "neuigkeiten"
end
As you can see, I match every page from pages to a single name and match all my other models and methods (I only used one as example) with scope. All of this works just fine. But now I have to add the Kaminare routes, for which the route looks like this:
resources :pages do
get 'seite/:page', :action => :neuigkeiten, :on => :collection
end
So, basically what I want to get is an URL like this:
/neuigkeiten/seite/2
The 2 is just an example and seite is the german word for page. But what i do get, is this:
/pages/seite/2
So, I get the model name, instead of the name I defined for this single page. I already tried switching the different codes but either I just have the original model name in the URL or I don't get nice URLs for pagination, which look like this:
/neuigkeiten?page=2
And if I try to match the pages without the resource like this:
match'/tagebuch/seite/:page', :to => 'pages#tagebuch', :on => :collection
I get the following error.
can't use collection outside resources scope
It seems to me that there should be another method to do this, because I can't be the only one having this kind of problem.
I'm glad for any help!
If anybody is interested in an solution, I found one myself. It's not perfect, but it works.
I had to install an extra gem for the localisation called "i18n_routing". Then in my routes.rb I did:
localized do
resources :news, :path => "neuigkeiten" do
get 'seite/:page', :action => :index, :on => :collection
end
end
The rest is done in the localized language file (en.yml).
Im upgrading a rails 2 app to rails 3 app and am having a bunch of routing issues. Heres the current:
So in the page its trying to load (results/_form.html.erb) I have a form with the following syntax:
<%= form_tag(:controller => "results",:action => "show") do %>
And i do have an action in my results_controller.rb called show. Yet i keep getting the no route matches error. Is this rails 2 syntax and not 3? Is there something I need to do in my routes.rb file? I think there is because that was a a major change between rails 2 and 3, im just not sure what. Any suggestions?
show action ideally should expect id to be passed in the params:
<%= form_tag(:controller => "results",:action => "show", :id => #user.id) do %>