In this lesson, we'll code a create
action — 'C' in the 'CRUD' life
cycle — that saves a new Post
object and then redirects to the newly-created
post's show
page.
Before implementing this functionality, let's first open up a Rails console session and create a record manually:
post = Post.new
post.title = "Title Goes Here"
post.description = "Desc goes here..."
post.save
This syntax will let you manually create a new Post
record with title
and
description
attributes. After running the save
method in the console, you
will see output similar to the following:
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "posts" ("title", "description", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "Title Goes Here"], ["description", "Desc goes here..."], ["created_at", "2015-11-23 22:26:43.799742"], ["updated_at", "2015-11-23 22:26:43.799742"]]
(1.2ms) commit transaction
=> true
As you can see, the save
method generates a SQL script that inserts a new
record into the database. Each of the Post
object's attributes is passed into
the SQL statement, and the method returns true
upon a successful save. At a
high level, this is what the create
method in our PostsController
will be
doing.
Open up the posts_controller.rb
file. Let's do a few things to replicate the
behavior we had in the console:
-
Create a new
Post
instance -
Pass in the parameters from the form
-
Save the record
To build this behavior initially, let's copy and paste the code that we ran in
the console. The only key difference is that now, instead of assigning
post.title
and post.description
manually, we want to be able to pull in form
data - stuff that a user has typed in and submitted. As long as the form is
properly connected to the controller and model, we can populate the title
and
description
attributes based on the user input:
def create
post = Post.new
post.title = params[:title]
post.description = params[:description]
post.save
end
You can access each of input values in a form using the hash syntax to grab the
elements from the params
hash. When a user submits a form, it is the params
hash that contains all the input data. As long as the form is routed to the
create
method we've written (in config/routes.rb
), we'll be able to
initialize a new instance of Post
, grab those input values from params
,
assign them the post
instance attributes and save the instance to our
database.
We've already got the route and our form created. If you go to /posts/new
,
fill out the form, and submit it, you'll get the error shown below.
That's OK! Rails is simply complaining that it can't find a create
view
template since, by default, it's trying to render a template called
create.html.erb
(which doesn't exist). Remember, Rails tries to map each
controller action directly to a template. However, with actions like create
,
we don't want a view template –– all we want is for the action to communicate
with the database and then redirect to a different page.
If you open up the console, you'll see that the record was successfully created
in the database even though we ran into an error page. Our form and create
action are working properly. How do we know the record was successfully created?
There are a couple of ways to check:
-
Type
Post.last
into the Rails console, and it will display the most recently created record. We can look at the record'screated_at
attribute to ensure the timestamp is current. -
We can also simply scroll up through the Rails server logs. All SQL statements are printed out in the log, so it's just a matter of locating the correct
INSERT
statement (example below):
(0.1ms) begin transaction
SQL (0.7ms) INSERT INTO "posts" ("title", "description", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "My Post"], ["description", "My desc"], ["created_at", "2015-12-26 18:00:31.393419"], ["updated_at", "2015-12-26 18:00:31.393419"]]
(2.2ms) commit transaction
To fix the 'missing template' error, we simply need to redirect the user after they've filled out the form. Let's do two refactors:
-
Update the code with a redirect that leverages a route helper method
-
Refactor the
post
variable into an instance variable
The revised create
method should look something like this:
def create
@post = Post.new
@post.title = params[:title]
@post.description = params[:description]
@post.save
redirect_to post_path(@post)
end
In this refactored create
action, we're following the convention of
redirecting to the new resource's show
page. It stands to reason that a user
who submits a new post would then like to view the successfully-created post.
With that being said, the page flow is not set in stone, and we could've
redirected the create
action to the index
action just as easily.
All our tests should be passing now, and the site is working in the browser.
Users are able to create records in the database using the HTML form, and, upon
submitting a new post, they're automatically redirected to the show
page for
the post they just created. In future lessons, we'll refactor this further to
incorporate awesome Rails components like strong parameters
and error handling
, but don't worry about those yet. Great job!