【RoR】「Railsの教科書」を使っての勉強(4)

概要

先に行った「アプリ作成」で、色々と知識不足が判明した。
そして、この状態で Rails 学習を進めても行き詰まると感じたので、より簡単でかつ分量が少ない情報を探した。
その結果、達人出版社の電子書籍「Railsの教科書」を使うことにしたので、同著書を使った勉強の記録を残す。

なお、「Railsの教科書」は著者の五十嵐邦明様が購入し易い金額*1で販売してくださっていますので、
ぜひ、ご購入のうえで本ページをご覧いただければ幸いです。
*2
 

開発環境

  • Linux (Ubuntu17.04)
  • ローカルPCを Web サーバとして稼働させる。(従って Cloud9 は使わない)

 

内容

本ページでは、Rails ファイルの構成・役割を記述する。
なお、基にしたプログラムは直前の【RoR】「Railsの教科書」を使っての勉強(3)で作成したプログラムである。
 

ファイルとディレクトリ構成

「rails new helloworld」と「rails g controller hello index」実行後の結果

  • 下図の ★ および 無表記が rails new hello で作成されたファイル・ディレクトリである。
  • 下図の ☆ が rails g controller hello index で作成されたファイル・ディレクトリの抜粋である。
% tree -L 3
.
└── helloworld
    ├── Gemfile
    ├── Gemfile.lock
    ├── README.md
    ├── Rakefile
    ├── app
    │   ├── assets
    │   │   ├── config
    │   │   │   └── manifest.js
    │   │   ├── images
    │   │   ├── javascripts
    │   │   │   ├── application.js
    │   │   │   ├── cable.js
    │   │   │   └── channels
    │   │   └── stylesheets
    │   │       └── application.css
    │   ├── channels
    │   │   └── application_cable
    │   │       ├── channel.rb
    │   │       └── connection.rb
    │   ├── controllers          ★MVC の Controller
    │   │   ├── application_controller.rb
    │   │   ├── hello_controller.rb     ☆ hello/index 依存処理
    │   │   └── concerns
    │   ├── helpers
    │   │   ├── hello_helpers.rb      ☆ hello/index 依存処理
    │   │   └── application_helper.rb
    │   ├── jobs
    │   │   └── application_job.rb
    │   ├── mailers
    │   │   └── application_mailer.rb
    │   ├── models           ★ MVC の Model。
    │   │   ├── application_record.rb
    │   │   └── concerns
    │   └── views            ★MVC の View。ブラウザへの表示処理をする
    │       ├── hello
    │        |  └── index.html.erb      ☆hello/index 依存処理
    │       └── layouts
    │           ├── application.html.erb
    │           ├── mailer.html.erb
    │           └── mailer.text.erb
    ├── bin
    │   ├── bundle
    │   ├── rails
    │   ├── rake
    │   ├── setup
    │   ├── update
    │   └── yarn
    ├── bin
    │   ├── bundle
    │   ├── rails
    │   ├── rake
    │   ├── setup
    │   ├── update
    │   └── yarn
    ├── config
    │   ├── application.rb
    │   ├── boot.rb
    │   ├── cable.yml
    │   ├── database.yml
    │   ├── environment.rb
    │   ├── environments
    │   │   ├── development.rb
    │   │   ├── production.rb
    │   │   └── test.rb
    │   ├── initializers
    │   │   ├── application_controller_renderer.rb
    │   │   ├── assets.rb
    │   │   ├── backtrace_silencers.rb
    │   │   ├── cookies_serializer.rb
    │   │   ├── filter_parameter_logging.rb
    │   │   ├── inflections.rb
    │   │   ├── mime_types.rb
    │   │   └── wrap_parameters.rb
    │   ├── locales
    │   │   └── en.yml
    │   ├── puma.rb
    │   ├── routes.rb        ★URL と Controller の紐付け
    │   ├── secrets.yml
    │   └── spring.rb
    ├── config.ru
    ├── db
    │   └── seeds.rb
    ├── lib
    │   ├── assets
    │   └── tasks
    ├── log
    ├── package.json
    ├── public
    │   ├── 404.html
    │   ├── 422.html
    │   ├── 500.html
    │   ├── apple-touch-icon-precomposed.png
    │   ├── apple-touch-icon.png
    │   ├── favicon.ico
    │   └── robots.txt
    ├── test
    │   ├── application_system_test_case.rb
    │   ├── controllers
    │   ├── fixtures
    │   │   └── files
    │   ├── helpers
    │   ├── integration
    │   ├── mailers
    │   ├── models
    │   ├── system
    │   └── test_helper.rb
    ├── tmp
    │   └── cache
    │       └── assets
    └── vendor
        └── bundle
            ├── bin
            │   ├── puma
            │   ├── pumactl
            │   ├── rackup
            │   ├── rake
            │   ├── sprockets
            │   ├── thor
            │   └── tilt
            ├── build_info
            ├── cache
            │   ├── activesupport-5.1.6.gem
            │   ├── arel-8.0.0.gem
            │   ├── builder-3.2.3.gem
            │   ├── coffee-script-2.4.1.gem
            │   ├── coffee-script-source-1.12.2.gem
            │   ├── concurrent-ruby-1.0.5.gem
            │   ├── crass-1.0.4.gem
            │   ├── erubi-1.7.1.gem
            │   ├── execjs-2.7.0.gem
            │   ├── ffi-1.9.23.gem
            │   ├── i18n-1.0.0.gem
            │   ├── mail-2.7.0.gem
            │   ├── method_source-0.9.0.gem
            │   ├── mini_mime-1.0.0.gem
            │   ├── mini_portile2-2.3.0.gem
            │   ├── minitest-5.11.3.gem
            │   ├── multi_json-1.13.1.gem
            │   ├── nio4r-2.3.0.gem
            │   ├── nokogiri-1.8.2.gem
            │   ├── puma-3.11.3.gem
            │   ├── rack-2.0.4.gem
            │   ├── rack-test-1.0.0.gem
            │   ├── rake-12.3.1.gem
            │   ├── rb-fsevent-0.10.3.gem
            │   ├── rb-inotify-0.9.10.gem
            │   ├── sprockets-3.7.1.gem
            │   ├── sqlite3-1.3.13.gem
            │   ├── thor-0.20.0.gem
            │   ├── thread_safe-0.3.6.gem
            │   ├── tilt-2.0.8.gem
            │   ├── turbolinks-5.1.0.gem
            │   ├── turbolinks-source-5.1.0.gem
            │   ├── tzinfo-1.2.5.gem
            │   ├── uglifier-4.1.8.gem
            │   ├── websocket-driver-0.6.5.gem
            │   └── websocket-extensions-0.1.3.gem
            ├── doc
            ├── extensions
            │   └── x86_64-linux
            ├── gems
            │   ├── activesupport-5.1.6
            │   ├── arel-8.0.0
            │   ├── builder-3.2.3
            │   ├── coffee-script-2.4.1
            │   ├── coffee-script-source-1.12.2
            │   ├── concurrent-ruby-1.0.5
            │   ├── crass-1.0.4
            │   ├── erubi-1.7.1
            │   ├── execjs-2.7.0
            │   ├── ffi-1.9.23
            │   ├── i18n-1.0.0
            │   ├── mail-2.7.0
            │   ├── method_source-0.9.0
            │   ├── mini_mime-1.0.0
            │   ├── mini_portile2-2.3.0
            │   ├── minitest-5.11.3
            │   ├── multi_json-1.13.1
            │   ├── nio4r-2.3.0
            │   ├── nokogiri-1.8.2
            │   ├── puma-3.11.3
            │   ├── rack-2.0.4
            │   ├── rack-test-1.0.0
            │   ├── rake-12.3.1
            │   ├── rb-fsevent-0.10.3
            │   ├── rb-inotify-0.9.10
            │   ├── sprockets-3.7.1
            │   ├── sqlite3-1.3.13
            │   ├── thor-0.20.0
            │   ├── thread_safe-0.3.6
            │   ├── tilt-2.0.8
            │   ├── turbolinks-5.1.0
            │   ├── turbolinks-source-5.1.0
            │   ├── tzinfo-1.2.5
            │   ├── uglifier-4.1.8
            │   ├── websocket-driver-0.6.5
            │   └── websocket-extensions-0.1.3
            └── specifications
                ├── activesupport-5.1.6.gemspec
                ├── arel-8.0.0.gemspec
                ├── builder-3.2.3.gemspec
                ├── coffee-script-2.4.1.gemspec
                ├── coffee-script-source-1.12.2.gemspec
                ├── concurrent-ruby-1.0.5.gemspec
                ├── crass-1.0.4.gemspec
                ├── erubi-1.7.1.gemspec
                ├── execjs-2.7.0.gemspec
                ├── ffi-1.9.23.gemspec
                ├── i18n-1.0.0.gemspec
                ├── mail-2.7.0.gemspec
                ├── method_source-0.9.0.gemspec
                ├── mini_mime-1.0.0.gemspec
                ├── mini_portile2-2.3.0.gemspec
                ├── minitest-5.11.3.gemspec
                ├── multi_json-1.13.1.gemspec
                ├── nio4r-2.3.0.gemspec
                ├── puma-3.11.3.gemspec
                ├── rack-2.0.4.gemspec
                ├── rack-test-1.0.0.gemspec
                ├── rake-12.3.1.gemspec
                ├── rb-fsevent-0.10.3.gemspec
                ├── rb-inotify-0.9.10.gemspec
                ├── sprockets-3.7.1.gemspec
                ├── sqlite3-1.3.13.gemspec
                ├── thor-0.20.0.gemspec
                ├── thread_safe-0.3.6.gemspec
                ├── tilt-2.0.8.gemspec
                ├── turbolinks-5.1.0.gemspec
                ├── turbolinks-source-5.1.0.gemspec
                ├── tzinfo-1.2.5.gemspec
                ├── uglifier-4.1.8.gemspec
                ├── websocket-driver-0.6.5.gemspec
                └── websocket-extensions-0.1.3.gemspec

 

