Sinatra+ActiveRecord+SQLite3で,軽量なWeb-DB連携例

今回はSinatra(シナトラ)についてです.
シナトラと言っても,フランク・シナトラではありません.(歳がばれますね)

普段, 何気にRailsを使用しています.
自分で書くコード量も少なく,ほとんどフレームワークがやってくれますが,ちょっとしたWebサイトを作成するだけでも,Gemやらファイルやらで,かなりのビッグサイズになってしまいます.

そんな,Railsのような巨大なフレームワークを使う程でもない,データベースの保守などのちょっとしたサイトを構築したい,でも,PHPではなく,あくまでもRubyで,しかもActiveRecordのようなデータベースマッパーや,ERBのようなテンプレートを利用したい,というような場合に最適なWebフレームワークが...

Sinatraです.

今回は,このSinatraのフレームワークを使って,SQLiteデータベースのテーブルのレコードの表示,登録,削除を行うWebアプリケーションを作成してみます.

参考にさせて頂いたのは,このサイトです.
Sinatra: README (Japanese)

とりあえず,SQLiteで簡単なデータベース(テーブル)を作成してみます.

まずは,作業用のディレクトリを作成して...

$ mkdir meibo
$ cd meibo/

SQLiteでmeiboデータベースを作成します.

$ sqlite3 meibo.db
SQLite version 3.7.13 2012-06-11 02:05:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>

次のような簡単なテーブルを作成します.
Rails?(ActiveRecord?)の流儀で,テーブル名は複数名表記(クラス名は単数表記)で付けておきます.

students table
students テーブル

まずは,テーブルのスキーマ.

sqlite> create table students (
   ...> id char(10) primary key,
   ...> name varchar(50),
   ...> email varchar(100)
   ...> );

続いて,レコードの追加.

sqlite> insert into students values ('1234567890', 'Kagoshima Taro', 'taro@kago.jp');
sqlite> insert into students values ('1234567891', 'Satsuma Hanako', 'hana@kago.jp');

最後に確認して,SQLiteを終了します.

sqlite> select * from students;
1234567890|Kagoshima Taro|taro@kago.jp
1234567891|Satsuma Hanako|hana@kago.jp
sqlite> .quit

さて次は,Bundlerを用いて必要なGemの準備を行います.

$ bundle init

カレントディレクトリに「Gemfile」が作成されますので,それを修正します.

# A sample Gemfile
source "https://rubygems.org"

gem "sqlite3"
gem "activerecord"

続いて,必要なGemを,システムではなく,このアプリケーションだけで利用するために,カレントディレクトリの配下「vendor/bundle」にインストールします.

$ bundle install --path vendor/bundle

irbでrequireできるかチェックしてみます.

$ bundle exec irb
irb(main):001:0> require 'active_record'
=> true

Railsのときと同じように,データベースに関する設定情報を「database.yml」という名前のYAML形式ファイルをカレントディレクトリに作成します.

development:
  adapter: sqlite3
  database: meibo.db

YAMLの読み込みは,次のようなメソッドで確認できます.

$ bundle exec irb
irb(main):001:0> YAML.load_file('database.yml')
=> {"development"=>{"adapter"=>"sqlite3", "database"=>"meibo.db"}}

実際に,ActiveRecordを利用して,テーブルデータを標準出力に表示するプログラム「meibo.rb」を作成します.

# coding:utf-8
require 'active_record'

ActiveRecord::Base.configurations = YAML.load_file('database.yml')
ActiveRecord::Base.establish_connection('development')

class Student < ActiveRecord::Base
end

# idが「1234567890」の学生だけ抽出しオブジェクトに格納します.
student = Student.find('1234567890')
puts student.id
puts student.name

実行結果です.

$ bundle exec ruby meibo.rb
1234567890
Kagoshima Taro

最後,下3行を,次のように書き直せば...

students = Student.all
students.each do |stu|
  puts stu.id + "\t" + stu.name + "\t" + stu.email
end

次のように,全てのレコードが出力されます.

$ bundle exec ruby meibo.rb
1234567890     Kagoshima Taro     taro@kago.jp
1234567891     Satsuma Hanako     hana@kago.jp

さて,お次はようやく「Sinatra」の出番です.

SinatraのGemをインストールするために,「Gemfile」に次のように追記します.

# A sample Gemfile
source "https://rubygems.org"

gem "sqlite3"
gem "activerecord"
gem "sinatra"

そして,実際にカレントディレクトリの「vendor/bundle」にインストール

$ bundle install

Sinatraは,次のようにRubyプログラムを記述して,

require 'sinatra'

get '/' do
    "Hello World!"
end

次のように,コマンドを打てば,Webサーバが立ち上がります.

$ bundle exec ruby hello.rb

WebブラウザでURL「http://localhost:4567/」と,ポート番号「4567」を指定して,localhostにアクセスすれば,結果が表示されます.

Sinatra,Hello Worldの実行結果
Sinatra,Hello Worldの実行結果

では,テーブルの内容がブラウザに表示されるように,「meibo.rb」を書き換えていきます.

# coding:utf-8
require 'active_record'

ActiveRecord::Base.configurations = YAML.load_file('database.yml')
ActiveRecord::Base.establish_connection('development')

class Student < ActiveRecord::Base
end

# 「GET /」でアクセスしてきたときに,studentsテーブルの全レコードデータを,ERBテンプレートファイル「views/index.erb」に渡します.
get '/' do
  @students = Student.all
  erb :index
end

