Ruby on Rails チュートリアル
-
第2版 目次
- 第1章ゼロからデプロイまで
- 第2章デモアプリケーション
- 第3章ほぼ静的なページの作成
- 第4章Rails風味のRuby
- 第5章レイアウトを作成する
- 第6章ユーザーのモデルを作成する
- 第7章ユーザー登録
- 第8章サインイン、サインアウト
- 第9章ユーザーの更新・表示・削除
- 第10章ユーザーのマイクロポスト
- 第11章ユーザーをフォローする
|
||
第2版 目次
|
||
最新版を読む |
Ruby on Rails チュートリアル
プロダクト開発の0→1を学ぼう
下記フォームからメールアドレスを入力していただくと、招待リンクが記載されたメールが届きます。リンクをクリックし、アカウントを有効化した時点から『30分間』解説動画のお試し視聴ができます。
メール内のリンクから視聴を開始できます。
第2版 目次
- 第1章ゼロからデプロイまで
- 第2章デモアプリケーション
- 第3章ほぼ静的なページの作成
- 第4章Rails風味のRuby
- 第5章レイアウトを作成する
- 第6章ユーザーのモデルを作成する
- 第7章ユーザー登録
- 第8章サインイン、サインアウト
- 第9章ユーザーの更新・表示・削除
- 第10章ユーザーのマイクロポスト
- 第11章ユーザーをフォローする
第2章デモアプリケーション
この章では、Railsの強力な機能をいくつか紹介するためのデモアプリケーションを作成します。scaffoldジェネレータというスクリプトを使ってアプリケーションをすばやく生成する事により、高度なRailsプログラミングとWebプログラミングの概要を学びます。コラム1.1で述べたように、本書の以後の章では基本的にこの逆のアプローチを取り、少しずつアプリケーションを作りながら各段階と概念を説明する予定ですが、scaffoldはRailsアプリケーションの概要を素早くつかむには最適なので、この章でのみあえて使用することにします。生成されたRailsアプリケーションはブラウザのアドレスバーにURLを入力すれば動かすことができるので、これによりRailsアプリの構造、そしてRailsで推奨されているRESTアーキテクチャに関する洞察を得ることにします。
デモアプリケーションは、後に作成するサンプルアプリケーションと同様、ユーザーと、それに関連しているマイクロポストから成り立っています。このデモアプリケーションはもちろん動きますが完成品ではなく、しかも多くの手順が「魔法」のように思えるかもしれません。第3章以降で作成するサンプルアプリケーションでは同等の機能を1つ1つ手動で作成しますので、ご安心ください。その分時間がかかることになりますが、どうか最後まで本書にお付き合いいただければと思います。本書の目的は、scaffoldを使用した即席のアプローチによる表面的な理解ではなく、そこを突破してRailsを深いレベルまで理解することにあります。
2.1 アプリの計画
はじめに、デモアプリケーションをどのようなものにするのか、計画を立てましょう。1.2.3と同じく、rails
コマンドでアプリケーションの骨格 (フォルダ構造、デフォルトで作成されるファイル類) を生成します。
$ cd rails_projects
$ rails new demo_app
$ cd demo_app
次に、Bundlerで使用するGemfile
をテキストエディタで編集します。リスト2.1の内容に書き換えてください。
Gemfile
。 source 'https://rubygems.org'
ruby '2.0.0'
#ruby-gemset=railstutorial_rails_4_0
gem 'rails', '4.0.5'
group :development do
gem 'sqlite3', '1.3.8'
end
gem 'sass-rails', '4.0.5'
gem 'uglifier', '2.1.1'
gem 'coffee-rails', '4.0.1'
gem 'jquery-rails', '3.0.4'
gem 'turbolinks', '1.1.1'
gem 'jbuilder', '1.0.2'
group :doc do
gem 'sdoc', '0.3.20', require: false
end
group :production do
gem 'pg', '0.15.1'
gem 'rails_12factor', '0.0.2'
end
1.4.1でも説明したとおり、--without productionオプションを追加することで、本番用のgemを除いたローカルgemをインストールします。
$ bundle install --without production
$ bundle update
$ bundle install
(第1章でも書きましたが、Bundlerでreadlineエラーが発生した場合は、Gemfile
にgem ’rb-readline’
を追加してください)。
最後に、このデモアプリケーションをバージョン管理下に置きます。既に説明したとおり、rails
コマンドを実行するとデフォルトの.gitignore
ファイルが生成されます。システム環境によっては、このファイルをリスト1.7のように変更しておくと便利なことがあります。Gitリポジトリを初期化して最初のコミットを実行しておきます。
$ git init
$ git add .
$ git commit -m "Initial commit"
必須ではありませんが、リポジトリを新規作成して (図2.1) GitHubにプッシュすることもできます。
$ git remote add origin https://github.com/<username>/demo_app.git
$ git push -u origin master
(最初のアプリケーションのときと同様、GitHubリポジトリを初期化するときにREADME
を使用しないように注意してください。)
これで、アプリ自体を作成するための下準備が整いました。Webアプリケーションを作る際、アプリケーションで使用される構造を表すためのデータモデルを最初に作成しておくのが普通です。今回のデモアプリケーションでは、ユーザーと短いマイクロポストのみをサポートするマイクロブログを作成します。そこで、まずアプリケーションのユーザーで使用するモデルを作成 (2.1.1) し、次にマイクロポストで使用するモデルを作成します (2.1.2)。
2.1.1ユーザーのモデル設計
Webでのユーザー登録の方法が多岐にわたることからもわかるように、ユーザーという概念をデータモデルで表す方法はたくさんありますが、ここではあえて最小限の構造に抑えておきます。各ユーザーには、重複のない一意のキーとなるinteger
型のID番号 (id
と呼びます) を割り当て、このIDに加えて一般公開されるstring
型の名前 (name
)、そして同じくstring
型のメールアドレス (email
) を持たせます。メールアドレスはユーザー名としても使われます。ユーザーのデータモデルの概要を図2.2に示します。
詳しくは6.1.1から解説しますが、図2.2のユーザー (users
) はデータベースのテーブル (table) に相当します。また、id
、name
、email
の属性はそれぞれテーブルのカラム (column: 列) に相当します。
2.1.2マイクロポストのモデル設計
マイクロポストのデータモデルはユーザー用のデータモデルよりもさらにシンプルです。id
と、マイクロポストのテキスト内容を格納するstring
型のcontent
だけで構成されています1。しかし実際には、マイクロポストをユーザーと関連付ける (associate) 必要があるため、ポストのオーナーを記録するためのuser_id
も追加します。これにより、データモデルは図2.3のようになります。
2.3.3では、user_id
という属性を使用して、1人のユーザーに複数のマイクロポストが関連付けられるという構造を簡潔に説明します。詳細は第10章で完全に説明します。
2.2Users リソース
ここでは、2.1.1で説明したユーザー用のデータモデルを、そのモデルを表示するためのWebインターフェイスに従って実装します。 このデータモデルとWebインターフェイスは、組み合わさってUsersリソースとなり、ユーザーというものを、HTTPプロトコル経由で自由に作成/読み出し/更新/削除できるオブジェクトとみなすことができるようになります。「はじめに」で約束したとおり、このUsersリソースはすべてのRailsプロジェクトに標準装備されているscaffoldジェネレータで生成します。scaffoldで生成された膨大なコードを今詳細に読む必要はありません。今の段階ではおそらく混乱するだけでしょう。
Railsのscaffoldは、rails generate
スクリプトにscaffold
コマンドを渡すことで生成されます。scaffold
コマンドの引数には、リソース名を単数形にしたもの (この場合はUser
) を使用し、必要に応じてデータモデルの属性をオプションとしてパラメータに追加します2。
$ rails generate scaffold User name:string email:string
invoke active_record
create db/migrate/20130305221714_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
invoke resource_route
route resources :users
invoke jbuilder_scaffold_controller
create app/controllers/users_controller.rb
invoke erb
create app/views/users
create app/views/users/index.html.erb
create app/views/users/edit.html.erb
create app/views/users/show.html.erb
create app/views/users/new.html.erb
create app/views/users/_form.html.erb
invoke test_unit
create test/controllers/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit
create test/helpers/users_helper_test.rb
invoke jbuilder
exist app/views/users
create app/views/users/index.json.jbuilder
create app/views/users/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/users.js.coffee
invoke scss
create app/assets/stylesheets/users.css.scss
invoke scss
create app/assets/stylesheets/scaffolds.css.scss
name:string
とemail:string
オプションを追加することで、Userモデルの内容が図2.2の表のとおりになるようにします (なお、id
パラメータはRailsによって自動的に主キーとしてデータベースに追加されるため、追加不要です)。
続いてデモアプリケーションの開発を進めるには、以下のようにRakeを使用してデータベースをマイグレート (migrate) する必要があります (コラム2.1)。
$ bundle exec rake db:migrate
== CreateUsers: migrating =================================
-- create_table(:users)
-> 0.0017s
== CreateUsers: migrated (0.0018s) ========================
このコマンドは、単にデータベースを更新し、users
データモデルを作成するためのものです (データベースのマイグレーションの詳細については 6.1.1以降で説明します)。なお、現在のGemfile
に対応するバージョンのRakeが確実に実行されるようにするために、bundle exec
を使用してrake
を実行します (1.2.2.3で勧めたとおりにRVMを使用している場合は、bundle exec
は省略することもできます。本書では、基本的に省略せずに書くことにします。bundle exec
を実行しなくて良いようにする他の方法については、3.6.1を参照してください)。
ここまで実行すれば、以下のようにrails s
コマンド (rails server
コマンドの短縮版) を実行してローカルWebサーバーを起動できるようになります。
$ rails s
これでhttp://localhost:3000/でデモアプリケーションをブラウザ表示できるようになっているはずです。
Unixでは、ソースコードから実行用プログラムをビルドするために主にmakeというツールが使われてきました。多くのプログラマーが、肉体レベルにまで刻み込まれた以下のようなコマンドを実行して
$ ./configure && make && sudo make install
LinuxやMac OS Xなどで日夜コードをコンパイルしています。
RakeはいわばRuby版のmakeであり、Rubyで記述することのできる、makeのような言語です。Railsでは、Rakeを頻繁に使用しています。特に、データベースを背後に持つWebアプリケーション開発時に必要となる管理タスクで顕著です。rake db:migrate
が一番よく使われるコマンドですが、rakeに-T db
オプションを付けて実行すると他にもさまざまなデータベースタスクが用意されているのがわかります。
$ bundle exec rake -T db
rakeで実行可能なタスクをすべて表示するには以下を実行します。
$ bundle exec rake -T
コマンドの多さに圧倒されがちですが、すべてのコマンドを今覚える必要はまったくありませんので、心配は無用です。Railsチュートリアルを最後まで読み終わる頃には、重要なコマンドは一通り使えるようになっていることでしょう。
2.2.1ユーザーページを表示する
http://localhost:3000/をブラウザで表示すると、デフォルトのRailsページが表示されます (図1.3)。実は、Usersリソースを作成した時に、これ以外のさまざまな「ユーザーを扱うためのページ」が既に作成されています。たとえば、/usersを表示すればすべてのユーザーの一覧が表示されますし、/users/newを表示すれば新規ユーザー作成ページが表示されます。この節では以後、ユーザーに関連するページについて手短に説明します。その際、表2.1に記載されている、ページとURLの関係を参照するとわかりやすいと思います。
URL | アクション | 用途 |
---|---|---|
/users | index | すべてのユーザーを一覧するページ |
/users/1 | show | id=1 のユーザーを表示するページ |
/users/new | new | 新規ユーザーを作成するページ |
/users/1/edit | edit | id=1 のユーザーを編集するページ |
まずはユーザーの一覧を表示するindexページから見てみましょう。もちろん、この時点ではまだユーザーは登録されていません (図2.4)。
ユーザーを新規作成するには、図2.5のnewページを表示します (注: ローカルのコンピュータで開発を行なっている場合は、URLのうちhttp://localhost:3000の部分は常に同じであるため、以後この部分は省略します)。 第7章では、このページをユーザー登録ページに転用します。
テキストフィールドに名前とメールアドレスを入力して [Create User] ボタンを押してください。ユーザーが作成され、図2.6のようにshowページが表示されます (緑色のウェルカムメッセージは、 7.4.2で解説するflashという機能を使用して表示しています)。ここで、URLが/users/1と表示されていることに注目してください。ご想像のとおり、この数字1
は図2.2のid
属性そのものです。7.1では、このページをユーザーのプロファイルに作り変える予定です。
今度は、ユーザー情報を変更するためにeditページを表示してみましょう (図2.7)。この編集ページ上でユーザーに関する情報を変更し、[Update User] ボタンを押せば、デモアプリケーション内のユーザー情報が変更されます (図2.8)。(詳細は第6章で説明しますが、このユーザー情報は、Webアプリケーションの背後にあるデータベースに保存されています。) このサンプルアプリケーションでも、ユーザーを編集または更新する機能を9.1で実装します。
ここでnewページに戻り、ユーザーをもう1人作成してみましょう。indexページを表示してみると、図2.9のようにユーザーが追加されています。7.1ではもっと本格的なユーザー一覧ページを作成する予定です。
ユーザーの作成、表示、編集方法について説明しましたので、今度はユーザーを削除してみましょう (図2.10)。 図2.10の [Destroy] リンクをクリックするとユーザーが削除され、indexページのユーザーは1人だけになります (もしこのとおりにならない場合は、ブラウザのJavaScriptが有効になっているかどうかを確認してください。Railsでは、ユーザーを削除するリクエストを発行するときにJavaScriptを使用しています)。なお、9.4ではサンプルアプリケーションにユーザーを削除する機能を実装し、管理権限 (admin) を持つユーザー以外は削除を実行できないように制限をかけます。
2.2.2 MVCの挙動
これでUsersリソースの概略についての説明が終わりましたが、ここで1.2.6で紹介した MVC (Model-View-Controller = モデル-ビュー-コントローラ) パターンの観点からこのリソースを考察してみましょう。具体的には、/usersのindexページをブラウザで開くという典型的な操作を行うときに何が起こっているかをMVC (図2.11) を使って説明します。
- ブラウザは/usersというURLへのリクエストを発行する。
- Railsは/usersをUsersコントローラ内の
index
アクションに割り当てる (ルーティング)。 index
アクションはUserモデルに「すべてのユーザーを取り出せ」と指示する (User.all
)。- Userモデルはすべてのユーザーをデータベースから取り出す。
- Userモデルはユーザーの一覧をコントローラに返す。
- コントローラはユーザーの一覧を
@users
変数に保存し、index
ビューに渡す。 - ビューは、その中に埋め込まれているRubyを使用してHTMLを生成する。
- コントローラは、生成されたHTMLをブラウザに返す3。
最初にブラウザからのリクエストを見てみましょう。このリクエストは、アドレスバーにURLを入力したりリンクをクリックした時に発生します (図2.11の1)。リクエストはRailsルーターに到達し (2)、ここでURL (とリクエストの種類: コラム3.3参照) に基づいて適切なコントローラのアクションに割り当てられます (ディスパッチ)。ユーザーのURLをUsersリソースで使用するコントローラアクションに割り当てる (マッピングする) ためのコードはリスト2.2です。このコードは、URLとアクションの組み合わせ (表2.1) を効率的に作成します。(:users
という一見奇妙な記法は、シンボルと呼ばれるものです。詳細については4.3.3で説明します。)
config/routes.rb
DemoApp::Application.routes.draw do
resources :users
.
.
.
end
2.2.1以降で紹介した各ページは、Usersコントローラの中にあるアクションにそれぞれ対応しています。1つのコントローラには関連する多数のアクションがまとめられています。リスト2.3は、scaffoldで生成したコントローラの骨格です。class UsersController < ApplicationController
という記法は、Rubyのクラスでの継承の使用例となっていることにも注目してください (継承の概略については2.3.4、詳細については4.4で説明します)。
app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def index
.
.
.
end
def show
.
.
.
end
def new
.
.
.
end
def create
.
.
.
end
def edit
.
.
.
end
def update
.
.
.
end
def destroy
.
.
.
end
end
ページの数よりもアクションの数の方が多いことにお気付きでしょうか。index
、show
、new
、edit
アクションはいずれも2.2.1のページに対応していますが、それ以外にもcreate
、update
、destroy
アクションがあります。通常、これらのアクションは、ページを出力せずにデータベース上のユーザー情報を操作します (もちろん、ページを出力しても良いのですが)。表2.2は、RailsにおけるRESTアーキテクチャ (コラム2.2) を構成するすべてのアクションの一覧です。RESTは、コンピュータ科学者Roy Fielding4によって提唱された「REpresentational State Transfer」という概念に基づいています。表2.2のURLには重複しているものがあることに注目してください。たとえば、show
アクションと update
アクションは、どちらも/users/1というURLに対応しています。これらのアクション同士の違いは、それらのアクションに対応するHTTP requestメソッドの違いでもあります。HTTP requestメソッドの詳細については3.2.1で説明します。
HTTPリクエスト | URL | アクション | 用途 |
---|---|---|---|
GET | /users | index | すべてのユーザーを表示するページ |
GET | /users/1 | show | id=1 のユーザーを表示するページ |
GET | /users/new | new | ユーザーを新規作成するページ |
POST | /users | create | ユーザーを作成するアクション |
GET | /users/1/edit | edit | id=1 のユーザーを編集するページ |
PATCH | /users/1 | update | id=1 のユーザーを更新するアクション |
DELETE | /users/1 | destroy | id=1 のユーザーを削除するアクション |
Rails関連の書籍を読んでいると “REST” という略語をよく見かけます。これはREpresentational State Transferの略です。RESTは、インターネットそのものやWebアプリケーションなどの、分散/ネットワーク化されたシステムやアプリケーションを構築するためのアーキテクチャのスタイルの1つです。REST理論そのものはかなり抽象的ですが、RailsアプリケーションにおけるRESTとは、アプリケーションを構成するコンポーネント (ユーザーやマイクロポストなど) を「リソース」としてモデル化することを指します。これらのリソースは、リレーショナルデータベースの作成/読み取り/更新/削除 (Create/Read/Update/Delete: CRUD) 操作と、4つの基本的なHTTP requestメソッド (POST/GET/PATCH/DELETE) の両方に対応しています (HTTP requestメソッドの詳細については、3.2.1、特にコラム3.3で説明します)。
Rails開発者にとっては、RESTfulなスタイルを採用することで、作成すべきコントローラやアクションの決定が楽になります。作成(C)・読み取り(R)・更新(U)・削除(D)を行うリソースだけでアプリケーション全体を構成してしまうことすら可能です。ユーザーやマイクロポストなどに関しては自然にリソース化できるので問題ありません。第11章では、「ユーザーをフォローする」というやや複雑な課題をREST理論でモデリングします。
UsersコントローラとUserモデルの関係をさらに考察するために、index
アクションを整理してみました (リスト2.4) (scaffoldで自動生成されるコードは冗長で紛らわしいので除いてあります)。
index
アクションを整理したもの。app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def index
@users = User.all
end
.
.
.
end
index
アクションに@users = User.all
という行があります (図2.11 の③に相当)。これによって、Userモデルからすべてのユーザーの一覧を取り出し (④)、@users
という変数に保存します (⑤)。なお、@usersは「あっと ゆーざーず」と発音します。Userモデルの内容はリスト2.5にあります。驚くほどシンプルな内容ですが、継承 (2.3.4および4.4) によって多くの機能が備わっています。特に、Active RecordというRubyライブラリのおかげで、リスト2.5のUserモデルはUser.all
というリクエストに対してすべてのユーザーを返すことができます。
app/models/user.rb
class User < ActiveRecord::Base
end
@users
変数にユーザー一覧が保存されると、コントローラはリスト2.6のビューを呼び出します (⑥)。@
記号で始まる変数はRubyではインスタンス変数と呼ばれます。ビューでは自動的にこれらのインスタンス変数を使用できます。この場合、リスト2.6のindex.html.erb
ビューは、@users
の一覧を並べ、1行ごとにHTMLの行として出力します (今はこのコードの意味がわからなくても問題ありません。これはあくまで説明のためのものです)。
app/views/users/index.html.erb
<h1>Listing users</h1>
<table>
<tr>
<th>Name</th>
<th>Email</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user, method: :delete,
data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New User', new_user_path %>
ビューはその内容をHTMLに変換し (⑦)、コントローラがブラウザにHTMLを送信して、ブラウザでHTMLが表示されます (⑧)。
2.2.3Users リソースの欠点
scaffoldで作成したUsersリソースは、Railsの概要を手っ取り早く説明するには良いのですが、以下のようなさまざまな問題点を抱えています。
- データの検証が行われていない。 このままでは、ユーザー名が空欄であったり、でたらめなメールアドレスを入力したりしても通ってしまいます。
- ユーザー認証が行われていない。 サインイン、サインアウトが行われていないので、誰でも無制限に操作できてしまいます。
- テストが行われていない。 厳密にはこれは正しい表現ではありません。というのも、scaffoldのコードには初歩的なテストが一応含まれているからです。ただ、scaffoldのテストコードは読みづらく、柔軟性もありません。さらにデータの検証、ユーザー認証、その他に必要な独自テストも含まれていません。
- レイアウトが整えられていない。 サイトデザインも操作法も一貫していません。
- 理解が困難。 scaffoldのコードを理解できるぐらいなら、そもそも本書を読む必要はないでしょう。
2.3Microposts リソース
Usersリソースを生成して内容を理解しましたので、今度はMicropostsリソースで同じことをやってみましょう。なお、この節全体について、Micropostsリソースを理解する際には2.2のuser要素と比較しながら進めることをお勧めします。実際、これらの2つのリソースはさまざまな面で似通っています。RailsのRESTful構造を身体に叩きこむには、繰り返し学ぶのが一番です。UsersリソースとMicropostsリソースの構造の類似点を理解することが、この章の主要な目的です (もちろん、この章のような初歩的なサンプルアプリケーションではない、頑丈なアプリケーションを開発するのは簡単ではありません。Micropostsリソースについては第10章で再び取り扱いますが、その頃にはMicropostsは作り込みが進んで外観がすっかり変わってしまいます)。
2.3.1マイクロポストのページを表示する
Usersリソースの場合と同様に、Micropostsリソースもscaffoldでコードを生成してみましょう。rails generate scaffold
コマンドを使用して、図2.3のデータモデルを実装してみます5。
$ rails generate scaffold Micropost content:string user_id:integer
invoke active_record
create db/migrate/20130307005528_create_microposts.rb
create app/models/micropost.rb
invoke test_unit
create test/models/micropost_test.rb
create test/fixtures/microposts.yml
invoke resource_route
route resources :microposts
invoke jbuilder_scaffold_controller
create app/controllers/microposts_controller.rb
invoke erb
create app/views/microposts
create app/views/microposts/index.html.erb
create app/views/microposts/edit.html.erb
create app/views/microposts/show.html.erb
create app/views/microposts/new.html.erb
create app/views/microposts/_form.html.erb
invoke test_unit
create test/controllers/microposts_controller_test.rb
invoke helper
create app/helpers/microposts_helper.rb
invoke test_unit
create test/helpers/microposts_helper_test.rb
invoke jbuilder
exist app/views/microposts
create app/views/microposts/index.json.jbuilder
create app/views/microposts/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/microposts.js.coffee
invoke scss
create app/assets/stylesheets/microposts.css.scss
invoke scss
identical app/assets/stylesheets/scaffolds.css.scss
新しいデータモデルでデータベースを更新するには、2.2のときと同様にマイグレーションを実行します。
$ bundle exec rake db:migrate
== CreateMicroposts: migrating =============================
-- create_table(:microposts)
-> 0.0023s
== CreateMicroposts: migrated (0.0026s) ======================
これでMicropostsを作成する準備ができました。作成方法は2.2.1と同じです。Railsのroutesファイルは期待どおりにscaffoldジェネレータによって更新され、リスト2.7のようにMicropostsリソース用のルールが追加されました6。ユーザーの場合と同様、resources :microposts
というルーティングルールは、表2.3に示したようにマイクロポスト用のURLをMicropostsコントローラ内のアクションに割り当てます。
config/routes.rb
DemoApp::Application.routes.draw do
resources :microposts
resources :users
.
.
.
end
HTTPリクエスト | URL | アクション | 用途 |
---|---|---|---|
GET | /microposts | index | すべてのマイクロポストを表示するページ |
GET | /microposts/1 | show | id=1 のマイクロポストを表示するページ |
GET | /microposts/new | new | マイクロポストを新規作成するページ |
POST | /microposts | create | マイクロポストを新規作成するアクション |
GET | /microposts/1/edit | edit | id=1 のマイクロポストを編集するページ |
PATCH | /microposts/1 | update | id=1 のマイクロポストを更新するアクション |
DELETE | /microposts/1 | destroy | id=1 のマイクロポストを削除するアクション |
Micropostsコントローラ自体の構造をリスト2.8に示します。リスト2.8の内容は、UsersController
がMicropostsController
に置き換わっているだけで、リスト2.3と完全に同一である点に注目してください。これは、RESTアーキテクチャが2つのリソースに同じように反映されていることを示しています。
app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
.
.
.
def index
.
.
.
end
def show
.
.
.
end
def new
.
.
.
end
def create
.
.
.
end
def edit
.
.
.
end
def update
.
.
.
end
def destroy
.
.
.
end
end
/microposts/newページをブラウザで開き、新しいマイクロポストの情報を入力してマイクロポストをいくつか作成してみましょう (図2.12)。
ここではひとまずマイクロポストを1つか2つ作成し、少なくとも片方のuser_id
が1
になるようにして、2.2.1で作成した最初のユーザーのidと同じにします。結果は図2.13のようになるはずです。
2.3.2マイクロポストをマイクロにする
マイクロポストのマイクロという名前にふさわしく、何らかの方法で文字数制限を与えてみましょう。Railsでは、検証 (validates) を使用して簡単にこのような入力制限を追加することができます。Twitterのように140文字の制限を与えるには、lengthを指定します。テキストエディタかIDEを使用してapp/models/micropost.rb
を開き、 リスト2.9の内容に置き換えます。(注: リスト2.9のようなvalidates
はRails 3の機能です。Rails 2.3の場合は validates_length_of
を使用します。)
app/models/micropost.rb
class Micropost < ActiveRecord::Base
validates :content, length: { maximum: 140 }
end
リスト2.9のコードは、これで本当に動作するのかと思えるかもしれませんが、ちゃんと動作します (検証機能については6.2でさらに詳しく説明します)。141文字以上の新規マイクロポストを投稿してみればわかります。図2.14に示したとおり、マイクロポストの内容が長すぎるというエラーメッセージがRailsによって表示されます (エラーメッセージの詳細については7.3.3で説明します)。
2.3.3ユーザーとマイクロポストをhas_manyで関連づける
異なるデータモデル同士の関連付けは、Railsの強力な機能です。ここでは、1人のユーザーに対し複数のマイクロポストがあるとしましょう。UserモデルとMicropostモデルをそれぞれリスト2.10とリスト2.11のように更新することでこの関連付けを表現できます。
app/models/user.rb
class User < ActiveRecord::Base
has_many :microposts
end
app/models/micropost.rb
class Micropost < ActiveRecord::Base
belongs_to :user
validates :content, length: { maximum: 140 }
end
この関連付けを図で表したものが図2.15です。microposts
テーブルにはuser_id
カラムを作成してあったので、それによってRailsとActive Recordがマイクロポストとユーザーを関連付けることができるようになっています。
第10章と第11章では、関連付けられたユーザーとマイクロポストを同時に表示し、Twitterのようなマイクロポストのフィードを作成する予定です。ここでは、Railsのconsoleを使用して、ユーザーとマイクロポストの関連付けを確認するにとどめます。Railsのconsoleは、Railsアプリケーションを対話的に操作することができる便利なツールです。まず、ターミナルでrails console
コマンドを入力します。続いて、User.first
を使用してデータベースから1人目のユーザーの情報を取り出し、first_user
変数に保存します7。
$ rails console
>> first_user = User.first
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
created_at: "2013-03-06 02:01:31", updated_at: "2013-03-06 02:01:31">
>> first_user.microposts
=> [#<Micropost id: 1, content: "First micropost!", user_id: 1,
created_at: "2011-11-03 02:37:37", updated_at: "2011-11-03 02:37:37">,
"2013-03-06 02:37:37", updated_at: "2013-03-06 02:37:37">,
#<Micropost id: 2,content: "Second micropost", user_id: 1,
created_at: "2013-03-06 02:38:54",updated_at: "2013-03-06 02:38:54">]
>> exit
(最後の行のようにexitを実行するとrails consoleを終了できます。多くのシステムでは、Ctrl-dキーを押して終了することもできます。) first_user.microposts
というコードを実行すると、そのユーザーに関連付けられているマイクロポストにアクセスできます。このときActive Recordは、user_id
がfirst_user
のid (ここでは1
) と等しいマイクロポストを自動的に返します。Active Recordの関連付け機能については第10章と第11章でさらに詳しく解説します。
2.3.4継承の階層
最後に、デモアプリケーションで使用しているRailsのコントローラとモデルのクラス階層について簡単に解説します。この節を理解するには、多少なりともオブジェクト指向プログラミング (OOP) の経験が必要です。オブジェクト指向プログラミングを学んだことのない方はこの節をスキップしても構いません。特に、クラスの概念 (4.4で解説します) に慣れていない方は、後でこの節をもう一度読み返してください。
最初に、モデルの継承構造について説明します。リスト2.12とリスト2.13を比較してみると、UserモデルとMicropostモデルはいずれもActiveRecord::Base
というクラスを継承しています (継承関係は<
記号で表現されています)。このクラスは、ActiveRecordが提供するベースクラスであり、クラス間のリレーションは図2.16のようになります。ActiveRecord::Base
クラスを継承したことによって、作成したモデルオブジェクトはデータベースにアクセスできるようになり、データベースのカラムをあたかもRubyの属性のように扱えるようになります。
User
クラスにおける継承。app/models/user.rb
class User < ActiveRecord::Base
.
.
.
end
Micropost
クラスにおける継承。app/models/micropost.rb
class Micropost < ActiveRecord::Base
.
.
.
end
コントローラの継承構造はもう少しだけ複雑です。リスト2.14とリスト2.15を比較してみると、UsersコントローラとMicropostsコントローラはいずれもApplicationControllerを継承しています。リスト2.16を見ると、ApplicationController
自身はActionController::Base
を継承しています。これはRailsのAction Packというライブラリが提供している、コントローラ用のベースクラスです。これらのクラス同士の関係を図2.17に示します。
UsersController
クラスにおける継承。app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
end
MicropostsController
クラスにおける継承。app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
.
.
.
end
ApplicationController
クラスにおける継承。app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
.
.
.
end
モデルの継承関係と同様に、UsersコントローラもMicropostsコントローラも最終的にはActionController::Base
を継承しており、モデルオブジェクトの操作、インバウンドHTTP requestのフィルタ、ビューをHTMLとして出力するなどの多彩な機能を実行できるようになっています。Railsのコントローラは必ずApplicationController
を継承しているので、Applicationコントローラで定義されたルールは自動的にアプリケーションのすべてのアクションに反映されます。たとえば8.2.1では、サンプルアプリケーションのすべてのコントローラにサインインとサインアウト用のヘルパーを含めています。
2.3.5デモアプリケーションのデプロイ
Micropostsリソースの説明が終わりましたので、ここでリポジトリをGitHubに登録しましょう。
$ git add .
$ git commit -m "Finish demo app"
$ git push
通常は、更新をあまりためないように、Gitのコミットをなるべく頻繁に行うことが望ましいのですが、この章の締めくくりとしてサイズの大きなコミットを1度だけ行っても問題ありません。
この時点で、デモアプリケーションを1.4のようにHerokuにデプロイしてもかまいません。
$ heroku create
$ git push heroku master
アプリケーションのデータベースが動作するようにするには、以下を実行して本番データベースのマイグレーションを行う必要もあります。
$ heroku run rake db:migrate
このコマンドを実行すると、Heroku上のデータベースが、ユーザーとマイクロポストのデータモデルで更新されます。
2.4最後に
ついにRailsアプリケーションを最後まで完成させました。この章で作成したデモアプリケーションには良いところもありますが、さまざまな弱点もあります。
良い点
- Rails全体を高度なレベルで概観できた
- MVCモデルを紹介できた
- RESTアーキテクチャに初めて触れた
- データモデルの作成を初めて行った
- データベースを背後に持つWebアプリケーションを本番環境で動かした
課題
- レイアウトやスタイルが皆無
- “Home” や “About” のような静的なページがない
- ユーザーにパスワードを設定できない
- ユーザーの画像も置けない
- サインインできない
- セキュリティがない
- ユーザーとマイクロポストを自動的に関連付けていない
- “following” 機能も “followed” 機能もない
- マイクロポストをフィードできない
- テスト駆動開発が行われていない
- 理解が困難
本書では以後、良い点を保ちつつこれらの弱点を克服していきます。
- もっと多い文字数の投稿できるモデルにしたい場合は (たとえば、マイクロポストではなく、ブログのような投稿を許可したい場合は)、
string
の代わりにtext
を使うとよいでしょう。↑ - scaffoldにおける命名は、モデル名の命名の習慣に従っています。リソースやコントローラは複数形で表し、モデルは単数形で表すのが普通です。
Users
ではなくUser
としたのはこのためです。↑ - ビューは、(ApacheやNginxなどのWebサーバーを経由してはいるが) ブラウザにHTMLを直接返すと説明している文献もあります。私は、Railsの実際の実装とは無関係に、コントローラを情報の流れの中心となるハブとみなすことを好んでいます。↑
- Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000. ↑
- ユーザーでscaffoldを実行した場合と同様に、scaffoldジェネレータはマイクロポストでもRailsモデルを単数形とする習慣に従います。実行したコマンドが
generate Micropost
と単数形になっていたのはこのためです。↑ - scaffoldで生成したコードにはリスト2.7よりも多くの改行が追加されます。Rubyは単なる改行を無視するので、問題はありません。↑
- 実際のターミナル上では、プロンプトが
ruby-2.0.0-head >
などと表示される可能性がありますが、Rubyのバージョンが環境によって異なる可能性があるため、例のプロンプトは>>と表記しています。↑
Railsチュートリアルは YassLab 社によって運営されています。
コンテンツを継続的に提供するため、書籍・動画・質問対応サービスなどもご検討していただけると嬉しいです。
研修支援や教材連携にも対応しています。note マガジンや YouTube チャンネルも始めたので、よければぜひ遊びに来てください!