Featured image of post Simple Blog with Rails #1

Simple Blog with Rails #1

Let's create a simple blog website by using Ruby on Rails !

This project made based on Rails Tutorial | Building a Blog with Ruby on Rails 6 using Rails 6.1.6 and Ruby 2.6.3p62. I am curious whether Rails can be used to make a blog like Wordpress so then I tried to follow this tutorial.

Generate New Project

Gem Configuration

Generate new project by running rails new simple-blog. Go to project folder cd simple-blog and open up Gemfile then commented out gem ‘jbuilder’ since we don’t want to generate JSON or API like project. And add gem devise for authentication then run bundle.

1
2
3
4
5
6
...
# gem 'jbuilder', '~> 2.7'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.4', require: false
gem 'devise'
...

Run rails g controller Home index in the terminal. This will create Home Controller with index action. It will be deleted later but for now we just want to have home index. So if we run local server rails s and go to localhost:3000 page on the web browser, we will see home page index.

Setting Authentication with devise

Lets create devise modal rails g devise:install and this is gonna take us to few things that we need to care. Follow the step and run rails g devise:views in the terminal.

Then let’s create modal called Author with login authentication, rails g devise Author, then migrate it, rails db:migrate. Then try to open localhost:3000/authors/sign_up on the browser and we’ll see a sign-up page. Try to sign-up your first account and, TA-DA, you’ve got authentication set up in just a couple of minutes.

Create Post and Author Authentication

Generate post modal by running this line in the terminal. This command will create field title - since we don’t specify the data type, it will generate string type -, published, published_at and author.

1
rails g scaffold Post title description:text published:boolean published_at:datetime author:references

Then try run localhost:3000/posts on your browser and play around with it and see how it all works.

Create Authentication for Post

We want to post only can be accessed when Author get authentication so we move posts resources under Author scope in route

1
2
3
4
5
6
...
  root to: "home#index"
  scope module: 'authors' do
    resources :posts
  end
end

Then try to see the result localhost:3000/posts and you’ll get a ‘Routing Error - uninitialized constant Authors’ because, instead of PostsController, it’s wanting to look at Authors::PostsController. To solve this, create new folder called authors under app/controllers and move post_controller.rb in it. Also in that file, wrap up all existing code inside module Authors / end.

And now go back to web browser and refresh. Oh no, You still see an error ‘No template for interactive request’. To solve this, you just need to crate new folder authors under app/views and move folder posts into the authors folder.

Check again the page and now it should work.

Create one-many relation for Author and Post

Add relationship between posts and author ‘has_many :posts’ in the file app/models/author.rb so the code looks like

1
2
3
4
5
6
...
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :posts
end

Enable Authentication

Create new controller called authors_controller.rb under app/controllers folder, put this line in the file,

1
2
3
class AuthorsController < ApplicationController
  before_action :authenticate_author!
end

save it and change inherit code from class PostsController < ApplicationController to class PostsController < AuthorsController in the posts_controller.rb file.

Let’s try run localhost:3000/posts and perhaps there is no differences since you’ve just sign up new account. Open another browser and access the address, then you see the new browser redirect to login page.

Author Layout

Specify layout for author in the authors_controller.rb file

1
2
3
4
class AuthorsController < ApplicationController
  before_action :authenticate_author!
  layout 'authors'
end

Refresh page localhost:3000/posts in the browser then you get error ‘Tempate is missing’. Solving this error, you need to create new template file called authors.html.erb in the folder app/views/layouts and copy all codes in application.html.erb to the new file.

Setting Post Layout

Setting bootstrap

Open BootstrapCDN on web browser and copy bootstrap.min.css into authors.html.erb file and paste under head tag. Next, Go to app/stylesheets and delete scaffold.scss file.

Setting Post Controller

In the file app/views/authors/posts/_form.html.erb, take away publish and author related fields.
Edit posts_controller.rb. Change POST to ‘current_author.posts’ in ‘set_index’, ‘create’, ‘index’ and ’new’.
Delete unwanted fields that we want to send from form so the final codes look like

Setting Author Layout

Edit parent layout app/layouts/authors.html.erb so that ‘<%= yield %>’, code that place chlid template, wrap in class container

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
...
  </head>

  <body class="bg-light">
    <div class="container">
      <p class="notice"><%= notice %></p>
      <p class="alert"><%= alert %></p>
      <%= yield %>
    </div>
  </body>
</html>

Setting Posts Layout

Edit child page layout for index action ‘app/views/authors/posts/index.html.erb’

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<h4 class='d-flex justify-content-between'>
  <span>Posts</span>
  <%= link_to 'New Post', new_post_path, class: 'btn btn-primary' %>
</h4>

<% @posts.each do |post| %>
  <%= link_to edit_post_path(post), class: 'text-decoration-none' do %>
  <div class="card mb-3">
    <div class="card-body">
      <h5 class="card-title mb-1 text-dark"> <%= post.title %> </h5>
      <p class="text-secondary mb-0"> <%= post.description %> </p>
    </div>
  </div>
  <% end %>
<% end %>

In here, we also change link to access post-edit layout instead of showing posts, then remove template to show them. Delete the file ‘app/views/authors/posts/show.html.erb’. The next, ‘show’ action def and ‘show’ symbol in before_action in the file ‘posts_controller.rb’ shall be removed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
module Authors 
  class PostsController < AuthorsController
  before_action :set_post, only: [:edit, :update, :destroy]
  
    # GET /posts
    def index
      @posts = current_author.posts
    end
  
    # GET /posts/new
    def new
      @post = current_author.posts.build
    end
  
    # GET /posts/1/edit
    def edit
    end
  
    # POST /posts
    def create
      @post =  current_author.posts.build(post_params)
  
      if @post.save
        redirect_to @post, notice: 'Post was successfully created.'
      else
        render :new
      end
    end
  
    # PATCH/PUT /posts/1
    def update
      if @post.update(post_params)
        redirect_to @post, notice: 'Post was successfully updated.'
      else
        render :edit
      end
    end
  
    # DELETE /posts/1
    def destroy
      @post.destroy
      redirect_to posts_url, notice: 'Post was successfully destroyed.'
    end
  
    private
      # Use callbacks to share common setup or constraints between actions.
      def set_post
        @post = current_author.posts.find(params[:id])
      end
  
      # Only allow a list of trusted parameters through.
      def post_params
        params.require(:post).permit(:title, :description)
      end
  end
end

menit 26:53

. . . . .

Create Element

1
rails g scaffold Element element_type:string content:text post:references position:integer --skip-template-engine

run db:migrate and move file elements_controller.rb from controllers folder into controllers/authors folder. Wrap all existing codes into module Authors and end tags. Then change enherit tag class ElementsController < ApplicationController to class ElementsController < AuthorsController.

In the route.rb we want to make element nested in the post resource so the code will look like

1
2
3
4
5
6
7
...
  scope module: 'authors' do
    resources :posts do
      resources :elements
    end
  end
end

Check the routes for element by running rails routes | grep element in the terminal.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy