やーまんぶろぐ

気が向いた時にだけ書くブログ

【ドットインストール】Sinatra入門

ドットインストールのSinatra入門を見てみました。
dotinstall.com

こないだBOTを作成するときに、久しぶりにSinatraを触ったので復習がてらですね。
yamano3201.hatenablog.jp

環境

➜  sinatra  ruby -v
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]
➜  sinatra  gem -v
2.6.3
➜  sinatra  gem list activerecord

*** LOCAL GEMS ***

activerecord (4.2.6, 4.2.1, 4.0.1)
activerecord-deprecated_finders (1.0.4, 1.0.3)
➜  sinatra  gem list sqlite3

*** LOCAL GEMS ***

sqlite3 (1.3.10)
➜  sinatra  gem list sinatra

*** LOCAL GEMS ***

sinatra (1.4.7, 1.4.6)
sinatra-contrib (1.4.7)

sinatra-contribをインストールして、require 'sinatra/reloader' しておきましょう。
コード修正するたびにSinatraの再起動が不要になるので便利です。
webcreator.weva.jp

実行方法

ruby main.rb -o localhost

あとはブラウザからアクセスするだけ。デフォルトは4567ポート。

パラメータを使う

require 'sinatra'
require 'sinatra/reloader'

# http://localhost:4567/about
get '/about' do
  "about this site page"
end

# http://localhost:4567/hello/kenta/yamano
# ?で挟んだパラメータであるname1, name2はなくても良い
get '/hello/?:name1?/?:name2?' do |name1, name2|
  "hello #{name1} #{name2}"
end

# http://localhost:4567/from/hokkaido/to/tokyo
# *はなんでも良い
get '/from/*/to/*' do |from, to|
  "from #{from} to #{to}"
end

# http://localhost:4567/users/555
# [0-9]* には数字の連続が入る
get %r{/users/([0-9]*)} do |i|
  "user id = #{i}"
end

テンプレートファイルを使う

require 'sinatra'
require 'sinatra/reloader'

# before処理は他の処理が始まる前に実行される
before do
  @author = "yamano"
end

# after処理は他の処理が始まる前に実行される
# logger.infoで指定した文字列はsinatraを立ち上げている画面で出力される
after do
  logger.info "page displayed successfully"
end

# よく使う処理はhelpersに登録しておくと便利
helpers do
  def strong(s)
    "<strong>#{s}</strong>"
  end
end

# http://localhost:4567/about
# views/about.erb ファイルを開く
# strongはhelpersで定義してある
get '/about' do
  @title = "about this page"
  @content = "this page is ... by " + strong(@author)
  @email = "xxx@gmail.com"
  erb :about
end

# http://localhost:4567/yamano
# views/index.erb ファイルを開く
# strongはhelpersで定義してある
get '/:name' do |n|
  @name = n
  @title = "Sinatra入門"
  @content = "main content by " + strong(@author)
  erb :index
end

viewsフォルダの下にあるerbファイルを呼び出すことができます。それぞれabout.erbファイルとindex.erbファイルを呼び出しています。

views/about.erb

<div><%= @content %></dv>
<div><%= @email %></dv>

views/index.erb

<h1>Hello <%= @name %></h1>
<div><%= @content %></dv>

erbファイルの共通部分はlayout.erbに書き出すことができます。
yieldの部分でindex.erbやabout.erbを呼んでいます。

views/layout.erb

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title><%= @title %></title>
</head>
<body>
  <%= yield %>
</body>
</html>

掲示板アプリを作る

上で学んだことを使いつつ、コメントの一覧表示、作成、削除を行える簡単なアプリを作ります。
f:id:yamano3201:20160426003542p:plain

掲示板アプリではDBを使うので、事前にsqlファイルからtableを作成しておきます。

import.sql

create table comments (
  id integer primary key,
  body text
);

.read で上のファイルをインポートします。

sqlite3 bbs.db
SQLite version 3.8.5 2014-08-15 22:37:57
Enter ".help" for usage hints.
sqlite> .read import.sql 

sqlite> .schema
CREATE TABLE comments (
  id integer primary key,
  body text
);
sqlite> quit;

ここからrubyファイル。

require 'sinatra'
require 'sinatra/reloader'
require 'active_record'

# 使用するDBを宣言
ActiveRecord::Base.establish_connection(
  "adapter" => "sqlite3",
  "database" => "./bbs.db"
)

class Comment < ActiveRecord::Base
end

# 入力にスクリプトが埋め込まれても実行されないようにエスケープする。
# erbファイルの入力のところでhを挿入することでエスケープできる。
helpers do
  include Rack::Utils
  alias_method :h, :escape_html
end

# 一覧表示。@commentsにコメント一覧が入っている。erbファイルではこれを呼び出す。
get '/' do
  @comments = Comment.order("id desc").all
  erb :index2
end

# bodyをキー、erbファイルで入力されたparams[:body]をバリューにしてDBに格納している
post '/new' do
  Comment.create({:body => params[:body]})
  redirect '/'
end

# 削除。idで削除。
post '/delete' do
  Comment.find(params[:id]).destroy
end

削除のところでは、jQueryを使っています。

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="utf-8">
  <title>BBS</title>
</head>
<body>
  <h1>BBS</h1>
  <ul>
    <% @comments.each do |comment| %>
    <li data-id="<%= comment.id %>">
      <%= h comment.body %>
      <span class="deleteCmd" style="cursor:pointer;color:blue">[x]
    </li>
    <% end %>
  </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.12.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>

</body>
</html>

これで簡単なアプリが動きます。

最後に

RailsでいうroutingとControllerとModelが一つのrubyファイルで表現されているイメージですかね。
簡単なCRUDアプリならSinatraで十分ですね。

Rails触ったことない人は、この記事だけだときついと思いますので本家の動画で確認ください。

気が向いたら、また書きます。