はじめに
この記事は前回の続きです。↓↓↓
https://qiita.com/alex0033/items/73f62ac7e5700ab2b4d6
今回は、コントローラー編ということで、Railsにおけるルーティングを実装していきたいと思います。
目指すべきディレクトリ構成は下記の通りです。
directory
|- app
|- controllers
|- basic_pages_controller
|- views
|- basic_pages
|- home.html.erb # ホームページ
|- next.html.erb # ネクストページ
|- config
|- routes.rb
|- srv.rb
ポイント
前回まで、次のような状態になっています。
・ruby srv.rb
とターミナルで入力すると、サーバを立てることができる。
・http://localhost:3000 にアクセスすると、ホームページが表示される。
今回目指すのは、下記の通りです。
・http://localhost:3000 (以後、ルートパス)にアクセスすると、ホームページが表示される。
・http://localhost:3000/next (以後、ネクストパス)にアクセスすると、ネクストページが表示される。
・ページアクセスの前にコントローラーを通るようにする
そこで、本記事の説明は次のようになります。
1.ネクストページの表示
①ビューファイル(app/views/basic_pages/next.html.erb)の作成
②<a>タグでホームページからアクセスしてみる
③設定(srv.rb)を変更
2.コントローラーもどきの作成
①サーブレットによるロジックの反映
②ファイルを整理してコントローラー風にする
3.ルーティング
①ルーティングの設定ファイル(config/routes.rb)の作成
②メタプログラミングによるルーティングの自動生成
1.ネクストページの表示
まずは、ネクストページを作成し、表示出来るようにしましょう。次の順に記述してきます。
①ビューファイル(app/views/basic_pages/next.html.erb)の作成
②<a>タグ でホームページからアクセスしてみる
③設定(srv.rb)を変更
①ビューファイル(app/views/basic_pages/next.html.erb)の作成
ビューファイルを作成しましょう。
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>ネクストページ</h1>
<p>This is a next page.</p>
</body>
</html>
##②<a>タグ でホームページからアクセスしてみる
ビューファイルの存在だけでは、アクセスすることができません。そこで、ホームページから<a>タグ を用いてアクセスを試みてみましょう。
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>ホームページ</h1>
<p>Hello, World</p>
<%= 1 + 4 %>
<!-- ネクストページへのリンク -->
<a href="../next.html.erb">to next</a>
</body>
</html>
ルートパスへアクセスすると、次のようになっているはずです。
試しに"to next"をタッチしてリンクをたどってみましょう。
おそらく、URLがhttp://localhost:3000/next.html.erb となっただけではないでしょうか。
③設定(srv.rb)を変更
ここまで、DocumentRoot
として、 ホームページへのパスを設定していました。
ここからは、app/views
に設定し、個別にURLと表示ファイルを設定していきます。
require 'webrick'
op = {
BindAdress: "127.0.1",
Port: 3000,
DocumentRoot: "."
}
WEBrick::HTTPServlet::FileHandler.add_handler("erb", WEBrick::HTTPServlet::ERBHandler)
s = WEBrick::HTTPServer.new(op)
# 以下、URLと表示ファイルの個別設定
s.mount('/', WEBrick::HTTPServlet::FileHandler, 'app/views/basic_pages/home.html.erb')
s.mount('/next', WEBrick::HTTPServlet::FileHandler, 'app/views/basic_pages/next.html.erb')
s.start
これで、ルートパスとネクストパスの設定はできました。
しかし、ホームページとのリンクが未設定なので、設定しましょう。
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>ホームページ</h1>
<p>Hello, World</p>
<%= 1 + 4 %>
<!-- ネクストページへのリンク設定 -->
<a href="/next">to next</a>
</body>
</html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>ネクストページ</h1>
<p>This is a next page.</p>
<!-- ホームページへのリンク設定 -->
<a href="/">to home</a>
</body>
</html>
これで、"to next"や"to home"をクリックすることで、ホームページとネクストページへの行き来ができるようになりました。
参考↓↓↓
https://docs.ruby-lang.org/ja/latest/library/webrick.html
https://docs.ruby-lang.org/ja/latest/method/WEBrick=3a=3aHTTPServer/i/mount.html
2.コントローラーの作成
ここまでで、URLを設定することによる画面遷移ができるようになりました。
ここから、コントローラーを通った上で、ビューを表示できるようにしていきましょう。
①サーブレットによるロジックの反映
②ファイルを整理してコントローラー風にする
①サーブレットによるロジックの反映
まずは、サーブレットを使って、ページ遷移前にロジックが反映されるようにしてみましょう。
require 'webrick'
require 'erb'
include WEBrick
op = {
BindAdress: "127.0.1",
Port: 3000,
DocumentRoot: "."
}
s = HTTPServer.new(op)
# サーブレット
class HomeServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
# ロジックのスタート
@home_string = "pass homeServlet"
# ロジックのエンド
erb = ERB.new File.open('app/views/basic_pages/home.html.erb').read
res.body = erb.result(binding)
end
end
class NextServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
# ロジックのスタート
@next_string = "pass nextServlet"
# ロジックのエンド
erb = ERB.new File.open('app/views/basic_pages/next.html.erb').read
res.body = erb.result(binding)
end
end
s.mount('/', HomeServlet)
s.mount('/next', NextServlet)
trap(:INT){ s.shutdown }
s.start
これで、インスタンス変数の値が反映されるはずです。
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>ホームページ</h1>
<p>Hello, World</p>
<p><%= 1 + 4 %></p>
<a href="/next">to next</a>
<p><%= @home_string %></p>
<p><%= @next_string %></p>
</body>
</html>
サーバを立てホームページにアクセスすると、インスタンス変数に格納された"pass homeServlet"という文字列の表示を確認することができると思います。
参考↓↓↓
http://unageanu.hatenablog.com/entry/20080720/1216539411
https://magazine.rubyist.net/articles/0017/0017-BundledLibraries.html
②ファイルを整理してコントローラー風にする
このままでは、コントローラーに当たるロジックがsrv.rbに書かれており、見通しが悪くなっています。
そこで、新たなディレクトリとファイルを作ることで整理していきましょう。
require 'erb'
def render_result(path)
erb = ERB.new File.open("app/views/#{path}.html.erb").read
erb.result(binding)
end
module BasicPagesController
class HomeServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
@home_string = "pass homeServlet"
res.body = render_result 'basic_pages/home'
end
end
class NextServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
@next_string = "pass nextServlet"
res.body = render_result 'basic_pages/next'
end
end
end
require 'webrick'
include WEBrick
op = {
BindAdress: "127.0.1",
Port: 3000,
DocumentRoot: "."
}
s = HTTPServer.new(op)
# ホームページとネクストページを表示させるためのロジック
require './app/controllers/basic_pages_controller.rb'
include BasicPagesController
s.mount('/', HomeServlet)
s.mount('/next', NextServlet)
trap(:INT){ s.shutdown }
s.start
これで、だいぶスッキリしました。
3.ルーティング
ここまでで、コントローラーを通ったページ表示が実装できました。
しかし、このままでは、新たなページ作成の度に、srv.rbを手動で更新することになります。
それでは、どんなページがあるのか分かりにくいので、ルーティングファイル(config/routes.rb)を使って整理します。
以下の手順で実装していきます。
①ルーティングの設定ファイル(config/routes.rb)の作成
②メタプログラミングによるルーティングの自動生成
①ルーティングの設定ファイル(config/routes.rb)の作成
class Routes
def initialize
@routes = Array.new
end
def make_routes
# 下記にルートを記載
get "/", "basic_pages", "home"
get "/next", "basic_pages", "next"
# 下記に返り値を記載(ルート情報の一覧を返す)
return @routes
end
def get(url, controller_name, action)
@routes.push({ url: url, controller_name: controller_name, action: action })
end
end
srv.rbにおいて、インスタンスを生成して、make_routesでルート一覧を生成・取得できるようにします。
②メタプログラミングによるルーティングの自動生成
config/routes.rbを元に、実際のルーティングをsrv.rbで設定していくコードを書く必要があります。
require 'webrick'
include WEBrick
op = {
BindAdress: "127.0.1",
Port: 3000,
DocumentRoot: "."
}
s = HTTPServer.new(op)
# Stringクラスの拡張
class String
def to_camel()
self.split("_").map{ |w| w[0] = w[0].upcase; w }.join
end
end
# ルーティング情報の取得
require './config/routes.rb'
r = Routes.new
routes = r.make_routes
# メタプログラミングでルーティングを自動生成
routes.each do |route|
require "./app/controllers/#{route[:controller_name]}_controller.rb"
include eval("#{route[:controller_name].to_camel}Controller")
s.mount route[:url], eval("#{route[:action].to_camel}Servlet")
end
trap(:INT){ s.shutdown }
s.start
これで、ルーティングも完成です。
まとめ
今回はコントローラー編ということで、コントローラーを通ったページ遷移を実装しました。
railsっぽくするには、まだまだ道のりが長そうですが、少しずつ実装していきたいと思います。