ローイングファンのプログラミング日記

ボート競技やプログラミングについて書きます

仮想環境でSinatraアプリを起動する手順

目次


今回の環境

ホストOS: macOS 10.14.1
VirtualBox 5.2.20
Vagrant 2.1.2
Cyberduck 6.7.0
ゲストOS: Ubuntu 18.04
PostgreSQL 10.3
Ruby 2.5.1p57
Sinatra 2.0.3

ディレクトリ・ファイル
MyUbuntuディレクトリに仮想環境を作成

仮想環境内にSinatraAppディレクトリを作成
Sinatraアプリのファイル名はmain.rb

データベースはPostgreSQLを使用

Sinatraアプリを起動する手順

ターミナル/PowerShellで仮想環境ディレクトリに移動する

cd MyUbuntu


Vagrantを起動する

vagrant up


仮想環境にログインする(ssh接続する)

vagrant ssh


(PowerShellの場合はそのままではssh接続できないのでPuttyを起動して以後Puttyで操作)

Cyberduckを起動する

ファイルやディレクトリの作成、削除、読み込みはCyberDuckをつかう

Sinatraアプリが配置されているディレクトリに移動する

cd SinatraApp


PostgreSQLサーバを起動する

sudo systemctl start postgresql


Sinatraアプリ(サーバ)を起動する

(set :environment, :productionSinatraコード内に記入している場合)

bundle exec ruby main.rb

(記入していない場合は-o [ipアドレス]オプションをつけて起動する)

Sinatraアプリをブラウザで表示する

ブラウザのURL入力欄に
http://[ipアドレス]:[ポート番号]と入力する

http://192.168.33.10:4567

(ipアドレスはVagrantfileの設定どおりに)

Sinatraアプリを終了する手順

Sinatraアプリ(サーバ)を停止する

controlキーとCキーを同時に押す

PostgreSQLサーバを終了する

sudo systemctl stop postgresql


Cyberduckを終了する

Cyberduckアプリを終了する

仮想環境からログアウトする

exit

(Puttyの場合はPuttyを終了する)

Vagrantを終了する

vagrant halt  



以上が仮想環境の起動・接続〜Sinatraアプリ起動、アプリ終了〜仮想環境の切断・終了までの手順

PostgreSQLに複数の外部ファイルを読み込ます方法

目次


外部ファイルを使ってレコードを一気に挿入

PostgreSQLをバージョンアップする方法がよくわかっていない。
データを移す方法がよくわからない。なので新バージョンをインストールするたびにレコードを挿入し直している。
バックアップ用のデータはinsert文をそのままSQLファイルにして保存してある。
外部ファイルを一つ一つ読み込ますのは面倒なので複数のファイルを一度に読み込ませている。

複数の外部ファイル

以下はresultデータベースのresultsテーブルに3年分のレース(レガッタ)結果を挿入する例。
次のような3つのファイルがあるとする。

2016result.sql

insert into results (year, rank, crew, time) values
(2016,1,'Crew1','08:08.06'),
(2016,2,'Crew2','08:11.24'),
(2016,3,'Crew3','08:14.41');


2017result.sql

insert into results (year, rank, crew, time) values
(2017,1,'Crew1','08:09.06'),
(2017,2,'Crew2','08:12.24'),
(2017,3,'Crew3','08:15.41');


2018result.sql

insert into results (year, rank, crew, time) values
(2018,1,'Crew1','08:10.06'),
(2018,2,'Crew2','08:13.24'),
(2018,3,'Crew3','08:16.41');


上記3つのファイルを一度に読み込ますためのファイルをつくる。

results2016_2018.sql

\i 2016result.sql
\i 2017result.sql
\i 2018result.sql


PostgreSQLに複数の外部ファイルを読み込ます手順

  • さきほどつくった4つのファイルを同じディレクトリに配置する
  • ターミナル/PowerShellでファイルを配置したディレクトリに移動する
  • PostgreSQLサーバを起動してresultデータベースに接続する
  • \iコマンドでresults2016_2018.sqlファイルを読み込ます