http://localhost:3000/hello/index」アクセス時の挙動について

1. GET メソッドが発生する

 

2. Rails の Routes がイベントを受信する

  • Routes は helloworld/config/route.rb である。
└── helloworld
    ├── config
    │   ├── routes.rb        ★URL と Controller の紐付け

 

3. Rails の Controller が Route からのイベントを受け取る

  • Controller は helloworld/app/controllers/hello_controller.rb である。
└── helloworld
    ├── app
    │   ├── controllers          ★MVC の Controller
    │   │   ├── application_controller.rb
    │   │   ├── hello_controller.rb     ☆ hello/index 依存処理

 

4. Rails の View が Controller (を経由して Model )からのイベントを受け取る

  • View は helloworld/apps/views/hello/index.html.erb である。
└── helloworld
    ├── app
    │   └── views            ★MVC の View。ブラウザへの表示処理をする
    │       ├── hello
    │        |  └── index.html.erb      ☆hello/index 依存処理

 
 

Hello world! アプリの挙動制御

ブロック図

 
下のブロック図は「Railsの教科書」より転載させてもらいました。
 
f:id:dnkrnka:20180409225147p:plain
 

1. Route

  • 設定ファイルを直接見る方法と、ブラウザ上で確認する2通りがある。
設定 - ファイルベース - helloworld/config/route.rb

