1. Introduction
This post gathers information about creating a Ruby on RAILS application with PostgreSQL2. Step-by-step
2.1. Create a Ruby on RAILS with PostgreSQL database
$ pwd/home/rails-home
$ rails new myrailsapppostgres -d postgresql
2.2. Grant PostgreSQL database permission for administration user 'root' used on RAILS
$ psqlpostgres=# CREATE USER root WITH PASSWORD 'root';
postgres=# GRANT postgres TO root;
postgres=# ALTER USER root CREATEDB;
postgres=# \q
2.3. Create RAILS database
$ pwd/home/rails-home/myrailsapppostgres
$ rake db:create
Created database 'myrailsapppostgres_development'
Created database 'myrailsapppostgres_test'
2.4. Configure RAILS to listen for any 0.0.0.0 IP adddress on Port 3000 (default is 127.0.0.1:3000)
$ pwd/home/rails-home/myrailsapppostgres
$ vim ./config/boot.rb
:
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
:
2.5. Create Welcome page
$ pwd/home/rails-home/myrailsapppostgres
$ rails generate controller Welcome index
$ vim app/views/welcome/index.html.erb
<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>
$ vim config/routes.rb
Rails.application.routes.draw do
get 'welcome/index'
root 'welcome#index'
end
2.6. Exploring RAILS files and folders
- app/: Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.
- bin/: Contains the rails script that starts your app and can contain other scripts you use to setup, update, deploy or run your application.
- config/: Configure your application's routes, database, and more. This is covered in more detail in Configuring Rails Applications.
- config.ru: Rack configuration for Rack based servers used to start the application.
- db/: Contains your current database schema, as well as the database migrations.
- Gemfile :
- Gemfile.lock : These files allow you to specify what gem dependencies are needed for your Rails application. These files are used by the Bundler gem. For more information about Bundler, see the Bundler website.
- lib/: Extended modules for your application.
- log/: Application log files.
- public/: The only folder seen by the world as-is. Contains static files and compiled assets.
- Rakefile: This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.
- README.md: This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.
- test/: Unit tests, fixtures, and other test apparatus. These are covered in Testing Rails Applications.
- tmp/: Temporary files (like cache and pid files).
- vendor/: A place for all third-party code. In a typical Rails application this includes vendored gems.
2.7. Creating a simple RAILS application
a) create a resource 'articles' and check routes
$ pwd/root/rails-home/myrailsapppostgres
$ vim config/routes.rb
Rails.application.routes.draw do
get 'welcome/index'
resources :articles
root 'welcome#index'
end
b) check all RESTfull actions
$ rails routesPrefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
root GET / welcome#index
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
c) Create a model for article
- Generate RAILS model for Article
$ rails generate model Article title:string text:text
Running via Spring preloader in process 3657
invoke active_record
create db/migrate/20170317185317_create_articles.rb
create app/models/article.rb
invoke test_unit
create test/models/article_test.rb
create test/fixtures/articles.yml
- Checking migrate scripts automatically generated by RAILS
$ cat db/migrate/*_create_articles.rb
class CreateArticles < ActiveRecord::Migration[5.0]
def change
create_table :articles do |t|
t.string :title
t.text :text
t.timestamps
end
end
end
$ cat app/models/article.rb
class Article < ApplicationRecord
validates :title, presence: true, length: { minimum: 3 }
end
- Run migrate scripts on environment (DEVELOPMENT)
$ rails db:migrate
== 20170317185317 CreateArticles: migrating ===================================
-- create_table(:articles)
-> 0.0092s
== 20170317185317 CreateArticles: migrated (0.0093s) ==========================
- Checking on PostgreSQL databases databases created by scripts
$ psql -h 127.0.0.1 -d myrailsapppostgres_development -U root -W
myrailsapppostgres_development=> \l
List of databases
Name | Owner
-------------------------------+----------
myrailsapppostgres_development | root ...
myrailsapppostgres_test | root ...
: :
- Checking on PostgreSQL databases tables created by scripts
myrailsapppostgres_development=> \d
List of relations
Schema | Name | Type | Owner
--------+----------------------+----------+-------
public | ar_internal_metadata | table | root
public | articles | table | root
public | articles_id_seq | sequence | root
public | schema_migrations | table | root
(4 rows)
- Checking on PostgreSQL databases table description created by scripts
myrailsapppostgres_development=> \d articles
Table "public.articles"
Column | Type | Modifiers
------------+-----------------------------+-------------------------------------------------------
id | integer | not null default nextval('articles_id_seq'::regclass)
title | character varying |
text | text |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
Indexes:
"articles_pkey" PRIMARY KEY, btree (id)
d) Create controller for article and implement actions from CRUD capabilities
$ rails generate controller Articles$ vim app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
end
$ vim app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def new # new action
@article = Article.new
end
def create # create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def show # show
@article = Article.find(params[:id])
end
def index # list
@articles = Article.all
end
def edit # edit
@article = Article.find(params[:id])
end
def update # 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
def article_params
params.require(:article).permit(:title, :text)
end
end
e) Create views for article and implement pages from CRUD capabilities: welcome index, new-create, show, list, edit and destroy
- welcome#index: view for application Welcome
$ vim app/views/welcome/index.html.erb
<h1>Welcome#index</h1>
<p>Find me in app/views/welcome/index.html.erb</p>
<%= link_to 'Articles', controller: 'articles' %>
- new: view for new record
$ vim app/views/articles/new.html.erb
<h1>New Article</h1>
<%= form_for :article, url: articles_path do |f| %>
<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 %>
- show: view for show record
$ vim app/views/articles/show.html.erb
<h1>Show Article</h1>
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<%= link_to 'Back', articles_path %>
- list: view for listing all records
$ vim app/views/articles/index.html.erb
<h1>Listing articles</h1>
<table>
<tr>
<th>Title</th>
<th>Text</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>
- edit: view for edit record
$ vim app/views/articles/edit.html.erb
<h1>Editing article</h1>
<%= form_for :article, url: article_path(@article), method: :patch 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 %>
<%= link_to 'Back', articles_path %>
f) Testing simple application CRUD
- http://localhost:3000/ - should return your welcome index
- http://localhost:3000/articles - should return a list of articles on database and you can show, edit or destroy
- http://localhost:3000/articles/new - should return a empty article form
2.8. Adding some validation to simple RAILS application
- Required fields and minimum limit of fields
$ vim app/models/article.rb
class Article < ApplicationRecord
validates :title, presence: true, length: { minimum: 3 }
end
- Capture new errors exceptions and show on top of page
$ vim app/views/articles/new.html.erb
:
<%= form_for :article, url: articles_path 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 %>
:
2.9. Using form to clean up duplications on view
a. Backup 'new' and 'edit' form
$ cp app/views/articles/new.html.erb app/views/articles/new.html.erb.without_form$ cp app/views/articles/edit.html.erb app/views/articles/edit.html.erb.without_form
b. Create template '_form' to be included by 'new' and 'edit'
$ vim app/views/articles/_form.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 %>
c. Change 'new' to include '_form'
$ vim app/views/articles/new.html.erb<h1>New Article</h1>
<h1>New article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
d. Change 'edit' to include '_form'
$ vim app/views/articles/edit.html.erb<h1>Editing article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
2.10. Adding second model detail of first master model
a. Create model comment detail of master article: one article has many comments
$ rails generate model Comment commenter:string body:text article:referencesRunning via Spring preloader in process 8667
invoke active_record
create db/migrate/20170318010912_create_comments.rb
create app/models/comment.rb
invoke test_unit
create test/models/comment_test.rb
create test/fixtures/comments.yml
b. Checking migrate scripts automatically generated by RAILS
$ cat db/migrate/*_create_comments.rb$ cat app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :article
end
$ cat test/models/comment_test.rb
:
$ cat test/fixtures/comments.yml
:
c. Run migrate scripts on environment (DEVELOPMENT)
$ rails db:migrate== 20170318010912 CreateComments: migrating ===================================
-- create_table(:comments)
-> 0.1321s
== 20170318010912 CreateComments: migrated (0.1323s) ==========================
d. Associating models
$ vim app/models/article.rbclass Article < ApplicationRecord
has_many :comments
validates :title, presence: true, length: { minimum: 5 }
end
e. Adding routing for new model comments
$ vim config/routes.rbRails.application.routes.draw do
get 'welcome/index'
resources :articles do
resources :comments
end
root 'welcome#index'
end
f. Generating a controller for detail new model Comment
$ rails generate controller Comments$ cat app/controllers/comments_controller.rb # will be changed soon
class CommentsController < ApplicationController
end
$ ls -lad app/views/comments/
$ ls -la test/controllers/comments_controller_test.rb
$ cat app/helpers/comments_helper.rb
module CommentsHelper
end
$ cat app/assets/javascripts/comments.coffee
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$ cat app/assets/stylesheets/comments.scss
// Place all the styles related to the Comments controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
g. Edit article view 'show' to let make a new details records of comments
$ vim app/views/articles/show.html.erb<h1>Show Article</h1>
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<h2>Comments</h2>
<% @article.comments.each do |comment| %>
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<% end %>
<h2>Add a comment:</h2>
<%= 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 %>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
h. Edit comments controller 'show' to implement 'create' and 'destroy'
$ vim app/controllers/comments_controller.rbclass CommentsController < ApplicationController
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
$ vim app/views/articles/show.html.erb
<p>
<strong>Title:</strong>
<%= @article.title %>
</p>
<p>
<strong>Text:</strong>
<%= @article.text %>
</p>
<h2>Comments</h2>
<% @article.comments.each do |comment| %>
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<% end %>
<h2>Add a comment:</h2>
<%= 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 %>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
i. Partial Comments to clean up 'show' with a template
$ cp app/views/articles/show.html.erb app/views/articles/show.html.erb.without_form$ vim app/views/comments/_comment.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>
j. Partial Form _form coments._form
$ vim app/views/comments/_form.html.erb<%= 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 %>
k. Partial Form _form article.show
$ vim app/views/articles/show.html.erb<h1>Show Article</h1>
<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 %>
l. Adding method 'create' and 'destroy' to controller Comments
$ vim app/controllers/comments_controller.rbclass CommentsController < ApplicationController
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
m. Deleting associated Objects
$ vim app/models/article.rb
class Article < ApplicationRecord
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { minimum: 3 }
end
3. References
- https://hostpresto.com/community/tutorials/how-to-install-ruby-on-rails-on-centos-7/
- http://guides.rubyonrails.org/getting_started.html
Nenhum comentário:
Postar um comentário