sábado, 18 de março de 2017

RAILS Using Scaffold to create CRUD application on PostgreSQL

1. Introduction

This post shows how to create a simple application using scaffolding generator connectiong to PostgreSQL.


2. Step-by-Step

2.1. Create application named 'weblog' using 'PostgreSQL' database

$ pwd
/home/rails-home
$ rails new weblog -d postgresql
$ cd weblog
$ pwd
/home/rails-home/weblog


2.2. Generate scaffold CRUD for 'post' entity with attributes title:string and body:string

a. Generate scaffold

$ rails generate scaffold post title:string body:text
Running via Spring preloader in process 2854
      invoke  active_record
      create    db/migrate/20170318144830_create_posts.rb
      create    app/models/post.rb
        :            :
      invoke  resource_route
       route    resources :posts
      invoke  scaffold_controller
      create    app/controllers/posts_controller.rb
      invoke    erb
      create      app/views/posts
      create      app/views/posts/index.html.erb
      create      app/views/posts/edit.html.erb
      create      app/views/posts/show.html.erb
      create      app/views/posts/new.html.erb
      create      app/views/posts/_form.html.erb
        :            :
      invoke    jbuilder
      create      app/views/posts/index.json.jbuilder
      create      app/views/posts/show.json.jbuilder
      create      app/views/posts/_post.json.jbuilder
        :            :


b. Checking what scaffold has done: 

(i) migration script

$ cat db/migrate/*_create_posts.rb
class CreatePosts < ActiveRecord::Migration[5.0]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :body
      t.timestamps
    end
  end
end

(ii) model for application

$ cat app/models/post.rb
class Post < ApplicationRecord
end

(iii) controller with actions new, create, ..., destroy

$ cat app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]
    :
  def index
    :
  end
    :
  def show
    :
  end
    :
  def new
    :
  end
    :
  def edit
    :
  end
    :
  def create
    :
  end
    :
  def update
    :
  end
    :
  def destroy
    :
  end
    :
  private
    def set_post
    :
    end
    :
    def post_params
    :
    end
    :
end

(iv) views

$ ls -la app/views/posts
total 36
drwxr-xr-x. 2 root root 4096 Mar 18 11:48 .
drwxr-xr-x. 4 root root   32 Mar 18 11:48 ..
-rw-r--r--. 1 root root  123 Mar 18 11:48 edit.html.erb
-rw-r--r--. 1 root root  579 Mar 18 11:48 _form.html.erb
-rw-r--r--. 1 root root  591 Mar 18 11:48 index.html.erb
-rw-r--r--. 1 root root   53 Mar 18 11:48 index.json.jbuilder
-rw-r--r--. 1 root root   88 Mar 18 11:48 new.html.erb
-rw-r--r--. 1 root root  104 Mar 18 11:48 _post.json.jbuilder
-rw-r--r--. 1 root root  227 Mar 18 11:48 show.html.erb
-rw-r--r--. 1 root root   40 Mar 18 11:48 show.json.jbuilder



c. Start RAILS server and observe what scaffold does for us

i) Configure RAILS on to listen for all interfaces

$ vim ./config/boot.rb
        :
      super.merge(Host:  '0.0.0.0', Port: 3000)
        :

ii) Create databases DEV and PROD using

$ rake db:create

iii) Create database tables using migrate

$ rails db:migrate

iv) Run rails server

$ rails server

v) Check results


  • http://localhost:3000 - See Yay! You're on Rails!
  • http://localhost:3000/posts - Simple CRUD application for Posts, you can do: new, show, edit, destroy
  • http://localhost:3000/posts.json - JSON object representing all posts:  [{"id":1,"title":"1","body":"first","created_at":"2017-03-18T15:15:30.015Z","updated_at":"2017-03-18T15:16:05.960Z","url":"http://localhost:3000/posts/1.json"}]


2.3. Adding some validation 

  • Edit model and add validation rule
$ vim app/models/post.rb
class Post < ApplicationRecord
  validates_presence_of :title
end

  • Try to create a post without title and observe error validation:      1 error prohibited this post from being saved:  Title can't be blank

2.3. Creating Comment model reference Post  (master detail)

a. Create resource comment referencing post

$ rails generate resource comment post:references body:text
Running via Spring preloader in process 3025
      invoke  active_record
      create    db/migrate/20170318185201_create_comments.rb
      create    app/models/comment.rb
      invoke    test_unit
      create      test/models/comment_test.rb
      create      test/fixtures/comments.yml
      invoke  controller
      create    app/controllers/comments_controller.rb
      invoke    erb
      create      app/views/comments
      invoke    test_unit
      create      test/controllers/comments_controller_test.rb
      invoke    helper
      create      app/helpers/comments_helper.rb
      invoke      test_unit
      invoke    assets
      invoke      coffee
      create        app/assets/javascripts/comments.coffee
      invoke      scss
      create        app/assets/stylesheets/comments.scss
      invoke  resource_route
       route    resources :comments

b. Run migrate to create database table for 'comment'

$ rails db:migrate
== 20170318185201 CreateComments: migrating ===================================
-- create_table(:comments)
   -> 0.1987s
== 20170318185201 CreateComments: migrated (0.1988s) ==========================

c. Configure nesting of routes on post controller to comment'

$  vim config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments
  end
end

d. Check routes created

$ rails routes
           Prefix Verb   URI Pattern                                 Controller#Action
    post_comments GET    /posts/:post_id/comments(.:format)          comments#index
                  POST   /posts/:post_id/comments(.:format)          comments#create
 new_post_comment GET    /posts/:post_id/comments/new(.:format)      comments#new
edit_post_comment GET    /posts/:post_id/comments/:id/edit(.:format) comments#edit
     post_comment GET    /posts/:post_id/comments/:id(.:format)      comments#show
                  PATCH  /posts/:post_id/comments/:id(.:format)      comments#update
                  PUT    /posts/:post_id/comments/:id(.:format)      comments#update
                  DELETE /posts/:post_id/comments/:id(.:format)      comments#destroy
            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

e. Check model 'comment' created

$ cat app/models/comment.rb
class Comment < ApplicationRecord
  belongs_to :post
end

f. Adjust 'post' model to has many of 'comment' models

$ vim app/models/post.rb
class Post < ApplicationRecord
  has_many :comments
  validates_presence_of :title
end


2.4. Edit view of 'post' to show related 'comments'

a. Edit view 'show' of 'post' - add code to show related comments

$ vim app/views/posts/show.html.erb
          :
<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>
<br><br>
<h2>Comments</h2>
  <div id="comments">
    <%# Expands to render partial: 'comments/comment', collection: @post.comments %>
    <%= render @post.comments %>
  </div>
    <%= render 'comments/new', post: @post %>
  </div>

b. Edit view templates '_form' and '_new' of 'Comment'

$ vim  app/views/comments/_new.html.erb
<%= form_for([ @post, Comment.new ], remote: true) do |form| %>
  Your comment:<br>
  <%= form.text_area :body, size: '50x20' %><br>
  <%= form.submit %>
<% end %>

$ vim app/views/comments/_comment.html.erb
<p><%= comment.body %> -- <%= comment.created_at.to_s(:log) %><p>

c. Implement 'comment' controller actions 

$ vim app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  before_action :set_post

  def create
    @post.comments.create! comments_params
    redirect_to @post
  end

  private
    def set_post
      @post = Post.find(params[:post_id])
    end

    def comments_params
      params.required(:comment).permit(:body)
    end

end


3. References



Nenhum comentário:

Postar um comentário