【4回目(前編)】Railsに挫折中の人が、Ruby/Sinatraから再入門してみた(全7回)

5/11より毎週土曜日、株式会社X-HACK主催の勉強会、
【全7回】Ruby / Vue.js「ゼロから」ウェブサービスを作る【初心者向け | 個別指導あり】
に参加しています。
学んだことをこちらでアウトプットしていきます!

今回は4回目!
1つでは到底まとめきれない充実した内容だったので、
前編:掲示板を作ってみよう!〜関数・モジュール化まで! ←(今回)
後編:スクレイピングデータをDBに保存〜proc、yieldについて!
に分けて説明します!

文中のコードはそのままコピペで動くはず?なので、
最初は処理が分からなくても、まず
作ってみましょう!

動かない、間違っている所などあれば教えていただけると嬉しいです!

Sinatraで簡易掲示板を作ってみよう!

⭐︎準備

まずは前回の復習!ここは、さらっとできるようになりましょう!
詳しくは、前回の記事を参照してください!

・プロジェクト作成

【ターミナル】

$ mkdir day4-sinatra
$ cd day4-sinatra
$ bundle init

// ファイルの作成
$ touch app.rb
$ mkdir views
$ touch views/index.erb

・Gemfile編集

【day4-sinatra/Gemfile】

source "https://rubygems.org"
gem 'sinatra'
gem 'sinatra-contrib'
gem 'pg'

・bundle install

$ bundle install
   または
$ bundle install --path vendor/bundle  //(作者はこっち)

下記のファイル構成になっていたら、準備完成!

⭐︎テーブルを作成しよう!

ここからが今回の本題です!
まず、掲示板に投稿した内容を保存するためのテーブルを作成します。
ターミナル等から作ることももちろん可能ですが、面倒なので今回は rubyファイルからテーブル作成します。

・create_board_contets.rbの作成

【ターミナル】

$ touch day4-sinatra/create_board_contets.rb

・create_board_contets.rbを編集
今回は、簡易掲示板なので、「id」「name」「comment」「commented_at」の4つのカラムを作成します。
接続情報は前回Herokuに作成したPostgresの情報を入力すればOK!

【day4-sinatra/create_board_contets.rb】

require 'pg' #postgresのgem読み込み

# DB情報を確認して埋める
conn = PG::connect(
 host: 'ホスト名',
 user: 'ユーザー名',
 password: 'パスワード',
 dbname: 'データベース名',
 port: '5432'
)

# テーブルを作成するSQL文を実行
conn.exec("
 drop table board_contents;
 CREATE TABLE board_contents (
   id serial,
   name text,
   comment text,
   commented_at timestamp,
   PRIMARY KEY (id)
 );"
)

・create_board_contets.rbを実行

【ターミナル】

$ ruby day4-sinatra/create_board_contets.rb

PGCommanderなどでテーブルが作成できているか確認できたら、掲示板用テーブルの作成が完了です!

⭐︎DB情報を悪用されないために

ここで一休み!
先程、Herokuに作成したPostgresの情報を入力しよう!と書きましたが、
実はこのままHeroku、Githubに公開してしまうと悪用されてしまう恐れが!
防ぐための設定をご紹介!

①"dotenv"というgemを使って、環境変数を設定

○"dotenv"とは?
→.envファイルに書いた設定を環境変数として簡単に読み込めるgem。

・Gemfileに"dotenv"を追記→bundle install

【day4-sinatra/Gemfile】

gem 'dotenv'

----------------------

【ターミナル】
$ bundle install

・「.env」ファイルを作成し、環境変数を設定

【ターミナル】

$ touch .env

-----------------

【day4-sinatra/.env】

// DB情報を記述
DATABASE_HOST='ホスト名'
DATABASE_USER='ユーザー名'
DATABASE_PASSWORD='パスワード'
DATABASE_NAME='データベース名'
DATABASE_PORT='5432'

・環境変数をapp.rbで読み込む

【day4-sinatra/app.rb】

require 'dotenv/load' # "dotenv"gemを読み込む

get '/' do
 # 設定した環境変数を使う
 connect = PG.connect(
   host: ENV['DATABASE_HOST'],
   user: ENV['DATABASE_USER'],
   password: ENV['DATABASE_PASSWORD'],
   dbname: ENV['DATABASE_NAME'],
   port: ENV['DATABASE_PORT']
 )

 (省略)...
end

②「.gitignore」ファイルを作成し、gitで管理しない
→「.gitignore」に記述したファイルをgitは無視するので、Githubに公開される事もなくなる!

【ターミナル】

$ touch .gitignore

---------------------

【day4-sinatra/.gitignore】

.env
/vendor/bundle

これでDB接続情報が漏れる心配が無くなりました!\(^o^)/

⭐︎掲示板の画面を作ろう!

・index.erbの編集

【day4-sinatra/views/index.erb】

<!DOCTYPE html>
<html lang="en" dir="ltr">
 <head>
   <meta charset="utf-8">
   <title>XHACK勉強会</title>
 </head>
 <body>
   <!-- DBから取得したデータを表示 -->
   <% @data.each do |data| %>
     <ul>
       <li>名前:<%= data["name"] %></li>
       <li>コメント:<%= data["comment"] %></li>
       <li>日時:<%= data["commented_at"] %></li>
     </ul>
   <% end %>
   <!-- 掲示板フォーム -->
   <form action="/comments" method="post">
     名前:<input type="text" name="name">
     <input class="form-control" type="text" placeholder="Default input" name="comment">
     <input class="btn btn-light" type="submit" value="送信する">
   </form>
 </body>
</html>

こんな画面が完成!

⭐︎データを取得・登録しよう

【day4-sinatra/app.rb】