helloworld/config/route.rb

Rails.application.routes.draw do
  get 'hello/index'

  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

 

設定 - ブラウザベース - http://localhost:3000/rails/info/routes

http://localhost:3000/rails/info/routes
f:id:dnkrnka:20180409222003p:plain
 

Route のシーケンス
  • 1-1. http://localhost:3000/hello/index に対して GET メソッドが発生する
  • 1-2. Route は helloworld/config/route.rb を参照する
  • 1-3. 該当するメソッド=GETがあるか探す
  • 1-4. 「get 'hello/index'」より、該当するメソッドが見つかったので、 HelloController の index メソッドを呼び出す

 

2. Controller

  • Route から公開関数が呼び出されて処理を行う。
  • 本アプリの場合は app/controllers/hello_controller.rb にある HelloController クラスの index 関数である。
設定 - app/controllers/hello_controller.rb:HelloController#index
class HelloController < ApplicationController
  def index
    @time = Time.current.in_time_zone('Asia/Tokyo')
  end
end

 

Controller のシーケンス
  • 2-1. Route に登録しておいたコールバック関数=HelloController#index を呼び出してもらう
  • 2-2. HelloController#index にて所定の処理をする
    • このとき、View に渡す情報はインスタンス(=非ローカル変数)に格納しておくと良い。

 

3. View

  • Controller を経た後に呼び出される。ブラウザへ送信するデータを最終決定する処理部分。
  • 本アプリの場合の設定ファイル=テンプレートは、 helloworld/apps/views/hello/index.html.erb である。
    • テンプレートにて <%= %> という書式を使うことで Rails インスタンスにアクセスできる。
設定 - app/views/hello/index.html.erb
<p>Hello world!</p>
<p> 現 在 時 刻 : <%= @time %></p>

 

View のシーケンス
  • 3-1. Controller を経て Rails フレームワークからテンプレートが呼び出される
  • 3-2. Controller (などの前段) で得た情報を取り出す
  • 3-3. ブラウザに応答を返す

 

Route→ Controller→ View のシーケンス

上記の各モデルでのシーケンスをつなげると以下のようになる。

  • 1-1. http://localhost:3000/hello/index に対して GET メソッドが発生する
  • 1-2. Route は helloworld/config/route.rb を参照する
  • 1-3. 該当するメソッド=GETがあるか探す
  • 1-4. 「get 'hello/index'」より、該当するメソッドが見つかったので、 HelloController の index メソッドを呼び出す
  • 2-1. Route に登録しておいたコールバック関数=HelloController#index を呼び出してもらう
  • 2-2. HelloController#index にて所定の処理をする
    • このとき、View に渡す情報はインスタンス(=非ローカル変数)に格納しておくと良い。
  • 3-1. Controller を経て Rails フレームワークからテンプレートが呼び出される
  • 3-2. Controller (などの前段) で得た情報を取り出す
  • 3-3. ブラウザに応答を返す

*1:2018年4月時点で700円でした

*2:本書籍についてはアフィリエイトではございませんので、同リンクから購入いただいても私にはフィードバックはありませんので、ご安心ください