以下はmacOS10での例。データベースへの接続方法は各環境ごとのものとする。


サーバを起動する

$ pg_ctl -D /usr/local/var/postgres -l logfile start

-l logfileはログを記録したい場合にお好みで。


resultデータベースに接続する

$ psql result


外部ファイルを読み込ます

result=# \i results2016_2018.sql


これで9件のレコードを一度に挿入できる。

今回の環境

macOS10.14
Ruby 2.5.1p57
PostgreSQL 10.3

Sinatraでよく使うツール その3

今回はスクリプトエスケープするメソッドについて。

目次


escape_htmlメソッド

スクリプトエスケープするにはRack::Utilsのescape_htmlを使う。

メソッド名を変更する

escape_htmlメソッドはhと名称を変えて使うことが多いらしい。
変更するにはalias_methodメソッドを使ったりdefで再定義する方法がある。
Sinatraではhelpersの中で定義するとどこでも呼び出せるようになる。

alias_methodを使って変更する

require 'sinatra'

helpers do
    include Rack::Utils
    alias_method :h, :escape_html
end


defで再定義

require 'sinatra'

helpers do
    def h(text)
      Rack::Utils.escape_html(text)
    end
end


使い方

実際にSinatraのコードを書いてみる。
今回の環境はVirtualBox Vagrant Ubuntu
Sinatraはbundlerの--pathオプションでインストール。

main.rb

require 'sinatra'
#-o [ipアドレス]オプションを不要にする
set :environment, :production

#escape_htmlをhに変更する
helpers do
    include Rack::Utils
    alias_method :h, :escape_html
end
#もしくは次のコードでも同じ
=begin
helpers do
   def h(text)
       Rack::Utils.escape_html(text)
   end
end
=end

#indexページを作成
get '/' do
    erb :index
end

#フォーム入力値を受け取って表示する
post '/escape_test' do
    @str = params[:str]
    #エスケープして表示
    "#{h @str}"
end


viewsディレクトリの中にindex.erbを配置する。
このページで入力を受け付ける。
views/index.erb

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
</head>
<body>
    <form action="escape_test" method="post">
        <input type="text" name="str">
        <button type="submit">submit</button>
    </form>
</body>
</html>


実行する

実行してみる。

main.rbの起動

bundle exec ruby main.rb


set :environment, :productionを使わない場合は-oが必要。

bundle exec ruby main.rb -o 192.168.33.**

192.168.33.**にはVagrantfileで設定したipアドレスが入る。


ブラウザで確認する
ブラウザにURLを入力して表示する。

http://192.168.33.**:4567


macOSWindowsの場合は

http://localhost:4567



フォーム入力
次のようにstyleを入力してsubmitしてみる。

<span style="color: red;">ボート競技は最高!</span>


エスケープされると<span>タグが文字列となって表示される。

<span style="color: red;">ボート競技は最高!</span>

こうなればエスケープ成功。

hがない場合

"#{h @str}""#{@str}"としてSinatraを再起動する。
先ほどと同じ文字列を入力してsubmitする。

ボート競技は最高!


hがないとstyleが有効になり赤い文字で表示されてしまう。
悪意のあるスクリプトエスケープする必要がある。

ドキュメント

Rubyリファレンスマニュアル
class Module > #インスタンスメソッド
alias_method
https://docs.ruby-lang.org/ja/latest/class/Module.html

Sinatra Top > DOCS
FREQUENTLY ASKED QUESTIONS
How do I escape HTML?
http://sinatrarb.com/faq.html

Sinatraでよく使うツール その2

Sinatraのデフォルト設定では、publicという名のディレクトリ内にCSSなどの静的ファイルを配置するきまりになっている。
今回はこのディレクトリ名を変更する方法について試す。

目次


静的ファイル用のディレクトリ名を変更するコード

#publicをmystaticに変更する
set :public_folder, File.dirname(__FILE__) + '/mystatic'


ディレクトリ名を変更するメリット

変更しておくとCSSファイルなどが外部からのぞかれにくくなる。