require 'sinatra'
require 'sinatra/reloader'
require 'pg'
require 'dotenv/load'

# DBからデータを取得する処理
get '/' do
 # 1.Postgresと接続
 conn = PG::connect(
   host: ENV['DATABASE_HOST'],
   user: ENV['DATABASE_USER'],
   password: ENV['DATABASE_PASSWORD'],
   dbname: ENV['DATABASE_NAME'],
   port: ENV['DATABASE_PORT']
 )

 # 2.全データを取得するための、sql文を用意
 @data = conn.exec("select * from board_contents;")

 # 3.接続を終了する
 conn.finish

 # 4.index.erbに遷移する
 erb :index
end

# DBに登録する処理
post '/comments' do
  # 1.Postgresと接続
  conn = PG.connect(
   host: ENV['DATABASE_HOST'],
   user: ENV['DATABASE_USER'],
   password: ENV['DATABASE_PASSWORD'],
   dbname: ENV['DATABASE_NAME'],
   port: ENV['DATABASE_PORT']
 )

 # 2.フォームから入力された情報(パラメータ)を受け取る
 name = params['name']
 comment = params['comment']

 # 3.登録するためのsql文を用意
 sql = "INSERT INTO board_contents (name, comment, commented_at) VALUES ('#{name}', '#{comment}', current_timestamp);"
 
 # 4.sql文を実行
 @data = conn.exec(sql)
 
 # 5.接続を終了する
 conn.finish

 # 6.もう一度、データ一を取得〜表示する処理を行う
 redirect '/'
end

簡易掲示板、完成!!
フォームから入力すると、フォームの上に投稿内容が表示されるようになります\(^o^)/

⭐︎関数・モジュール化

最後に、関数・モジュール化について!
実は、先程の処理、重複した処理を書かれていたのに、気づきませんでした?!
DBとの接続〜実行〜終了までの部分!

【day4-sinatra/app.rb】

# ①Postgresと接続
 conn = PG::connect(
   host: ENV['DATABASE_HOST'],
   user: ENV['DATABASE_USER'],
   password: ENV['DATABASE_PASSWORD'],
   dbname: ENV['DATABASE_NAME'],
   port: ENV['DATABASE_PORT']
 )

 # ②SQL文を実行
 @data = conn.exec(sql)

 # ③接続を終了する
 conn.finish

嫌だ!同じこと書きたくない!!絶対に嫌だ!!!

そんなわがままなお悩みを解決するのが、、、

「関数」、「モジュール化」です!!

○関数化

・重複した処理を「関数」で一つにまとめる

# 文字列で受け取ったsqlを実行する関数
def postgres(sql)
 # ①Postgresと接続
 conn = PG::connect(
   host: ENV['DATABASE_HOST'],
   user: ENV['DATABASE_USER'],
   password: ENV['DATABASE_PASSWORD'],
   dbname: ENV['DATABASE_NAME'],
   port: ENV['DATABASE_PORT']
 )
 # ②SQL文を実行
 data = conn.exec(sql)
 # ③接続を終了する
 conn.finish
 data
end

post '/' do
  # 関数を呼び出す
  @data = postgres("select * from board_contents;")
  erb :index
end

post '/comments' do
  
  name = params["name"]
  comment = params["comment"]
  sql = "INSERT INTO board_contents (name, comment) VALUES ('#{name}', '#{comment}');"
  # 関数を呼び出す
 @data = postgres(sql)
  redirect '/'
end

こうすると引数にSQL文を渡せば、DB処理はこの関数がやってくれます!

○モジュール化
更に、モジュール化すると他ファイルからも関数を呼び出すことができます!

・「mydatabase.rb」ファイルを作成

【ターミナル】

$ touch day4-sinatra/mydatabase.rb

・「mydatabase.rb」ファイルを編集

【day4-sinatra/mydatabase.rb】

require 'pg'
require 'dotenv/load'

module Mydatabase
 def self.exec(sql)
   @conn = PG.connect(
       host: ENV['DATABASE_HOST'],
       user: ENV['DATABASE_USER'],
       password: ENV['DATABASE_PASSWORD'],
       dbname: ENV['DATABASE_NAME'],
       port: ENV['DATABASE_PORT']
   )
   data = @conn.exec(sql)
   @conn.finish
   data
 end
end

app.rbで、モジュールを使ってみましょう!
モジュールにすると、require './mydatabase' をすることで違うファイルからも関数を呼び出せる!

require 'sinatra'
require 'sinatra/reloader'
require 'pg'
require 'dotenv/load'
require './mydatabase' # moduleの読み込み

get '/' do
 # moduleを使ったDBアクセス
 @data = Mydatabase.exec("select * from board_contents;")
 erb :index
end

post '/comments' do
 name = params["name"]
 comment = params["comment"]
 sql =  "INSERT INTO board_contents (name, comment, commented_at) VALUES ('#{name}', '#{comment}', current_timestamp);"
 # moduleを使ったDBアクセス
 @data = Mydatabase.exec(sql)
 redirect '/'
end

完成!
app.rbのコード量が劇的に減りました!

これで、DB操作はこのモジュールに任せればOK!
SQL文だけ変えれば、delete、update、insert、selectなど全てに対応できるように!
DBは自由自在に扱えます\(^o^)/
めっちゃ便利〜〜〜!!!感動です!!!!(涙)

ぜひ、皆さんも重複した処理は、関数、モジュール化できないか考えると、コードがスッキリ!かつ楽に!なると思います!

前編は以上です!!

今回書ききれなかったprocについては後編に回します!
procとyieldについて学べばコーディングの幅が格段に上がる!はずです!
ぜひ後編も見てください〜!

この記事が気に入ったらサポートをしてみませんか?