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 %>
Related
Im just looking for some clarification on the following piece of code, well part of it.To give some background i have an app where you can upload recipes, search recipes and save them as favourites, this piece of code is in a controller "recipes", action is "my_recipes"
<%= link_to "Add to favorites", {:controller => 'favourites', :action => 'create', :recipe_id => recipe.id}, {:method => :post } %>
My understanding is that this creates a link_to (anchor tag if you will) that makes a post request through the create method within the favourites controller. This part I think i underdstand (corrections welcome), the part i am unsure of is
:recipe_id => recipe.id}
I know this is passing the recipe_id for example but I would like to know why we do this? and what relevance of the : before the first recipe_id.May seem obvious to some but you dont know until you learn.
Any help appreciated
Is this code in a partial? Is recipe being passed along? You should rewrite as so:
link_to "Add to favorites", new_favourite_path(recipe), method: :post
Do rake routes in your console and find out what the path is for creating favourites, then replace 'new_favourite' with that above. Note, the route might be identified with something more explicit like new_favourite_recipe.
To answer you question, you must pass recipe, or recipe.id because otherwise the controller wouldn't know which recipe to add to the favourites. You don't need to specify the user as that should be accessed directly from within the controller action using something like current_user.
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
So I'm getting a 'No route matches' error, and being new to Rails 3 (and Rails in general), I really don't know what the problem is. Here are the pertinent routes:
resources :users
#...
match 'reset_password(/:reset_password_code)' => 'users#reset_password', :as => :reset_password, :via => :get
match 'reset_password' => 'users#reset_password_submit', :as => :reset_password, :via => :post
The GET method works fine. I get a routing error when the form POSTs that's generated on the get page, which starts like this.
<%= form_for #user, :url => reset_password_url do |f| %>
It looks like it's posting to the right spot, as the url is generated using 'reset_password_url', it's posting to it, and the url looks as it should... anyone have any ideas?
UPDATE
I'm using Rails 3.0.4
I've tried taking out every other route except for the ones that I've mentioned here, and I still can't figure out why it's not working.
Figured it out!
In my form, rails was (correctly) assuming that since I had a user that I was using with the form_for helper, that I wanted to update the user, not make a new one.
Therefore, it was using the PUT method to post my form. To solve the routing problem, I just had to change the last route to:
match 'reset_password' => 'users#reset_password_submit', :as => :reset_password, :via => :put
I only found the issue after using the Web Inspector in webkit to see the whole request, and looked at the _method parameter being sent in.
I am just playing around with Ruby on Rails 3.0 with a simple message board and found several issues with will_paginate.
The most pressing is that each time a new page is displayed a database query of every single post in the topic is performed.
As you can imagine, if you have a topic with 10,000+ posts this is very slow.
Is there a way to stop this odd behavior?
Show controller:
#posts=#topic.posts
#posts = Post.paginate #posts, :page => params[:page],:order => "post_number"
Model
cattr_reader :per_page
##per_page = 20
view
<%= will_paginate #posts %>
In your controller try:
#posts = Post.paginate_by_topic_id #topic.id, :page => params[:page],:order => "post_number"
Look at the example in the will_paginate docs
Upgrade will_paginate to version 3.0.0. Then:
class Post
self.per_page = 20
end
#topic.posts.page(params[:page]).order("post_number")