以前、まだQiitaを愛していた頃に、こんな記事を書いたことがある。
社内向けWebアプリで、機能が限定的だったとしても、SinatraじゃなくてRailsで書いたほうが総合的にラクよ、という話。この考え自体は今もそんなに変わっていなくて、なんだかんだでRailsはラクだ。
しかし、最近になって、SinatraでWebアプリケーションを書いてみて「これはうまく行った」という例を1つ見つけた。
不具合解析のアシスタント的なアプリケーションだ。
- DBはもともとあるものに接続して、そこにある情報を読むだけ。書き込みは行わない。
- sinatra-activerecordは使う
- SinatraにおけるDBマイグレーションのツラミを感じることがない
- 入力フォームは最低限でいい
- テストを真面目に書く必要がない
ようするに、手でSQLを叩くよりはマシ、くらいのものを作りたければ割とお手軽ということ。
## application.rb ## # frozen_string_literal: true require 'bundler' Bundler.require :default, (ENV['RACK_ENV'] || :development).to_sym require_relative './config/activerecord' require_relative './config/zeitwerk' require 'sinatra/base' class Application < Sinatra::Base # いろいろ... end
## config.ru ## # frozen_string_literal: true require_relative './application' run Application
## Gemfile ## # frozen_string_literal: true source 'https://rubygems.org' gem 'mysql2' gem 'puma' gem 'rack' gem 'sinatra', require: false gem 'sinatra-activerecord' gem 'zeitwerk' group :development do gem 'pry-byebug' gem 'rubocop' end
## config/zeitwerk.rb ## # frozen_string_literal: true loader = Zeitwerk::Loader.new loader.push_dir('./models') loader.setup
## config/activerecord.rb ## # frozen_string_literal: true # ref: https://hai3.net/blog/active-record-readonly/ module ActiveRecord class Base def readonly? true end def self.readonly_attributes attribute_names end # Disable annoying STI self.inheritance_column = :_xxxxxx end end ActiveRecord::Base.logger = Logger.new($stdout) ActiveRecord.verbose_query_logs = true
このくらいの下地を整えてあげれば、modelsにDB参照用に振り切ったモデルを定義して、config/database.ymlをRailsのものをコピってくれば、あとはviewsを必要な分だけ置けばいい。
MVCしたい?
SinatraアプリケーションではModelとViewはあるが、コントローラなんてものはない。
とはいえ、わざわざコントローラ"層"を定義する必要がどこまであるだろう?erbにして、冒頭で必要なパラメータを取ればそれでよくないだろうか?
class Application < Sinatra::Base get '/customer_info' do erb :"guide/customer_info.html" end end
## views/guide/customer_info.html.erb <% customer_id = params[:customer_id].presence customer_name = params[:customer_name].presence if customer_id.present? @customer = Customer.find(customer_id) elsif customer_name.present? @customer = Customer.find_by!(name: customer_name) end %> <form method="GET"> <p>どれか1こ入れてね。</p> <div class="mb-3"> <label for="input_customer_id" class="form-label">ID</label> <input id="input_customer_id" type="text" class="form-control" name="customer_id" value="<%= customer_id %>" /> </div> <div class="mb-3"> <label for="input_customer_name" class="form-label">NAME</label> <input id="input_customer_name" type="text" class="form-control" name="customer_name" value="<%= customer_name %>" /> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> <% if @customer %> <% data = [ ['ID', @customer.id], ['NAME', @customer.name], ['契約開始日', @customer.contract.started_at], ] %> <table class="table"> <thead> <tr> <th scope="col">key</th> <th scope="col">value</th> </tr> </thead> <tbody> <% data.each do |key, value| %> <tr> <th scope="row"><%= key %></th> <td><%= value %></td> </tr> <% end %> </tbody> </table> <% end %>
まとめ
DBをみて解析が必要なシーンだと、Sinatra+ActiveRecordでWebアプリケーション作ると意外とイイ!
(コードは、このリポジトリを大いに参考にさせてもらった。)