I am sorry for my bad english first.
I just installed ruby and rails few hours ago (you wouldn't believe it took me 3 days to install ruby,rvm,rails and etc, on this ubuntu 10.04 machine) and I am trying to implement basic Member scaffold. My version of rails is 3.0.0 and my ruby is 1.9.2.
When I #rails generate scaffold Member email:string password:string it created various files. I also did #rake db:migrate to implement database in mysql.
So within member controller, I saw that I have to go through 127.0.0.1:3000/members/ to get to the basic scaffold setup.
I just changed
def new
#member = Member.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #member }
end
end
above statements in member controller into
def register
#member = Member.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #member }
end
end
U see, I just changed the new into register, and now, when I try to get into
127.0.0.1:3000/members/register
The ActiveRecord::RecordNotFound error shows up.
How can I resolve this problem?
I just want to make
127.0.0.1:3000/members/register
to be a page where user can register..
btw, this RoR seems to be very complicated, and api documents seems to be too broad to be understood for beginners. I ordered a RoR book last week, so I will see how it goes...
By using the scaffold generator members gets mapped as a resource. Look in the config/routes.rb
resources :members
When entities are mapped as resources they get a set of default routes. You can see all your mapped routes by doing rake routes
members GET /members(.:format) {:action=>"index", :controller=>" members"}
members POST /members(.:format) {:action=>"create", :controller=> "members"}
new_member GET /members/new(.:format) {:action=>"new", :controller=>"members"}
edit_member GET /members/:id/edit(.:format) {:action=>"edit", :controller=>"members"}
member GET /members/:id(.:format) {:action=>"show", :controller=>"members"}
member PUT /members/:id(.:format) {:action=>"update", :controller=>"members"}
member DELETE /members/:id(.:format) {:action=>"destroy", :controller=>"members"}
When you rename the new action to register there no longer is a valid route for that mapping.
What you could do is to leave the action as new and just add the following route in your routes.rb
match 'members/register' => 'members#new'
This way you do not break other things in the scaffold. If you really want to rename the action to register I would suggest not using scaffolds.
You need to add 'register' method to routes, like:-
map.connect '/members/register', :controller => 'members', :action => 'register'.
After adding the above to routes.rb restart the server.
Thanks, Anubhaw
I had the very same problem when creating a new html.erb.
Even my routes.rb match 'controller/action' => 'controller#action' were correct.
Later I found that the problem was that the resources :controller were above the match.
This is the correct order that worked for me:
match 'controller/action' => 'controller#action' resources :controller
Thanks to pavlo for asking this question, and to maz because his answer gave me the hint that the resources were involved in the error.
Related
I added a new controller action and added correspondent route
def students
#students = Swimming::Student.all
render :json => #students
end
namespace :swimming do
resources :classschedules do
get 'students', :action => 'students', :as => :students ,:on => :collection
end
end
but when I access this page
http://localhost:3000/swimming/classschedules/students
I got this error
ActiveRecord::RecordNotFound in Swimming::ClassschedulesController#show
Couldn't find Swimming::Classschedule with id=students
It looks like rails tries to load another route
GET /swimming/classschedules/:id(.:format) swimming/classschedules#show
I am attaching all related routes
swimming_classschedules GET /swimming/classschedules(.:format) swimming/classschedules#index
POST /swimming/classschedules(.:format) swimming/classschedules#create
new_swimming_classschedule GET /swimming/classschedules/new(.:format) swimming/classschedules#new
edit_swimming_classschedule GET /swimming/classschedules/:id/edit(.:format) swimming/classschedules#edit
swimming_classschedule GET /swimming/classschedules/:id(.:format) swimming/classschedules#show
PUT /swimming/classschedules/:id(.:format) swimming/classschedules#update
DELETE /swimming/classschedules/:id(.:format) swimming/classschedules#destroy
date_swimming_classschedules GET /swimming/classschedules/date/:date(.:format) swimming/classschedules#date
students_swimming_classschedules GET /swimming/classschedules/students(.:format) swimming/classschedules#students
editnote_swimming_classschedules POST /swimming/classschedules/editnote/:date(.:format) swimming/classschedules#editnote
GET /swimming/classschedules(.:format) swimming/classschedules#index
POST /swimming/classschedules(.:format) swimming/classschedules#create
GET /swimming/classschedules/new(.:format) swimming/classschedules#new
GET /swimming/classschedules/:id/edit(.:format) swimming/classschedules#edit
GET /swimming/classschedules/:id(.:format) swimming/classschedules#show
PUT /swimming/classschedules/:id(.:format) swimming/classschedules#update
DELETE /swimming/classschedules/:id(.:format) swimming/classschedules#destroy
How to fix this issue?
UPDATE *it has been fixed*
The issue because I had two blocks of
namespace :swimming do
resources :classschedules do
end
end
in routes.rb
Copying the answer from the comments in order to remove this question from the "Unanswered" filter:
The issue because I had two blocks of
namespace :swimming do
resources :classschedules do
end
end
in routes.rb
~ answer per wwli
Lets say I am creating a new Foo using a form and a standard Rails restful controller, which looks something like this:
class FoosController < ApplicationController
...
def index
#foos = Foo.all
end
def new
#foo = Foo.new
end
def create
#foo = Foo.create(params[:foo])
if #foo.save
redirect_to foos_path, :notice => 'Created a foo.'
else
render 'new'
end
end
...
end
So, if I use the standard restful controller (as above), then when I'm creating the Foo I am at example.com/foos/new, and if I submit the form and it saves correctly I'm at example.com/foos showing the index action. However, if the form is not filled correctly the form is rendered again and error messages are shown. This is all plain vanilla.
However, if errors are shown, the form page will be rendered but the URL will be example.com/foos, because the CREATE action posts to that url. However, one would expect to find Foos#index at example.com/foos, not the form they just submitted now with error messages added.
This seems to be Rails standard behavior, but it doesn't make a lot of sense to me. Obviously I could redirect back to new instead of rendering new from the create action, but the problem with that is the error messages etc. would be lost along with the partially complete Foos in memory.
Is there a clean solution for this problem, a way to send people back to example.com/foos/new when there are errors in the new Foo form they submitted?
Thanks!
To answer your comment on another answer:
I'm wondering if there's a way, without rewriting the controller at all, to tell rails that you want the URL to match the rendered template, rather than the controller action that called it.
I don't think so; URLs are tied directly to routing, which is tied into a controller and action pair--the rendering layer doesn't touch it at all.
To answer your original question, here's information from another similar question I answered.
As you've found, by default when you specify resources :things, the POST path for creating a new thing is at /things. Here's the output for rake routes:
things GET /things(.:format) {:action=>"index", :controller=>"things"}
POST /things(.:format) {:action=>"create", :controller=>"things"}
new_thing GET /things/new(.:format) {:action=>"new", :controller=>"things"}
edit_thing GET /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
thing GET /things/:id(.:format) {:action=>"show", :controller=>"things"}
PUT /things/:id(.:format) {:action=>"update", :controller=>"things"}
DELETE /things/:id(.:format) {:action=>"destroy", :controller=>"things"}
It sounds like you want something more like this:
create_things POST /things/new(.:format) {:action=>"create", :controller=>"things"}
things GET /things(.:format) {:action=>"index", :controller=>"things"}
new_thing GET /things/new(.:format) {:action=>"new", :controller=>"things"}
edit_thing GET /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
thing GET /things/:id(.:format) {:action=>"show", :controller=>"things"}
PUT /things/:id(.:format) {:action=>"update", :controller=>"things"}
DELETE /things/:id(.:format) {:action=>"destroy", :controller=>"things"}
Although not recommended, you can get this result with the following route:
resources :things, :except => [ :create ] do
post "create" => "things#create", :as => :create, :path => 'new', :on => :collection
end
You would also need to modify your forms to make them POST to the correct path.
You could hook into rails routing by adding this in an initializer:
https://gist.github.com/903411
Then just put the regular resources in your routes.rb:
resources :users
It should create the routes and behaviour you are looking for.
You can set up the routing manually, if you're that concerned about what URL is going to show. For what you want, you can have a GET to /foos/new render your form, and a POST to the same URL do the creation:
map.with_options :controller => :foos do |foo|
foo.new_foo '/foos/new', :conditions => {:method => :get}, :action => :new
foo.create_foo '/foos/new', :conditions => {:method => :post}, :action => :create
foo.foos '/foos', :conditions => {:method => :get}, :action => :index
end
This should work without requiring any changes to your controller (yay!) - all three actions from your example are taken care of. The few disclaimers:
This is based on my routing for a 2.3.8 app - some syntax (semantics?) changes are probably required to get it into Rails 3 routing style.
My attempts to mix this style of routing with map.resources have failed horribly - unless you're more familiar with this than me, or Rails 3 routing is better (both easily possible), you'll have to do this for every route to the controller.
And finally, don't forget to add /:id, (.:format), etc. to the routes that need them (none in this example, but see #2).
Hope this helps!
Edit: One last thing - you'll need to hard-code the URL in your form_for helper on /foos/new.html.erb. Just add :url => create_foo_path, so Rails doesn't try to post to /foos, which it will by default (there might be a way to change the creation URL in the model, but I don't know of it, if there is one).
You could use Rack::Flash to store the parameters you wanted in the user's session and then redirect to your form url.
def create
#foo = Foo.new(params[:foo])
if #foo.save
redirect_to foos_path, :notice => 'Created a foo.'
else
flash[:foo] = params[:foo]
flash[:errors] = #foo.errors
redirect_to new_foo_path #sorry - can't remember the Rails convention for this route
end
end
def new
# in your view, output the contents of flash[:foo]
#foo = Foo.new(flash[:foo])
end
I'm having a pretty weird problem with one of my rails apps. I think I'm probably doing something really silly that I just haven't been able to identify. My problem is that, I seem to be missing about half of my index paths.
For example, if my controller is "foos" for a model foo, I'll have the:
foos POST /foos(.:format) {:action=>"create", :controller=>"foos"}
But no GET option which would usually be as:
foos GET /foos(.:format) {:action=>"index", :controller=>"foos"}
Below I'll show you my actually code, to help me recover my missing index routes.
routes.rb:
resource :announcements, :controller => "announcements" do
resources :comments
member do
post 'vote'
end
end
routes for the announcements part:
announcements POST /announcements(.:format) {:action=>"create", :controller=>"announcements"}
new_announcements GET /announcements/new(.:format) {:action=>"new", :controller=>"announcements"}
edit_announcements GET /announcements/edit(.:format) {:action=>"edit", :controller=>"announcements"}
GET /announcements(.:format) {:action=>"show", :controller=>"announcements"}
PUT /announcements(.:format) {:action=>"update", :controller=>"announcements"}
DELETE /announcements(.:format) {:action=>"destroy", :controller=>"announcements"}
As you can see there is no get / index. In my controller, I have the simply index method defined...
def index
#announcements = Announcement.all
respond_to do |format|
format.html
format.xml { render :xml => #announcements }
end
end
I really don't understand why I don't have this index path. It's happening on several other controllers as well. Any help would be appreciated.
Edit: In the console, app.announcements_path returns a method missing error, in addition to the others that have missing index paths.
This is because you're using the singularized version of resources (resource). There is no index action route generated for these. You should change this to be the pluralized version, and remove :controller from the line too.
I am a .NET developer moving to Ruby on Rails. I have been programming in ASP.NET MVC and now trying to apply the same concepts to Rails. I created index action and now when I say home/index it automatically redirects me the "show" action which does not exists. My routes.rb file has this particular line:
resources :home
home is the home_controller.
What am I doing wrong?
class HomeController < ApplicationController
def show
end
# show all the articles
def index
#articles = Array.new[Article.new,Article.new,Article.new]
respond_to do |format|
format.html
format.xml { render :xml => #articles }
end
end
def new
#article = Article.new
respond_to do |format|
format.html
format.xml { render :xml => #article }
end
end
def create
#article = Article.new(params[:post]);
if #article.save
format.html { redirect_to(#post,
:notice => 'Post was successfully created.') }
end
end
def confirm
end
end
You can run "rake routes" to check out what rails thinks about your routes and which urls will be dispatched to which controllers.
In your case, I get:
home_index GET /home(.:format) {:action=>"index", :controller=>"home"}
home_index POST /home(.:format) {:action=>"create", :controller=>"home"}
new_home GET /home/new(.:format) {:action=>"new", :controller=>"home"}
edit_home GET /home/:id/edit(.:format) {:action=>"edit", :controller=>"home"}
home GET /home/:id(.:format) {:action=>"show", :controller=>"home"}
home PUT /home/:id(.:format) {:action=>"update", :controller=>"home"}
home DELETE /home/:id(.:format) {:action=>"destroy", :controller=>"home"}
So to get to the index action, you need to go to "/home". If you go to "/home/index", it will think "index" is the ID of the resource, thus dispatching to the show action.
However, in Rails, it's custom to use plural names for controllers, and naming them after the resource they represent (this is usually a model, but it doesn't have to be). So in your case the name of the controller should be "ArticlesController" and your routes.rb should contain "resources :articles". Rails is very anal about plural and singular names.
The big advantage of using the plural name of the resource you're accessing, is that you can now use short notations, like "redirect_to #article", "form_for #article do |f|", etc.
So, resources in Rails are supposed to be telling about what you want your actually getting. This helps maintenance too, since other developers have to guess less. If you find yourself needing more than one ArticlesController, consider using namespaces, or try to figure out if one of those controllers are actually another resource (even though they store their data in the same database table).
More information about the routers can be found in the Rails Guide: http://guides.rubyonrails.org/routing.html
I'm new to Ruby on Rails, and I'm sure I'm just missing something simple and stupid, but I can't figure out how to get my 'account/signup' action working.
This is what I have in my routs file:
map.connect ':controller/:action'
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
map.root :controller => "home"
I've added this to my accounts controller:
def signup
#account = Account.new
respond_to do |format|
format.html # signup.html.erb
format.xml { #account }
end
end
And I've added signup.html.erb to the accounts views folder.
Yet when I go to it in the browser I get this error:
ActiveRecord::RecordNotFound in AccountsController#show
Couldn't find Account with ID=signup
What am I doing wrong?
Add the following code right on top of your routes.rb file
ActionController::Routing::Routes.draw do |map|
map.connect 'account/signup', :controller => 'account', :action => 'signup'
...
...
...
end
Also I think you mean Account and not Accounts.
Here's a tip:
If you run rake routes it'll show you all the possible routes for your app.
It should then be obvious depending on what URL you are entering whether it'll be correctly resolved or not.
For a good overview of routes read this guide. There's really a lot of stuff you can do with routes so it's worth taking some time to read it.
If you want to follow the REST model, you controller should be called sessions and your signup action should be new, so in your routes you could do :
map.resources :sessions
This website is highly recommended to all newcomers to Rails :
http://guides.rubyonrails.org/
The following will do as well when added to the do |map| section of routes.rb
map.resource :account, :member => {:signup => :get}
Will create the standard routes for your accounts controller, as well as add the new route account/signup. It also provides the usual url helpers in addition to signup_account_url and signup_account_path