Quite a lot has changed since Rails 1 and I'm really impressed by the people who are willing to spend the time to sit down with Rails 3 and learn the differences (1). The community needs to be welcoming to these and the RTFM'ers aren't being helpful. This is where I think I can help out.
I would write that like this in Rails 3:
<%= form_for(@album) do |f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :artist %>
<%= f.text_field :artist %>
</p>
<p>
<%= f.label :genre %>
<%= f.text_field :genre %>
</p>
<p>
<%= f.label :release_date %>
<%= f.datetime_select :release_date %>
</p>
<%= f.submit %>
<% end %>
Woah, so many changes! Where do we begin? The top line, of course!
form_for
is a method that's been in Rails for a while and has become exceedingly useful over the past couple of major revisions. This method will take the @album
variable set up in the controller and inspect it to determine a couple of things 1) where the form should go 2) what the values of the fields should be.
I should mention at this stage that it should be mentioned that your app/views/albums/new.html.erb
should now look like this:
<h2>New Album</h2>
<%= render "form" %>
OMG, more new stuff! It's ok: render "form"
will render the app/views/albums/_form.html.erb partial. This is where the above form_for
tomfoolery should live now. Why? Let me continue explaining.
In your AlbumsController
's new
action, you'd have something like this:
def new
@album = Album.new
end
form_for
is smart enough to go: "hey, that's a new Album
resource, he probably wants to go to the create
action for this form because he's being a good lad and following the Rails conventions", so that's precisely what it'll do.
Except:
This will raise an exception that there's no albums_path
method defined. What the?
In Ruby on Rails 2, RESTful routing became a Big Thing. It's best if you read the routing guide, since if I explained it I would only be repeating a lot of it. Basically: RESTful routing is a convention for the URL routes of your application that determines that when we do a POST (it's a form, remember?) to /albums, this will go to the create
action.
But how does Rails know to do this?
Because in your config/routes.rb file you've put this line:
resources :albums
This defines routes to "The Seven" default actions of your controller (index, show, new, create, edit, update and destroy). Seriously, read the routing guide to know all about this beauty.
So back to our little form_for
. It knows to go to /albums
for a new object, which is cool and all. So what's up with the f
block argument? Well, this is a form builder object which allows us to build form elements for the specific Album
object from our new
(and soon, edit
) actions. When we call:
<%= f.text_field :title %>
We are doing the Rails 1 equivalent of:
<%= text_field :album, :title %>
It's just a little bit of syntatic sugar that Rails gives you in order to make your views more DRY.
I also added labels to your form because users need to know what the fields are that they're filling in. The beautiful part here is that the user won't see :title
, but will see Title
instead. For :release_date
, they'll see "Release Date". Beautiful.
At the end of the form, I use f.submit
. This will generate a submit button that says either "Create Album" if @album
is a new object, or "Update Album" if it's a pre-existing object. But where do the pre-existing objects get edited?
In the edit
action!
def edit
@album = Album.find(params[:id]
end
In your app/views/albums/edit.html.erb file you'd have much the same you have in its new.html.erb sibling:
<h2>Editing Album</h2>
<%= render "form" %>
You can use precisely the same line in both of these to render the same partial, but it will perform differently if the object is new or if it is pre-existing (commonly referred to as persisted).
In the case of the edit
action rendering this partial, it will generate a route to /albums/1
for the form and do a Rails-specialty PUT
request to this resource. Another thing the routing guide will explain very well, I hope.
I'm sorry for the length of this answer but there's no real short answer for this question, it's quite a large change but trust me when I say it really is for the better.
Rails 3 rocks.
(1) Less so with the people who aren't.