Tuesday, April 18, 2017

The Codes inside Getting Started with Rails

In my previous blog, I have demonstrated how to download my sample codes from https://github.com/jimmy2046/gettingstarttedwithrails. The sample codes are the finished work from Getting Started with Rails - http://guides.rubyonrails.org/getting_started.html.

I want to show the codes inside Getting Started with Rails very quickly and briefly.

~/gettingstarttedwithrails/app/views/welcome/index.html.erb shows the welcome page when a user goes to http://localhost:3000/
<h1>Hello, Rails!</h1>
<%= link_to 'My Blog', controller: 'articles' %>

~/gettingstarttedwithrails/config/routes.rb defines the routing table when a user calls a specific controller:
Rails.application.routes.draw do
#  get 'welcome/index'

  resources :articles do
    resources :comments
  end

  root 'welcome#index'

end

app/controllers/articles_controller.rb defines the actions when the user wants to do with the articles, such as index (list), new (create), edit, update. It also defines user name and password are required for all actions except index and show.
class ArticlesController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]

  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def edit
    @article = Article.find(params[:id])
  end

def create
  @article = Article.new(article_params)

  if @article.save
    redirect_to @article
  else
    render 'new'
  end
end

def update
  @article = Article.find(params[:id])

  if @article.update(article_params)
    redirect_to @article
  else
    render 'edit'
  end
end

def destroy
  @article = Article.find(params[:id])
  @article.destroy

  redirect_to articles_path
end

private
  def article_params
    params.require(:article).permit(:title, :text)
  end
end


app/views/articles/new.html.erb defines the format of the HTML page when a user wants to add a new article.
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>

db/migrate/20170414223939_create_articles.rb defines the database meta data of the articles during migration:
class CreateArticles < ActiveRecord::Migration[5.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :text

      t.timestamps
    end
  end
end

app/views/articles/show.html.erb specifies the format when a user reads the details of an articles:
<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>

<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>

<h2>Comments</h2>
<%= render @article.comments %>

<h2>Add a comment:</h2>
<%= render 'comments/form' %>

<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

app/views/articles/index.html.erb lists out all the articles in the blog:
<h1>Listing articles</h1>
<%= link_to 'New article', new_article_path %>
<table>
  <tr>
    <th>Title</th>
    <th>Text</th>
    <th colspan="3"></th>
  </tr>

  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
      <td><%= link_to 'Edit', edit_article_path(article) %></td>
      <td><%= link_to 'Destroy', article_path(article),
              method: :delete,
              data: { confirm: 'Are you sure?' } %></td>
    </tr>
  <% end %>
</table>

app/models/article.rb defines the foreign keys, minimum text length and not null column of the datatype:
class Article < ApplicationRecord
  has_many :comments, dependent: :destroy
  validates :title, presence: true,
                    length: { minimum: 5 }
end

app/views/articles/edit.html.erb renders the edit page in HTML when a registered user wants to edit an article:
<h1>Edit article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>

app/views/articles/_form.html.erb defines the template of article. It encourages code reuse and avoid the repeating portion of files: new.html.erb and edit.html.erb:
<%= form_for @article do |f| %>

  <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2>
        <%= pluralize(@article.errors.count, "error") %> prohibited
        this article from being saved:
      </h2>
      <ul>
        <% @article.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <p>
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </p>

  <p>
    <%= f.label :text %><br>
    <%= f.text_area :text %>
  </p>

  <p>
    <%= f.submit %>
  </p>

<% end %>

db/migrate/20170414232923_create_comments.rb specifies the data type and foreign key during database migration:
class CreateComments < ActiveRecord::Migration[5.0]
  def change
    create_table :comments do |t|
      t.string :commenter
      t.text :body
      t.references :article, foreign_key: true

      t.timestamps
    end
  end
end

app/models/comment.rb specifies the foreign keys of table comment:
class Comment < ApplicationRecord
  belongs_to :article
end

app/controllers/comments_controller.rb controls the actions related to comment model, such as create a new comment and destroy (delete) a comment. User name and password are required for destroying a comment:
class CommentsController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy

  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end

  def destroy
    @article = Article.find(params[:article_id])
    @comment = @article.comments.find(params[:id])
    @comment.destroy
    redirect_to article_path(@article)
  end

  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end

app/views/comments/_comment.html.erb re-factors the reused portion for displaying comments in files: show.html.erb
<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>

<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>

<p>
  <%= link_to 'Destroy Comment', [comment.article, comment],
               method: :delete,
               data: { confirm: 'Are you sure?' } %>
</p>

app/views/comments/_form.html.erb re-factors the reused portion for submitting a comment in a form:
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

These are the summary of the codes. Unlike web application development using C#, Microsoft Entity Framework, ASP or Java, the Model-View-Controller (MVC) model in Ruby on Rails requires very little or no programming logics, such as if-then-else statement, loops, SQL statement in traditional programming languages.

No comments:

Post a Comment

How to kill an abandoned process in Linux/Unix

I remembered it, then I forgot, then I remembered it, and then I forgot again. In case of a Linux/Unit process hang, I have to figure out ...