Sinatra Top > README > #Static Files
http://sinatrarb.com/intro.html

Note that the public directory name is not included in the URL. A file ./public/css/style.css is made available as http://example.com/css/style.css.


注意書きにあるようにpublicのままだとCSSファイルが表示されてしまうことがある。
名称を変更することでこれを防ぐ。

つかい方

今回の環境はVirtualBox Vagrant Ubuntu
Sinatraはbundlerの--pathオプションでインストール。

コードをrequireのつぎあたりに記入する。
main.rb

require 'sinatra'
#-o [ipアドレス]オプションを不要にする
set :environment, :production
#publicをmystaticに変更する
set :public_folder, File.dirname(__FILE__) + '/mystatic'

get '/' do
    erb :index
end


views/index.erb

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <!-- リンクのパスはmystatic(public)の下層から記入 -->
    <link rel="stylesheet" href="/css/style.css" type="text/css" media="all">
</head>
<body>
    <h1 class="red">レガッタはおもしろい</h1>
</body>
</html>


mystatic/css/style.css

.red {
    color: red;
}


ディレクトリ/ファイル構造

変更前

- main.rb
- views
    - index.erb
- public
    - css
        - style.css


変更後

- main.rb
- views
    - index.erb
- mystatic
    - css
        - style.css


実行

Sinatraファイルの起動

bundle exec ruby main.rb


set :environment, :productionを使わない場合は

bundle exec ruby main.rb -o 192.168.33.**

192.168.33.** にはVagrantfileで設定したipアドレスが入る。


ブラウザにURLを入力して表示

http://192.168.33.**:4567


macOSWindowsの場合は

http://localhost:4567



レガッタはおもしろい、と赤色の文字で表示されていれば成功。

Sinatraでよく使うツール

今回はローカル開発環境で使うと便利なコードについて。

目次


起動時に -o [ipアドレス]オプション が不要になるコード

set :environment, :production


つかい方

コードをrequireのつぎあたりに記入する。
今回の環境はVirtualBox Vagrant Ubuntu
Sinatraはbundlerの--pathオプションでインストール。

main.rb

require 'sinatra'

set :environment, :production

get '/' do
    'Hello world'
end


起動方法

main.rbを起動する。

bundle exec ruby main.rb


返答。

INFO  WEBrick::HTTPServer#start done.


起動成功。


set :environment, :productionがない場合。

bundle exec ruby main.rb -o 192.168.33.**

のように-o [ipアドレス]オプションが必要となる。
192.168.33.**にはVagrantfileで設定したアドレスを入力する。

ブラウザーに表示

サーバーが起動したらブラウザに表示する。
下記のようにURLを入力すれば Hello world が表示される。

http://192.168.33.**:4567


Sinatraドキュメント

Sinatra Configuring Settings
Sinatra Top > DOCS > Configuring Settings
#Built-in Settings
:environment
http://sinatrarb.com/configuration.html

Heroku PostgresにSQLファイルを読み込ます

Heroku PostgresにはCSVファイルを挿入できないようなのでCSVファイルからinsert文のSQLファイルをつくる。
つくったSQLファイルをHeroku Postgresに読み込ませればレコードを挿入できる。

目次


前提条件

Heroku Postgresを操作するにはローカルにもPostgreSQLがインストールされている必要がある。
Heroku上でデータベースとテーブルの設定を済ましておく。

CSVファイル

今回のサンプル
sample.csv

2018,全日本大学選手権,男子エイト,1,Aクルー,05:55.91
2018,全日本大学選手権,男子エイト,2,Bクルー,06:00.70
2018,全日本大学選手権,男子エイト,3,Cクルー,06:01.04
2018,全日本大学選手権,男子エイト,4,Dクルー,06:03.31


Heroku Postgresのテーブル

テーブル名: samples

Column Type
id integer
year smallint
tournament_name character varying(20)
event_name character varying(20)
rank smallint
crew character varying(20)
goaltime character varying(10)

# idはserial primary key

CSVファイルをSQLファイルに変換するコード

rewrite.rb

require 'csv'