表示用のテンプレートファイル「views/index.erb」を別に用意します.
テンプレートファイルは,デフォルトでは「views」ディレクトリに入れておかないとダメなようです.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Test</title>
</head>
<body>
  <table border>
    <tr>
      <th>学籍番号</th>
      <th>氏名</th>
      <th>E-mail</th>
    </tr>

    <% @students.each do |stu| %>
    <tr>
      <td><%= stu.id %></td>
      <td><%= stu.name %></td>
      <td><%= stu.email %></td>
    </tr>
    <% end %>

</table>
</body>
</html>

Railsのビューテンプレートのように書けます.

これの実行結果が,これです.

meibo.rbの実行結果
meibo.rbの実行結果

では,新規レコードを追加できるように,formタグを利用して,入力用ボックスと「登録」ボタンを追加します.

<!DOCTYPE html>
<html>
   :
  (略)
   :
    <% @students.each do |stu| %>
    <tr>
      <td><%= stu.id %></td>
      <td><%= stu.name %></td>
      <td><%= stu.email %></td>
      </tr>
    <% end %>

    <form method="post" action="new">
    <tr>
      <td><input type="text" name="id"></td>
      <td><input type="text" name="name"></td>
      <td><input type="text" name="email"></td>
      <td><input type="submit" value="登録"></td>
    </tr>
    </form>
  </table>
</body>
</html>
「登録」ボタンの追加
「登録」ボタンの追加

これにより,「登録」ボタンを押したときは,POSTメソッドで,URL「http://localhost/new」(localhostの場合)を呼び出し,「id」,「name」,「email」の値がparamsハッシュに格納されて渡されます.

POST /new」が呼び出されたときの処理を「meibo.rb」に追記します.

# coding:utf-8
require 'active_record'
require 'sinatra'
require 'erb'

ActiveRecord::Base.configurations = YAML.load_file('database.yml')
ActiveRecord::Base.establish_connection('development')

class Student < ActiveRecord::Base
end

get '/' do
  @students = Student.all
  erb :index
end

post '/new' do
  student = Student.new
  student.id = params[:id]
  student.name = params[:name]
  student.email = params[:email]
  student.save
  redirect '/'
end

post ‘/new’ do 〜 end」のブロックを追加します.
Studentオブジェクトをnewで作成し,各パラメータの値を各フィールドに代入し,saveコマンドでレコードとして保存します.その後,一覧表示をさせるために,redirectメソッドで「GET /」を呼び出すようにします.

最後に,既存のレコードを削除できるように,行ごとにformタグを利用して,「削除」ボタンを追加します.

<!DOCTYPE html>
<html>
   :
  (略)
   :
    <% @students.each do |stu| %>
    <tr>
      <td><%= stu.id %></td>
      <td><%= stu.name %></td>
      <td><%= stu.email %></td>
      <form method="post" action="del">
      <td><input type="submit" value="削除"></td>
      <input type="hidden" name="id" value="<%= stu.id %>">
      <input type="hidden" name="_method" value="delete">
      </form>
    </tr>
    <% end %>
 :
(略)
 :
</html>
「削除」ボタンの追加
「削除」ボタンの追加

これにより,「削除」ボタンを押したときは,POSTメソッドで,URL「http://localhost/del」(localhostの場合)を呼び出し,「id」の値がparamsハッシュに格納されて渡されます.

しかし,RESTfulを意識したものであれば,削除は「DELETE」メソッドになりますので,実際は現在のブラウザの仕様上,POSTメソッドですが,hiddenのinputタグで,「name=”_method” value=”delete”」とすれば,DELETEメソッドとしてSinatraが解釈してくれます.

参考「2.7. The PUT and DELETE methods|Sinatra Book

DELETE /del」が呼び出されたときの処理を「meibo.rb」に追記します.

# coding:utf-8
require 'active_record'
require 'sinatra'
require 'erb'

ActiveRecord::Base.configurations = YAML.load_file('database.yml')
ActiveRecord::Base.establish_connection('development')

class Student < ActiveRecord::Base
end

get '/' do
  @students = Student.all
  erb :index
end

post '/new' do
  student = Student.new
  student.id = params[:id]
  student.name = params[:name]
  student.email = params[:email]
  student.save
  redirect '/'
end

delete '/del' do
  student = Student.find(params[:id])
  student.destroy
  redirect '/'
end

delete ‘/del’ do 〜 end」のブロックを追加します.
Studentオブジェクトをパラメータ「id」で指定して呼び出し,destroyメソッドで削除します.その後,一覧表示をさせるために,redirectメソッドで「GET /」を呼び出すようにします.

以上,「meibo.rb」,「index.erb」,「detabase.yml」の3つのファイルだけで,ここまでできました.「database.yml」の内容をそのまま「meibo.rb」にハードコーディングすれば,2つのファイルだけになりますし,「index.erb」の内容を「meibo.rb」に埋め込めば,「meibo.rb」単独でも可能です.

「MVC」モデルならぬ,「MC+V」モデルのような感じで,シンプルで扱いやすいと思います.

$ ls vendor/bundle/ruby/1.9.1/gems/
activemodel-3.2.8/     i18n-0.6.1/            sqlite3-1.3.6/
activerecord-3.2.8/    multi_json-1.3.6/      tilt-1.3.3/
activesupport-3.2.8/   rack-1.4.1/            tzinfo-0.3.33/
arel-3.0.2/            rack-protection-1.2.0/
builder-3.0.4/         sinatra-1.3.3/

BundlerによってインストールされたGemもこれだけですので,サイズも

$ du -hs meibo/
 14M	meibo/

と,こんな感じです.

広告

5 thoughts on “Sinatra+ActiveRecord+SQLite3で,軽量なWeb-DB連携例

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中