Creating Simple Blogging Platform - Displaying Posts
By: Lukasz Muzyka, On:
This tutorial assumes you have already completed:
- Install Ruby on Rails
- Create Ruby on Rails application
- Create Static Pages - without this deploy will not work
- Install Git
- Create Remote Git Repository - optional but recommended
- Deploy application to Heroku
- Manage users with Devise
- How to add Twitter Bootstrap to Ruby on Rails application - Advised
- Creating Simple Blogging Platform - Creating Model
- Creating Simple Blogging Platform - Routes
We have created routes that allow us to type in our browser the address that matches "action" in our "controller." But, what are controllers and actions? In simple terms, controller is the entity on our code that is dedicated to manage certain resource. In our case, it will be posts. Controller is the place where we will decide on the logical interaction between our app and users. Action, on the other hand, is a "subset" of a controller. For example, we will have an action that creates a post.
In our tutorial, we will look at 7 standard actions:
Action Name | Role |
---|---|
Show | Displaying single record |
Index | Displaying list of records |
New | Displaying form new record |
Create | Saving new record to the database |
Edit | Displaying form for editing of a record |
Update | Saving changes made in "edit" form |
Destroy | Deleting record |
Step 1: Create controller
We will look at those one by one as we're building our application, but first lets generate new, empty controller for posts.
bash
$ rails generate controller posts
create app/controllers/posts_controller.rb
invoke erb
create app/views/posts
invoke test_unit
create test/controllers/posts_controller_test.rb
invoke helper
create app/helpers/posts_helper.rb
invoke test_unit
create test/helpers/posts_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/posts.js.coffee
invoke scss
create app/assets/stylesheets/posts.css.scss
Notice that we are using plural 'posts.' When we were generating model we used singular, capitalized "Post." This is Rails convention.
Quick Tip: For your models' names, always use nouns that have plural forms. Otherwise, controllers and models might have problems communicating properly.
Step 2: Display Posts and Define Action
There are 2 actions that are made for displaying records: "Show" and "Index". First, we will look at index. Open the newly created posts_controller.rb
/app/controllers/posts_controller.rb
class PostsController < ApplicationController
end
We'll start by defining our index action:
class PostsController < ApplicationController
def index
end
end
We just added an empty block
that starts with declaration def index
and ends with end
like almost anything in rails. Always remember about closing your blocks with end
. If you forget to do it, you will evoke an error that looks like this:
Step 3: Create HTML Template
After we've created the action in the controller, we need to build a HTML template for the action to display. To start, we will create a simple file with one line of HTML inside of the app/views/posts
folder and call it index.html.erb
:
/app/views/posts/index.html.erb
<h1>This will be a list of posts</h1>
Because we call the template the same as our action - "index". Rails will match them together so we don't need to specify anywhere that we want these two files to work together. Now, we can restart our application with rails server
and open the URL that points to the index: http://localhost:3000/posts
Great, we know that our application works. Next thing we need to do is to actually display all the posts that we have in our database. This is 2 step processes:
- First: we need to find posts in the database - controller
- Second: display list as a website - HTML template (view)
Step 4: Modify Controller
Let's open controller and add some code:
/app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all
end
end
@posts
- is a name of the variable that we will use to store the posts that we have found in the database. For now, we will just pull all the posts we can find. Of course, we will have to find a better way in case there are a lot of posts in our database. But for now, we're ok with this simple approach.
Step 5: Modify HTML Template
By giving our variable a "@" symbol we've allowed it to travel from controller to the view (HTML template). Therefore, we can now use it to iterate over the list of posts.
/app/views/posts/index.html.erb
<h1>This is a list of posts</h1>
<ul>
<% @posts.each do |p| %>
<li>
<h3><%= p.title %></h3>
<p><%= p.body %></p>
</li>
<% end %>
</ul>
Now head to http://localhost:3000/posts
Step 6: Use Bootstrap
At this point, we can add posts to links in our website menu so we don't need to type URL by hand each time we want to go to the list of posts. We will take an advantage of Bootstrap CSS. In application.html.erb
add the following code:
/app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %> alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<%= value %>
</div>
<% end %>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<%= link_to "Demo App", root_path, class: 'navbar-brand' %>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><%= link_to 'Posts', posts_path %></li>
<% if current_user %>
<li><%= link_to 'Logout', destroy_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to 'Login', new_user_session_path %></li>
<% end %>
</ul>
</div>
</div>
</nav>
<div class="container">
<%= yield %>
</div>
</body>
</html>
Step 7: Define Action inside Controller
Let's move on and add a dedicated page to display individual posts. This will be the page where eventually we can add some sort of commenting system.
First, same as before, we need to define action inside the controller:
/app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all
end
def show
end
end
Step 8: Match Names
Second, we need the HTML template in /app/views/posts
folder that matches name of the action show.html.erb
/app/views/posts/show.html.erb
<h1>This will be a individual post page</h1>
Step 9: Run Rake Routes
Now, the question is: When users type the address of a post, how do we find the post using that URL? Let's look at the routes that we have previously created:
bash
$ rake routes
posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PATCH /posts/:id(.:format) posts#update PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy
Let's have a look at this list closer this time.
Route Name | Request Type | URI | Controller#Action | Needs :ID |
---|---|---|---|---|
posts | GET | /posts(.:format) | posts#index | no |
POST | /posts(.:format) | posts#create | no | |
new_post | GET | /posts/new(.:format) | posts#new | no |
edit_post | GET | /posts/:id/edit(.:format) | posts#edit | YES |
post | GET | /posts/:id(.:format) | posts#show | YES |
PATCH | /posts/:id(.:format) | posts#update | YES | |
PUT | /posts/:id(.:format) | posts#update | YES | |
DELETE | /posts/:id(.:format) | posts#destroy | YES |
Step 10: Understand Columns
The first column shows the path that we can use to create a link. We will add to it either _path
or _url
to build a link to the index page:
<%= link_to "All Posts", posts_path %>
We simply took prefix posts
added _path
to it and rails now knows we want to create a link to controller for posts and action index.
The second column is a method to transfer information between the server and the browser. Basically GET means that the browser "gets" data from the server and anything else (PUT POST PATCH DELETE) is the data going from the browser to the server. For example "edit" gets post form the server. This form will come populated with existing posts title and body. When we click "Save" this will be send to the server to "update" action using PUT.
The third Column is the URI (Uniform Resource Identifier). This is, more or less, what we will see in the URL bar in our browser. One important thing to notice here are all symbols with ":". Those parameters are required by our router in order to point us in the right direction. Let's take edit_post
as an example. URI here is /posts/:id/edit(.:format)
. :id
is an identifier of the post itself. We will use it to find the post in the database. For example, if we want to edit post with ID number 124 the URl would be: http://localhost:3000/posts/124/edit.
I have added one column for you to see clearly which action requires passing the parameters with it.
Fourth column indicated which action of which controller the route is pointing to.
Step 11: Use Parameter and Edit HTML Files
With all this information, we can go back to the controller and find our individual post using parameter form URI.
/app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all
end
def show
@post = Post.find(params[:id])
end
end
This time we created variable @post
inside of which we save result of a query on all posts using :id
as a parameter. This id comes from the URI. We can now use this variable to display the post on its page.
/app/views/posts/show.html.erb
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
Finally, go to the index.html.erb
file, we just need to change title
of post
into a link to the show page.
/app/views/posts/index.html.erb
<h1>This is a list of posts</h1>
<ul>
<% @posts.each do |p| %>
<li>
<h3><%= link_to p.title, post_path(p.id) %></h3>
<p><%= p.body %></p>
</li>
<% end %>
</ul>
Above you can see how we added _path
to post
prefix and used p.id
to provide param for the link.
Comment
You can login to comment