概要
app.rb
など一つのファイルにいろいろなルーティングを実装するとファイルを分けたくなると思います
今回はその方法を紹介したいと思います
おそらく王道の方法かなと思います
環境
- macOS 10.13.4
- Ruby 2.5.1p57
- Sinatra 2.0.1
各種ファイルの準備
- bundle init
- vim Gemfile
gem "sinatra"
bundle install --path vendor
- touch config.ru
- mkdir controllers
- touch controllers/home.rb
- touch controllers/admin.rb
- mkdir views
- touch views/home.erb
- touch views/admin.erb
今回は分離するコントローラは controllers
というディレクトリで管理することにします
全体の構成は以下のとおりです
.
├── .bundle
│ └── config
├── Gemfile
├── Gemfile.lock
├── config.ru
├── controllers
│ ├── admin.rb
│ └── home.rb
└── views
├── admin.erb
└── home.erb
3 directories, 8 files
config.ru の作成
Sinatra でコントローラを分ける場合、パスごとに処理するコントローラを Rack::URLMap
という機能を使って定義します
今回は 2 つのルーティングを違うコントローラを使って処理します
require './controllers/home.rb'
require './controllers/admin.rb'
run Rack::URLMap.new({
'/' => Home,
'/admin' => Admin
})
作成した Rack::URLMap
を run することを忘れないようにしてください
home.rb
に Home クラスを admin.rb
に Admin クラスを後で定義します
home.rb の作成
先程定義した /
ルーティングを処理するクラスを定義します
- vim controllers/home.rb
require 'sinatra/base'
class Home < Sinatra::Base
set :root, File.join(File.dirname(__FILE__), '..')
set :views, Proc.new { File.join(root, "views") }
get '/' do
erb :home
end
get '/users' do
'users'
end
end
今回は 2 つの処理を記載しました
/
に対する処理と /users
に対する処理です
ついでにテンプレートも作成します
- vim views/home.erb
home
とりあえず文字列を返すようにします
作成したクラスは必ず Sinatra::Base
を継承します
また今回のようにコントローラをアプリケーションの直下ではなく controllers
といったサブディレクトリに配置する場合には Sinatra の :root
と :views
の書き換えが必要になります
set :root, File.join(File.dirname(__FILE__), '..')
set :views, Proc.new { File.join(root, "views") }
何をしているかというと home.rb
の一つ上位のディレクトリを :root
に設定しかつ :root
配下にある views
というディレクトリをテンプレートを定義するディレクトリとして設定しています
デフォルトだとこれがコントローラクラスの直下になっています
admin.rb の作成
今度は /admin
配下を処理する Admin クラスを定義します
- vim controllers/admin.rb
require 'sinatra/base'
class Admin < Sinatra::Base
set :root, File.join(File.dirname(__FILE__), '..')
set :views, Proc.new { File.join(root, "views") }
get '/' do
erb :admin
end
get '/users' do
'admin users'
end
end
- vim views/admin.erb
admin
先程の home.rb
とほぼ同じように定義されていることがわかります
が、admin.rb
は /admin
配下のルーティングを処理します
なので上記の場合、処理するパスとしては /admin
と /admin/users
が対象になります
このように URLMap
で定義したパスはコントローラ内の実装では省略することができます
動作確認
- bundle exec rackup config.ru
で起動しましょう
localhost:9292
で起動します
確認するパスとしては以下の 4 つです
/
-> home が返ってくる/users
-> users が返ってくる/admin
-> admin が返ってくる/admin/users
-> admin users が返ってくる
となれば OK です
上記以外のパスにアクセスした場合は Sinatra のデフォルトの 404 ページが返ってくると思います
ちょっとしたテクニック
「404 や 500 ページは共通のページを出したい」
「コントローラクラスに毎回 :root
と :views
を定義するのは面倒」
という場合には Base クラスを作成しましょう
- vim controllers/base.rb
require 'sinatra/base'
class Base < Sinatra::Base
set :root, File.join(File.dirname(__FILE__), '..')
set :views, Proc.new { File.join(root, "views") }
end
そして home.rb
で継承するクラスを Base クラスに変更すれば OK です
- vim controllers/home.rb
require './controllers/base.rb'
class Home < Base
get '/' do
erb :home
end
get '/users' do
'users'
end
end
こうすることで毎回定義する必要がなくなります
また、先程少し出てきた 404 ページの処理などもこの base.rb に記載すれば継承した home.rb などで実装する必要がなくなります
また rspec と組み合わせたテストを行いたい場合は spec_helper.rb で app メソッドを定義する際に Rack::URLMap
を返すようにすれば OK です
各種コントローラクラスの require も忘れないようにしてください
module RSpecMixin
include Rack::Test::Methods
def app
Rack::URLMap.new({
'/' => Home,
'/admin' => Admin
})
end
end
最後に
Sinatra でコントローラを分離する方法を紹介しました
おそらくこれが王道の方法だと思います
このあたりの処理は Sinatra では自分で実装するしかありません
が、rails などを使えばフレームワーク側で全部やってくれるものもあります
ただ、rails の場合はルーティングを追加すると実装するべき関数も勝手にいろいろ定義されるのでやりすぎちゃう感もあります
この辺りは自分のやりたいことに合わせて選択すれば良いかなと思います
0 件のコメント:
コメントを投稿