SinatraでWebアプリの基本を理解する(データはファイルに保存)


Railsという巨大なフレームワークを学習する前に、Rubyを用いてWebアプリケーションを作成するためのフレームワークである「Sinatra」でWeb開発の基礎を学びました。

シンプルなメモアプリを作成しました。

RubyとSinatraではじめる Webアプリケーション開発の教科書 が参考になりました。

メモアプリの機能

  • メモの作成、編集、削除
  • メモ一覧の表示
  • 特定のメモを表示

実行環境

  • Ruby:3.1.2
  • Bundler:2.3.16 →ユーザー全体の共有場所ではなく、アプリケーションディレクトリに必要なgemパッケージを整えるソフトウェア。
  • sinatra:3.0.5
  • webrick:1.7.0 →Ruby上でWebサーバーの機能を提供するライブラリ。
  • sinatara-contrib:3.0.5

学んだこと✏️

1.ディレクトリを設計
  • 画像ファイルなど静的なコンテンツは、アプリケーションディレクトリ直下のpublicに入れておく。 ※ここでは、public/配下にデータ保存先のファイルを置くと、URLにアクセスした際にファイルの中身が閲覧できてしまう。
memo_app/
  - data/
    - memos.json # データ保存先
  - public/
    - styles.css # CSSファイル
  - views/
    - edit.erb # メモ編集画面
    - index.erb # メモ一覧表示画面
    - layout.erb # 各ビューの共通部分
    - new.erb # メモ作成画面
    - show.erb # 特定のメモ表示画面
  - memo.rb # ルーティング定義
2. 実装
2-1. ディレクトリとライブラリの用意
  • まず、関連ファイルが散乱しないように適当な名前で作業用のディレクトリを作成。

  • Gemfile(Bundlerの設定ファイル)を編集し、gemをインストール。

2-2. メモ一覧の表示機能
  • メモのデータとしてdata/memos.jsonを作成。

  • memo.rbを作成し、ルーティングを定義。

Routes - Sinatra README.md

  • メモ一覧を表示するビューviews/layout.erbを作成。

    • viewsというディレクトリ名とlayout.erbというファイル名は、Sinatraのルールとして固定。
    • erbとはEmbedded Rubyの略で、HTMLのデータ本体に直接Rubyのプログラムを埋め込んで実行する技術のこと。
    • <%= yield %>の部分にそれぞれのビューの内容が埋め込まれる。
    • data/styles.cssを用意。今回は見た目は考慮せず作成。
  • メモ一覧を表示するviews/index.erbを作成。

2-3. 特定のメモの表示機能
  • memo.rbにルーティングを追加し、views/show.erbを作成。
  • views/index.erbにメモへのリンクを追加。
2-4. メモの作成機能
  • memo.rbにルーティングを追加し、views/new.erbを作成。
  • ルーティングは上から順に合致するURLを探すため、get '/memos/new'get '/memos/:id'より上に配置する。
  • SecureRandom.uuidを使用し、一意のIDを付与。登録した順に表示させるため、Time.nowメソッドを使用。
  • 実装はPRGパターン(Post→Redirect→Get)
  • views/index.erbにメモ作成画面へのリンクを追加します。
2-5. メモの編集機能
  • memo.rbにルーティングを追加し、views/edit.erbを作成。
  • URLに任意のアドレスを指定することは簡単にできる為、該当のメモがすでに存在するか確認する処理を追記。(ディレクトリトラバーサルなどの様々な脆弱性に繋がる)
  • views/show.erbに編集ボタンを追加。
2-6. メモの削除
  • memo.rbにルーティングを追加し、views/show.erbに削除ボタンを追加。

3. XSS対策(メモ保存時にhtmlをエスケープする)

  • XSS対策としてRack::Utilsescape_htmlを使用。 helpers(views側で使うロジックを入れることが多い)に定義しておくとどこからでも呼び出せる。

memos.rbに以下を追加。

#require 'json'

helpers do
  def h(text)
    Rack::Utils.escape_html(text)
  end
end
  • views側を書き換える。