Introduction
これまで Rails をそれなりにやってきて、ちょっとしたWebアプリならそれなりサクッと作れるようにはなりましたが、 Fat Controller だの Fat Model と言われるようにどこかで臨界点が来て、従来のMVCアーキテクチャとは違う別の設計を模索してみたい欲が出てきました
そのとっかりとして、巷で話題の クリーンアーキテクチャ に触れるために、 Rails の対抗馬として名乗りを挙げた Ruby 製フレームワーク Hanami を始めてみようかと思いました
Install
まずは Hanami を立ち上げてみます。
$ mkdir hanami-tutorial
$ cd hanami-tutorial
$ bundle init
Gemfile を書き換えます。
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "hanami"
ライブラリをインストールして Rails と同様にサーバーを立ち上げます。
$ bundle
$ bundle exec hanami new .
$ bundle exec hanami server
導入完了!と思いきや、2020年3月20日現在、エラーになりました
Bundler could not find compatible versions for gem "dry-types":
In snapshot (Gemfile.lock):
dry-types (= 0.12.3)
In Gemfile:
hanami (~> 1.3) was resolved to 1.3.3, which depends on
hanami-validations (>= 1.3, < 3) was resolved to 1.3.6, which depends on
dry-validation (~> 0.11, < 0.12) was resolved to 0.11.2, which depends on
dry-types (~> 0.12.0)
hanami-model (~> 1.3) was resolved to 1.3.2, which depends on
dry-types (~> 0.11.0)
Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.
指示に従って、もう一度サーバーを立ち上げます。
$ bundle update
$ bundle exec hanami server
http://localhost:2300/ を開くと...
Static Page
Rails チュートリアルと同様に、まずは静的なページを作ってみます。
ルーティングは Rails 感があります。
root to: 'home#index'
アクションは Rails と違い独立したクラスを作ります。
module Web
module Controllers
module Home
class Index
include Web::Action
def call(params)
end
end
end
end
end
ビューも Rails と違います。 Rails における View は Hanami においては View と Template に分かれていて、 Rails の Helper などの UI に関わるロジックは View で、 HTML テンプレートは Template が担当します。
module Web
module Views
module Home
class Index
include Web::View
end
end
end
end
<h1>Bookshelf</h1>
http://localhost:2300/ を開くとページが差し替わったはずです。
これで自由にページを作れるようになりました
Template Engine
Hanami のデフォルトのテンプレートエンジンは Rails と同様に Erb ですが、 Slim や Haml で書きたいですよね。
Slim をインストールして、先ほど作ったテンプレートを書き換えます。
gem 'slim'
$ bundle
$ mv apps/web/templates/home/index.html.erb apps/web/templates/home/index.html.slim
h1 Bookshelf
これで Slim は導入できました
Pry
Ruby 2.7 以下だとデバッグのために Pry を導入したいですね。これも簡単。
gem 'pry'
$ bundle
$ bundle exec hanami console
[1] pry(main)>
Ridgepole
意見は分かれますが、自分はプロトタイピング重視で、 Rails のマイグレーションではなく Ridgepole を使いたいです。
gem 'ridgepole'
$ bundle
Rails の database.yml
に相当するものが無いので、便宜上新たに作ります。
# ridgepole を使うために用意
development:
adapter: sqlite3
database: db/hanami_tutorial_development.sqlite
Ridgepole が使う Schemafile を生成します。まだテーブルを定義していないので空ファイルが出力されます。
$ bundle exec ridgepole -c config/database.yml -e > Schemafile
テーブルを作ってみます。
create_table :users, force: :cascade do |t|
t.string :email, null: false
t.timestamps null: false
t.index :email, unique: true
end
$ bundle exec ridgepole -c config/database.yml -a
Apply `Schemafile`
-- create_table("users", {})
-> 0.0052s
-- add_index("users", ["email"], {:unique=>true})
-> 0.0035s
テーブルが作られたのでモデルを作ります。 Rails におけるモデルは Hanami においては Repository と Entity に分かれます。クリーンアーキテクチャが見えてきましたね
class UserRepository < Hanami::Repository
end
class User < Hanami::Entity
end
コンソールで動作確認してみます。
[1] pry(main)> UserRepository.new.create(email: 'test@example.com')
[2] pry(main)> UserRepository.new.find(1)
=> #<User:0x0000000000000000 ...
[3] pry(main)> UserRepository.new.users.where(email: 'test@example.com')
=> #<ROM::Relation::Composite name=users dataset= ...
Hanami は ActiveRecord ではなく Rom という ORM を使っていますが、 Rails エンジニアなら雰囲気で使えそうな気がしますよね?
Job Queue
Rails の ActiveJob に相当する非同期処理モジュールが Hanami にはありませんが、自分の経験上 Job Queue ミドルウェアを移行することはそんなに無いので、ここでは Sidekiq を入れてみましょう。
gem 'sidekiq'
Sidekiq.configure_server do |config|
config.redis = { url: ENV['REDIS_URL'] }
end
Sidekiq.configure_client do |config|
config.redis = { url: ENV['REDIS_URL'] }
end
ワーカーを作ります。引数で与えられた秒数だけ待機して foo! と叫ぶだけのやつです。
class SleepyEchoWorker
include Sidekiq::Worker
def perform(time)
sleep time
puts 'foo!'
end
end
Sidekiq を立ち上げます。
$ REDIS_URL=redis://localhost:6379 bundle exec sidekiq -r ./config/boot.rb
コンソールでワーカーを呼び出します。
[1] pry(main)> SleepyEchoWorker.perform_async(3)
Sidekiq を立ち上げたターミナルで、3秒間待機した後に foo! とログに出ることが確認できましたね
Conclusion
Rails エンジニアが Hanami でWebアプリを開発するための初期導入についてまとめてみました。今後 Hanami で開発する際にハマったことがあればここに追記していこうかと思います。
ありがとうございました