momota.txt

hello, hello, hello, how low?

Rails から外れた僕らは Sinatra で I Did It My Way (2)

sinatra

前回の “sinatra で rails から外れた僕らは sinatra で i did it my way” の続き

今回は、mongodb を使って簡単な sinatra web アプリケーションをつくってみる。 また、bootstrap3 で簡単に見た目を綺麗にしてみる。


MongoDB を使うための準備

データの永続化をするために、ここでは mongodb を使う。別に sqlite3 や MySQL でも良かったがなんとなく NoSQLを選定。

まずは、こちらを参考に mongodb をインストールする。

1
2
3
4
5
6
7
8
$ brew update
$ brew install mongodb
$ mongo --version
MongoDB shell version: 2.4.6

# mongod を起動する
$ /usr/local/bin/mongod --fork
all output going to: /usr/local/var/log/mongodb/mongo.log

mongodb を ruby から扱うための gem を bundler でインストールする。

Gemfile に mongobson_ext を追加する。(以下は Gemfile の diff 結果)

1
2
3
4
5
6
7
8
9
10
diff --git a/Gemfile b/Gemfile
index 140fec0..74db599 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,3 +6,6 @@ gem "activerecord", "3.2.13"
 gem "sqlite3", "1.3.7"
 gem "sinatra", "1.4.3"
 gem "sinatra-contrib", "1.4.0"
+gem "mongo"
+gem "bson_ext"

bundler でインストールする。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/...........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using i18n (0.6.1)
Using multi_json (1.8.0)
Using activesupport (3.2.13)
Using builder (3.0.4)
Using activemodel (3.2.13)
Using arel (3.0.2)
Using tzinfo (0.3.37)
Using activerecord (3.2.13)
Using backports (3.3.4)
Installing bson (1.9.2)
Installing bson_ext (1.9.2)
Using eventmachine (1.0.3)
Installing mongo (1.9.2)
Using rack (1.5.2)
Using rack-protection (1.5.0)
Using rack-test (0.6.2)
Using tilt (1.4.1)
Using sinatra (1.4.3)
Using sinatra-contrib (1.4.0)
Using sqlite3 (1.3.7)
Using bundler (1.3.5)
Your bundle is complete!

ルーティング処理を追加する

まず、mongodb を ruby から扱うために require 'mongo' しておく。

before filter で mongodb とのコネクションを張っておく。

helper には、html エスケープ処理の alias を定義しておく。(のちほど views/index.erb で使う)

ブラウザから投稿”/new”と削除”/delete”の HTTP POST リクエストを受け付けるため、各ルーティング処理を追加している。 投稿では、mongodb への insert 処理を、削除では、mongodb からの remove 処理を記述している。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
require 'sinatra'
require 'sinatra/reloader'
require 'mongo'

# filter
before do
  db_con = Mongo::Connection.new('localhost', 27017)
  @db    = db_con.db('sinatra_sample')
  @comments = @db.collection('comments')
end

# helper
helpers do
  # escape html
  include Rack::Utils
  alias_method :h, :escape_html
end

get '/' do
  erb :index
end

post '/new' do
  @comments.insert( :body => params[:body] )
  redirect '/'
end

post '/delete' do
  id = BSON::ObjectId( params[:id] )
  @comments.find('_id' => id).each { |d_comment|
    @comments.remove( d_comment )
  }
end

フォームとか

フォームとかを作るため、views/index.erb を修正する。

<ul> ブロックで、mongodb からデータを抜いてきてリスト表示させている。

<form> ブロックで新規の投稿をする。/new に POST しているので、上記の post '/new' do ... end 部分の処理にルーティングされる。

<script> ブロックで jquery を利用して既存記事を削除する。Google APIを利用。 [x] をクリックしたときに、/delete に POST しているので、上記の post '/delete' do ... end 部分の処理にルーティングされる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  <h1>sinatra sample</h1>
  <ul>
    <% @comments.find.each { |comment| %>
    <li data-id="<%= comment["_id"]%>">
      <%= h comment["body"] %>
      <span class="deleteCmd" style="cursor:pointer; color:blue">[x]</span>
      </li>
    <% } %>
  </ul>

  <h2>Add new</h2>
  <form method="post" action="new">
    <input type="text" name="body"> <input type="submit" value="post">
  </form>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script>
    $('.deleteCmd').click(function() {
      var el = $( this ).parent();
      if(confirm('are you sure to delete ?')) {
        $.post('/delete', {
          id: el.data('id')
          }, function() {
            el.fadeOut( 800 );
          });
      }
      })
  </script>

これで、mongodb を使った sinatra web アプリケーションができた。

ちょっと殺風景なので、twitter bootstrap3 を使ってお化粧する。

twitter bootstrap3 を使う

できあがったものがかなりそっけないので、CSS フレームワークである twitter bootstrap を使って、すこしだけおしゃれにする。 zip ファイル で配布されているので、ダウンロードして解凍する。 sinatra では静的ファイルを public/ 以下につっこむため、解凍したディレクトリを public にリネームして sinatra アプリを作っているワーキングディレクトリへ置いておく。

layout テンプレートの修正

bootstrap を使うため、views/layout.erb を以下のように修正する。 落としてきた css とscript を指定するのと、bootstrap を使う上で必須な jquery を指定している。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meata charset="urf-8">
    <title>sinatra test</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
  </head>
  <body>
  <div class="container" syle="padding:20px 0">
    <h1>Sinatra Sample</h1>
    <%= yield %>
  </div>

  <script src="http://code.jquery.com/jquery.js"></script>
  <script src="js/bootstrap.min.js"></script>
  </body>
</html>

views/indx.erb も以下のように修正する。 <ul> をやめて、<table> へ。[x]という文字列も、削除アイコンへ修正。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  <table class="table table-striped">
    <% @comments.find.each { |comment| %>
    <tr data-id="<%= comment["_id"]%>">
      <td>
      <%= h comment["body"] %>
        <span class="deleteCmd" style="cursor:pointer;">
          <i class="glyphicon glyphicon-remove"></i>
        </span>
      </td>
    </tr>
    <% } %>
  </table>

  <h2>Add new</h2>
  <form method="post" action="new">
    <div class="form-group">
      <label class="control-label" for="comment" >comment</label>
      <input type="text" name="body" class="form-control" placeholder="your comment">
    </div>
    <div class="form-group">
      <input type="submit" value="post" class="btn btn-primary">
    </div>
  </form>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
  <script>
    $('.deleteCmd').click(function() {
      var el = $( this ).parent().parent();
      if(confirm('are you sure to delete ?')) {
        $.post('/delete', {
          id: el.data('id')
          }, function() {
            el.fadeOut( 800 );
          });
      }
      })
  </script>

これで、bundle exec ruby main.rb で sinatra を起動して http://localhost:4567/ にアクセスする。

こんな感じでちょっとだけおしゃれになる。

Comments