class Sqlwriter
    def initialize(csv_file, sql_file)
        @csv_file = csv_file
        @sql_file = sql_file
    end

    def rewrite
        txt = "insert into samples (year,tournament_name,event_name,rank,crew,goaltime) values \n"

        CSV.foreach(@csv_file) do |csv_file|
            txt << "(#{csv_file[0]},'#{csv_file[1]}','#{csv_file[2]}',#{csv_file[3]},'#{csv_file[4]}','#{csv_file[5]}'),\n"
        end
        txt.gsub!(/,\Z/,";")
        open(@sql_file,"w") do |sql_file|
            sql_file.write txt
        end
    end
end

Sqlwriter.new("sample.csv","sample.sql").rewrite


実行結果

rewrite.rbとsample.csvを同じディレクトリに置いて実行する。
実行結果は次のとおり。

sample.sql

insert into samples (year,tournament_name,event_name,rank,crew,goaltime) values 
(2018,'全日本大学選手権','男子エイト',1,'Aクルー','05:55.91'),
(2018,'全日本大学選手権','男子エイト',2,'Bクルー','06:00.70'),
(2018,'全日本大学選手権','男子エイト',3,'Cクルー','06:01.04'),
(2018,'全日本大学選手権','男子エイト',4,'Dクルー','06:03.31');


Heroku Postgres

Heroku PostgresのWebページ

Heroku Dev Center
Heroku Postgres

https://devcenter.heroku.com/articles/heroku-postgresql

Heroku PostgresにSQL文を読み込ます

Herokuにログインする前にターミナルのcdコマンドでsample.sqlファイルがある場所に移動しておく。
移動したらHerokuにログインする。

heroku login
#メールアドレスとパスワードが必要


Heroku Postgresにログインする。

heroku pg:psql --app [appname]
#[appname]は各自のアプリ名


SQLファイルを読み込ませてデータベースにレコードを挿入する。

\i sample.sql


SQLファイルの内容が実行されてレコードが挿入される。

Heroku Postgresからログアウトする。

\q


Herokuからログアウトする。

heroku logout


今回の動作確認環境

macOS 10.13.6
Ruby 2.5.1p57
PostgresSQL 10.3

条件分岐を1行にまとめる

目次


if文のみ

後置ifをつかう。
式 if 条件

event_name = 'エイト'

# if 条件 式 end
if event_name == 'エイト'
    puts "スイープ種目です。"
end

# 後置ifをつかう。
puts "スイープ種目です。" if event_name == 'エイト'


if文 else節が1つのみの場合

else節が1つしかなく、式が単純な場合は 条件 ? 式1 : 式2がつかえる。

event_name = 'エイト'

# if else end
if event_name == 'クォドルプル'
    puts "スカル種目です。"
else
    puts "スイープ種目です。"
end

# 条件 ? 式1 : 式2
# 条件が偽の場合は : 以降の式が実行される。
event_name == 'クォドルプル' ? puts("スカル種目です。") : puts("スイープ種目です。")


ちなみに上の場合puts "スカル種目です。"と書くとエラーになる。

エラーの例

event_name = 'エイト'

event_name == 'クォドルプル' ? puts "スカル種目です。" : puts "スイープ種目です。"
# syntax errorになる


putsの引数を()で囲むか、puts式全体を()で囲む必要がある。

event_name = 'エイト'

event_name == 'クォドルプル' ? (puts "スカル種目です。") : (puts "スイープ種目です。")
# スイープ種目です。 と表示される。


case文のwhen節を1行にまとめる

when節にthenを明記すると1行にまとめることができる。

thenなし、改行あり

event_name = 'エイト'

case event_name
when 'クォドルプル'
    puts "スカル種目です。"
when 'エイト'
    puts "スイープ種目です。"
end


thenあり、改行なし

event_name = 'エイト'

case event_name
when 'クォドルプル' then puts "スカル種目です。"
when 'エイト' then puts "スイープ種目です。"
end

# thenなし、改行なしはエラーになる。


今回の動作確認環境

Ruby 2.5.1p57