Create Action Requires POST

UPDATE: I wrote the whole post below, and then I figured it out...oy, the risks of auto-generated code. Typically, I use script/generate scaffold to build my controllers and views, then I start modifying from there. The risk of using auto-generated code is that you don't know every detail...and, if you're gonna own a program, you gotta know ever detail.

Long story short: I started digging around at .../verification.rb and I finally ended up back at my own controller and found this that scaffold sticks this bit of code in at the top of every controller:

# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, :only => [ :destroy, :create, :update ],
:redirect_to => { :action => :list }

which is why I wasn't able call create with a GET. Yikes!




Boy, what a morning! I found a "feature" of Rails that I don't quite understand yet, but it certainly caused me a lot of headache. Maybe somebody else who is frustrated will benefit from this information.

Long story short: if you are going to call the create action in a controller, then you can only do so via POST. If you try to do so via GET you will get an error like the one below. In other words:

<html>
<body>
Form with POST method --> works
<form action="/books/create" method="post">
<input type="submit" name="submit" value="submit">
</form>

Form with GET method --> does not work
<form action="/books/create" method="get">
<input type="submit" name="submit" value="submit">
</form>
</body>
</html>

Apparently, Rails has some sort of before_filter that requires certain types of actions to be called via certain HTTP methods. (Note: I am not using any of the Rails RESTful stuff, e.g. map.resources.)

I have yet to figure out exactly what filter causes this requirement. Also, I would be interested in knowing if there is a way to inspect all the before filters that will be run for a given action or controller. If you know, please post in the comments.

Special thanks to Dirkjan for helping me debug this far.

From development.log

Processing BooksController#create (for 127.0.0.1 at 2007-09-11 10:53:22) [GET]
Session ID: e042ea5ba771fd5423d39369ec8e1227
Parameters: {"action"=>"create", "controller"=>"books", "journal_id"=>"1"}
Redirected to http://localhost:3005/books/list
Filter chain halted as [#<ActionController::Filters::ClassMethods::ProcFilter:0x47e198c @filter=#<Proc:0x0391ce4c@C:/InstantRails-1.7-win/InstantRails/ruby/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/verification.rb:74>>] returned false.
Completed in 0.01000 (100 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/books/create?journal_id=1]


Processing BooksController#list (for 127.0.0.1 at 2007-09-11 10:53:22) [GET]
Session ID: e042ea5ba771fd5423d39369ec8e1227
Parameters: {"action"=>"list", "controller"=>"books"}
Book Columns (0.010000) SHOW FIELDS FROM books
SQL (0.000000) SELECT count(*) AS count_all FROM books 
Book Load (0.000000) SELECT * FROM books LIMIT 0, 10
Rendering within layouts/books
Rendering books/list
Completed in 0.03000 (33 reqs/sec) | Rendering: 0.01000 (33%) | DB: 0.01000 (33%) | 200 OK [http://localhost/books/list]

No comments: