概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: The Ultimate Intermediate Ruby on Rails Tutorial: Let’s Create an Entire App!
- 原文公開日: 2017/12/17
- 著者: Domantas G
Rails5中級チュートリアルはセットアップが短めで、RDBMSにはPostgreSQL、テストにはRSpecを用います。
原文が非常に長いので分割します。章ごとのリンクは順次追加します。
注意: Rails中級チュートリアルは、Ruby on Railsチュートリアル(https://railstutorial.jp/)(Railsチュートリアル)とは著者も対象読者も異なります。
目次
- 1. 序章とセットアップ
- 2. レイアウト(本章)
- 3. 投稿
- 3-1 認証
- 3-2 ヘルパー
- 3-3 テスト
- 3-4 メインフィード
- 3-5 単一の投稿
- 3-6 特定のブランチ
- 3-7 Service Object
- 3-8 新しい投稿を作成する
- 4. インスタントメッセージ
- 4-1 非公開チャット
- 4-2 連絡先
- 4-3 グループチャット
- 4-4 メッセンジャー
- 5. 通知
- 5-1 つながりリクエスト
- 5-2 チャット
Rails5「中級」チュートリアル(2)レイアウト(翻訳)
それではコーディングを始めます。どこから始めてもよいのですが、私はWebサイトを新しく作るときは基本的な表示構造を最初に作ってから他のものを作るのが好みなので、この方法で進めることにしましょう。
2-1 Homeページ
今はhttp://localhost:3000を開くとRailsのwelcomeページが表示されるので、これを独自のデフォルトページに変えることにします。そのためには、Pages
コントローラを生成します。Railsのコントローラに慣れていない方は、Action Controllerを読んでRailsのコントローラの概要を理解しておいてください。コマンドプロンプトで以下を実行して、新しいコントローラを生成します。
rails g controller pages
このRailsジェネレータによっていくつかのファイルが作成されます。コマンドプロンプトの出力は以下のような感じになります。
このPagesController
を使って、特殊な静的ページを制御します。テキストエディタでCollabfieldプロジェクトを開きましょう。私はSublime Textを使っていますが、お好みのエディタで構いません。
pages_controller.rb
ファイルを開きます。
app/controllers/pages_controller.rb
homeページの定義はここで行います。もちろん、homeページを別の方法で他のコントローラに定義することも可能ですが、私はhomeページをPagesController
の内部で定義するのが好みです。
pages_controller.rb
を開くと以下のようになっています(Gist)。
# app/controllers/pages_controller.rb
class PagesController < ApplicationController
end
これはPagesController
という名前の空のクラスになっており、ApplicationController
クラスを継承しています。ApplicationController
のソースコードはapp/controllers/application_controller.rb
にあります。
私たちが今後作成するコントローラは、すべてApplicationController
クラスから継承します。つまり、ApplicationController
クラスで定義したメソッドはすべてのコントローラで利用できるようになります。
index
という名前のpublicメソッドを定義しましょう。これはアクションとして呼び出せます(Gist)。
# controllers/pages_controller.rb
class PagesController < ApplicationController
def index
end
end
Action Controllerの概要をお読みになった方ならおわかりのように、呼び出されるコントローラとそのpublicメソッド(アクション)は「ルーティング」によって決定されます。それではルーティングを定義して、Webサイトのrootページを開いたときに呼び出されるコントローラとアクションをRailsに認識させてみましょう。app/config/routes.rb
ファイルを開きます。
Railsのルーティングがわからない方は、この機会にガイドのRailsのルーティングをじっくり読んでルーティングに慣れておきましょう。
ルーティングに以下のコードを追加します。
root to: 'pages#index'
追加後のroutes.rb
は以下のようになります(Gist)。
# app/config/routes.rb
Rails.application.routes.draw do
root to: 'pages#index'
end
Rubyのハッシュシンボル#
はメソッドを文章の中で表記するときに使います。アクションは単なるpublicメソッドなので、pages#index
は「PagesController
のpublicメソッド(アクション)であるindex
を呼び出す」という意味です。
rootパスhttp://localhost:3000を開くと、このindex
アクションが呼び出されます。しかしレンダリングするテンプレートが未定義のままなので、index
アクションに対応するテンプレートを新しく作ってみましょう。app/views/pages
ディレクトリに移動してindex.html.erb
ファイルを開きます。このファイルには、通常のHTMLの他にERB(Embedded Ruby)コードを書けます。このファイルに以下のように書けば、テンプレートがブラウザに表示されるようになります。
<h1>Home page</h1>
http://localhost:3000を開くと、デフォルトのRails情報ページの代わりに以下のような感じで表示されるはずです。
これでやっと基本的な出発点にたどり着きました。ここからWebサイトに新しい要素を導入していきます。このあたりでgitの最初のcommitを行うのがよいでしょう。
コマンドプロンプトで以下を実行します。
git status
以下のような結果が出力されます。
参考までに、新しいRailsアプリを生成すると、新しいローカルgitリポジトリも初期化されます。
以下を実行して、現在の変更内容をすべて追加します。
git add -A
続いて以下を実行し、変更内容をすべてcommitします。
git commit -m "Generate PagesController. Initialize Home page"
試しに以下を実行してみましょう。
git status
変更点がすべてcommitされたので、「nothing to commit」と表示されます。
2-2 Bootstrap
ナビゲーションバーやレスポンシブなグリッドシステムを使えるよう、Bootstrapライブラリを使うことにします。Bootstrapを使うには、エディタでGemfileにbootstrap-sass gemを追加する必要があります。エディタでGemfile
を開きます。
collabfield/Gemfile
bootstrap-sass
gemをGemfileに追加します。ドキュメントにも書かれているように、sass-rails
gemが存在していることも確認する必要があります。
...
gem 'bootstrap-sass', '~> 3.3.6'
gem 'sass-rails', '>= 3.2'
...
ファイルを保存して以下を実行し、追加したgemをインストールします。
bundle install
アプリを実行中の場合は、Railsサーバーを再起動して新しいgemを利用できるようにします。サーバーを再起動するには、Ctrl + C
でサーバーを停止し、rails s
コマンドを再度実行してサーバーを起動するだけで完了します。
assets
ディレクトリに移動してapplication.css
ファイルを開きます。
app/assets/stylesheets/application.css
コメントアウトされている行の下に以下を追加します。
...
@import "bootstrap-sprockets";
@import "bootstrap";
続いてapplication.css
をapplication.scss
にリネームします。この変更はRailsでBootstrapライブラリを用いるのに必要です。また、これによってSassの機能を使えるようになります。
今後Sass変数を作成する場合に備えて、すべての.scss
ファイルがレンダリングされるよう順序を変更する必要があります。Sass変数が使われる前に定義されるよう、順序を変更したいと思います。
これを行うには、application.scss
ファイルの以下の2行を削除します。
*= require_self
*= require_tree .
Bootstrapライブラリが使えるようになるまであと少しです。もうひとつやっておかなければならないことがあります。bootstrap-sassドキュメントに記載されているとおり、BootstrapのJavaScriptはjQueryライブラリに依存しています。RailsでjQueryを使えるようにするには、jquery-rails gemを追加する必要があります。
訳注: Rails 5.1以降でjQueryを使う場合、gemよりもWebpackとyarnでインストールする方法が標準になりつつあります。この時点でWebpackとyarnでjQueryをインストールする場合、
gem 'jquery-rails'
の代わりに以下の方法が使えます。
1. Gemfileにgem 'webpacker', github: 'rails/webpacker'
を追加し、bundle install
を実行する
2.rails webpacker:install
を実行し、Webpackerをインストールする
3.yarn install jquery
を実行し、jQueryをインストールする
サーバー再起動後の手順は同じです。
gem 'jquery-rails'
以下を実行します。
bundle install
再度サーバーを再起動します。
最後は、アプリのJavaScriptファイルでBootstrapとjQueryをrequireする手順です。application.js
ファイルを開きます。
app/assets/javascripts/application.js
以下の行を追加します(訳注: require_tree .
の前の行に追加します)。
//= require jquery
//= require bootstrap-sprockets
変更をgitにcommitします。
git add -A
git commit -m "Add and configure bootstrap gem"
2-3 ナビゲーションバー
ナビゲーションバーは、Bootstrapのnavbarコンポーネントを元に今後いろいろ変更を加えます。ナビゲーションバーはパーシャルテンプレートに保存します。
この時点でこれを行う理由は、アプリのあらゆるコンポーネントを別ファイルに分割するのが望ましいためです。コンポーネントを分割することで、アプリのコードのテストや管理がずっとやりやすくなりますし、コードを複製せずにコンポーネントをアプリの別の箇所で再利用することもできます。
以下のディレクトリに移動します。
views/layouts
以下のファイルを作成します。
_navigation.html.erb
パーシャルファイルの先頭にはアンダースコア_
を付け、Railsフレームワークがこのファイルをパーシャルとして認識できるようにします。これを行うには、Bootstrapドキュメントのnavbarコンポーネントのコードをこのファイルにコピペして保存します。このパーシャルをWebサイトで表示するには、コードのどこかでレンダリングする必要があります。views/layouts/application.html.erb
ファイルを開きます。このファイルの内容は、デフォルトで常にレンダリングされます。
application.html.erb
ファイルには以下のメソッドがあります。
<%= yield %>
リクエストされたテンプレートはここでレンダリングされます。HTMLファイル内でRuby構文を使うには、<% %>
(ERBの書式)で囲む必要があります。ERB構文の違いについて手っ取り早く知りたい方は、StackOverflowの回答をご覧ください。
2-1 Homeページセクションでは、ルーティングを設定することでroot URLが認識されるようにしました。これにより、GET
リクエストを送信してrootページに移動すると、常にPagesController#index
アクションが呼び出されます。ルーティングに対応するアクション(ここではindex
)は、yield
メソッドでレンダリングされるテンプレートを用いてレスポンスを返します。homeページのテンプレートがapp/views/pages/index.html.erb
にあることを思い出しましょう。
ナビゲーションバーはすべてのページに表示したいので、ナビゲーションファイルのレンダリングはデフォルトのapplication.html.erb
ファイル内で行います。パーシャルファイルをレンダリングするには、パーシャルへのパスを引数に与えてrender
メソッドを呼び出します。以下のようにyield
メソッドの上にrender
を追加します。
...
<%= render 'layouts/navigation' %>
<%= yield %>
...
これで、http://localhost:3000をブラウザで開くと以下のようにナビゲーションバーが表示されます。
予告のとおり、このナビゲーションバーに変更を加えることにします。最初に、<li>
要素と<form>
要素をすべて削除します。今後ここには独自の要素を作成します。変更後の_navigation.html.erb
ファイルは次のようになります。
<!-- views/layouts/_navigation.html.erb -->
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- ブランド表示と、モバイル表示切り替え用のグループ化 -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- ナビゲーションリンク/フォームなどのコンテンツをここにまとめて表示をオンオフできるようにする -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
</ul>
<ul class="nav navbar-nav navbar-right">
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
これでレスポンシブなナビゲーションバーの基本部分ができました。ここでgitに新しくcommitするのがよいでしょう。コマンドプロンプトで以下を実行します。
git add -A
git commit -m "Add a basic navigation bar"
今度はナビゲーションバーの名前をBrand
からcollabfield
に変更します。Brand
はlink要素なので、リンクの生成には[link_to](https://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to)
メソッドを使うべきです。その理由は、link_to
メソッドを使う方がURIパスを簡単に生成できるからです。コマンドプロンプトでプロジェクトディレクトリに移動し、以下のコマンドを実行します。
rails routes
このコマンドは、routes.rb
ファイルで生成される利用可能なルーティングを表示します。以下が出力されます。
この時点のルーティングは先ほど定義した1つだけです。出力結果にPrefix
カラムがあることにご注目ください。このprefixを使って、表示したいページへのパスを生成できます。パスの生成は、このprefix名の後ろに_path
を追加するだけでできます。たとえばroot_path
と書けば、rootページへのパスが生成されます。それでは、このlink_to
メソッドとルーティングの力を借りてやってみましょう。
<a class="navbar-brand" href="#">Brand</a>
上のコードを以下に置き換えます。
<%= link_to 'collabfield', root_path, class: 'navbar-brand' %>
メソッドの使い方がよくわからなくても、適当にググればたいてい解説ドキュメントを見つけられることを覚えておきましょう。たまにハズレのドキュメントもあるので、その場合はもう少し丁寧にキーワードを指定してググれば、有用なブログ記事やStackOverflowの回答が見つかることもあります。
第1引数で渡す文字列は、<a>
要素の値を追加します。第2引数はパスの指定に必要で、ここでパスを生成するのにルーティングが役立ちます。第3引数はオプションで、ここで渡したものはhtml_options
ハッシュに組み込まれます。ここでは、ナビゲーションバーにBootstrapを効かせたいので、navbar-brand
クラスの追加が必要です。
ただいまの小さな変更をgitにcommitしましょう。この後のセクションでアプリのデザインに手を加える予定ですが、このナビゲーションバーから変更を開始します。
git add -A
git commit -m "Change navigation bar's brand name from Brand to collabfield"
2-4 スタイルシート
スタイルシートファイルの構成方法をご紹介します。Railsには、スタイルシートの構成方法についての厳密な規則はなく、人それぞれ少しずつ違っています。
ここでは、私が普段用いている構成方法をご紹介します。
base
ディレクトリ: アプリ全体で使われるSass変数やスタイルはここに置いています(デフォルトのフォントサイズやデフォルト要素のスタイルなど)。partials
ディレクトリ: ほとんどのスタイルはここに置いています。このディレクトリでは、コンポーネントやページごとにスタイルを分割するようにしています。responsive
ディレクトリ: ここでは、異なる画面サイズごとに、異なるスタイルルールを定義しています(デスクトップ画面のスタイル、タブレット画面のスタイル、スマートフォン画面のスタイルなど)。
最初に、以下を実行してgitリポジトリで新しいブランチを切ります。
git checkout -b "styles"
これにより、新しいgit branch
が作成され、自動的にそのブランチに切り替わります。今後、新たなコード変更を別ブランチ上で実装する場合はこのようにします。
別ブランチを切る理由は、現在動作しているバージョン(master
ブランチ)から、プロジェクトに追加する新しいコードを切り離し、変更によってmaster
ブランチに悪影響が生じることのないようにするためです。
実装が終わったら、変更をmaster
ブランチにmergeできます。
最初にディレクトリをいくつか作成します。
- app/assets/stylesheets/partials/layout
このlayout
ディレクトリでnavigation.scss
というファイルを作成し、以下のコードを追加します(Gist)。
//app/assets/stylesheets/partials/layout/navigation.scss
.navbar-default, .navbar-toggle:focus, .collapsed, button.navbar-toggle {
background: $navbarColor !important;
border: none;
a {
color: white !important;
}
}
上のScssコードでは、navbarの背景色とリンクの色を変更しています。既にお気づきのように、a
セレクタが別の宣言ブロックの内部でネストしていますが、これはSassの機能です。!important
は、デフォルトのBootstrapスタイルを強制的にオーバーライドするのに使います。最後に、この部分では色名の代わりにSass変数が使われていることにお気づきかと思います。Sass変数を使う理由は、アプリ全体で色を変更できるようにするためです。このSass変数を定義しましょう。
最初に以下のディレクトリを作成します。
app/assets/stylesheets/base
base
ディレクトリの下にvariables.scss
ファイルを作成し、以下を定義します。
$navbarColor: #323738;
試しにこの時点でhttp://localhost:3000をブラウザで開いてみると、スタイルはまだ何も変更されていません。スタイルが反映されない理由は、2-2 Bootstrapセクションでapplication.scss
ファイルから以下を削除したためです。
*= require_self
*= require_tree .
上を削除したのは、すべてのスタイルが自動的にimportされることのないようにするためでした。
つまり、スタイルシートのファイルを新しく作成するときは、メインのapplication.scss
ファイルで(明示的に)importしなければならないということです。importを追加したapplication.scss
ファイルは次のようになります(Gist)。
//app/assets/stylesheets/application.scss
// ...デフォルトのコメント
// Bootstrap
@import "bootstrap-sprockets";
@import "bootstrap";
// Variables
@import "base/variables";
// Partials - メインのcssファイル
@import "partials/layout/*";
variables.scss
をpartialよりも先にimportする理由は、partialで使われるSass変数より先にSass変数が定義されるようにするためです。
navigation.scss
ファイルのコードの冒頭に、さらに以下のCSSを追加します。
//app/assets/stylesheets/partials/layout/navigation.scss
nav {
.navbar-header {
width: 100%;
button, .navbar-brand {
transition: opacity 0.15s;
}
button {
margin-right: 0;
}
button:hover, .navbar-brand:hover {
opacity: 0.8;
}
}
}
好みに応じて、上のコードを冒頭に追加する代わりに末尾に追加しても構いません。個人的には、CSSセレクタの「詳細度」の順でCSSコードを配置およびグループ化するようにしています。繰り返しますが、CSSファイルの構成方法は人それぞれ少しずつ違っています。私の場合、詳細度の小さい(大雑把な)セレクタを上に、詳細度の大きいセレクタを下に置くようにしています。たとえば、要素型セレクタはクラスセレクタより上になり、クラスセレクタはIDセレクタより上になるといった具合です。
ここで変更をgitにcommitしましょう。
git add -A
git commit -m "Add CSS to the navigation bar"
今度は、画面を下にスクロールしてもナビゲーションバーが常に最上部に表示されるようにしたいと思います。現時点でスクロールするほどのコンテンツがありませんが、コンテンツは今後増えます。この段階でナビゲーションバーを固定しておくのがよいとは思いませんか?
これを行うには、Bootstrapのnavbar-fixed-top
クラスを使います。次のように、nav
要素にこのクラスを追加します。
<!-- views/layouts/_navigation.html.erb -->
<nav class="navbar navbar-default navbar-fixed-top">
ついでに、Bootstrap Grid Systemの左側の境界にcollabfield
を配置したいと思います。現在のクラスがcontainer-fluid
になっているので、現時点のcollabfield
はviewportの左側境界に配置されています。これを変更するには、(2行目の)このクラスをcontainer
に変更します。
変更後の_navigation.html.erb
ファイルは次のようになります。
<!-- views/layouts/_navigation.html.erb -->
<div class="container">
変更をcommitします。
git add -A
git commit -m "
- in _navigation.html.erb add navbar-fixed-top class to nav.
- Replace container-fluid class with container"
http://localhost:3000をブラウザで開くと、Home page
というテキストがナビゲーションバーの下に隠れてしまいました。これはnavbar-fixed-top
クラスのせいです。この問題を解決するには、navigation.scss
に以下を追加して<body>
要素を下に下げます。
//app/assets/stylesheets/partials/layout/navigation.scss
body {
margin-top: 50px;
}
これで、アプリは以下のように正常に表示されるはずです。
変更をcommitします。
git add -A
git commit -m "Add margin-top 50px to the body"
先ほど、新しいブランチを切ってそこに切り替えて作業していたのを思い出しましょう。ここでmaster
ブランチに戻ることにします。
以下のコマンドを実行します。
git branch
以下のようにブランチのリストが表示されています。現在のブランチはstyles
になっています。
master
ブランチに切り替えるには、以下を実行します。
git checkout master
以下を実行すれば、styles
ブランチで行った変更をすべてmergeできます。
git merge styles
このコマンドによって、2つのブランチがmergeされ、変更の概要が以下のように表示されます。
style
ブランチが不要になったので、以下を実行して削除します。
git branch -D styles