このガイドでは、Ruby on Rails (以下 Rails) を初めて設定して実行するまでを解説します。
このガイドの内容:
本ガイドは、ゼロからRailsアプリケーションを構築したいと考えている初心者を対象にしています。読者がRailsの経験がないことを前提としています。ただし、このドキュメントを最大限に活用するために、以下のソフトウェアがインストールされ、利用可能な状態になっていることを前提としています。
Railsとは、Rubyプログラミング言語の上で動作するWebアプリケーションフレームワークです。 Rubyの経験がまったくない場合、Railsを学ぶのはかなり大変な作業になるでしょう。Rubyを学ぶための精選されたオンラインリソース一覧はたくさんありますので、その中から以下をご紹介します。
これらはいずれもよくできていますが、中にはRubyのバージョンが1.6など古いものもありますのでご注意ください。また、バージョン1.8を対象にしているものが多く、Railsでの日常的な開発に使用されている新しい文法が含まれていないこともあります。
Railsとは、Rubyプログラミング言語で書かれたWebアプリケーションフレームワークです。 Railsは、あらゆる開発者がWebアプリケーションの開発を始めるうえで必要となる作業やリソースを事前に仮定して準備しておくことで、Webアプリケーションをより簡単にプログラミングできるように設計されています。他の多くの言語によるWebアプリケーションフレームワークと比較して、アプリケーションを作成する際のコード量がより少なくて済むにもかかわらず、より多くの機能を実現できます。 Rails経験の長い多くの開発者から、おかげでWebアプリケーションの開発がとても楽しくなったという意見をいただいています。
Railsは、最善の開発方法というものを1つに定めるという、ある意味大胆な判断に基いて設計されています。Railsは、何かをなすうえで最善の方法というものが1つだけあると仮定し、それに沿った開発を全面的に支援します。言い換えれば、ここで仮定されている理想の開発手法に沿わない別の開発手法は行いにくくなるようにしています。この「The Rails Way」、「Rails流」とでもいうべき手法を学んだ人は、開発の生産性が著しく向上することに気付くでしょう。従って、Rails開発において別の言語環境での従来の開発手法に固執し、他所で学んだパターンを強引に適用しようとすると、せっかくの開発が楽しくなくなってしまうでしょう。
Railsの哲学には、以下の2つの主要な基本理念があります。
本ガイドを活用するための最善の方法は、以下の手順を文字どおり1つずつ実行し、手順を取りこぼさないようにすることです。取りこぼしがあると、その後の手順が期待どおりに進まない可能性があります。この手順で作成された完全なRailsプロジェクトのコードはコチラで公開されているので、躓いてしまったときなどに参照してください。また、完成したサンプルアプリケーションはコチラで公開されています。
本ガイドの手順に従うことで、blogという名前の非常にシンプルなブログのRailsプロジェクトを作成できます。Railsアプリケーションを構築する前に、Rails本体がインストールされていることを確認してください。
以下の例では、Unix系OSのプロンプトとして$記号を使用していますが、これはカスタマイズ可能であり、自分の環境では異なる記号になっていることもあります。Windowsではc:\source_code>のように表示されます。
ターミナル (コマンドプロンプトとも言います) ウィンドウを開いてください。Mac OS Xの場合、ターミナル (Terminal.app) という名前のアプリケーションを実行します。Windowsの場合は[スタート] メニューから [ファイル名を指定して実行] をクリックして'cmd.exe'と入力します。$で始まる記述はコマンド行なので、これらはコマンドラインに入力して実行してください。続いて現在インストールされているRubyのバージョンが最新のものであることを確認してください。
RubyやRuby on Railsを素早くインストールするためのツールは多数存在します。Windowsユーザーの場合はRailsインストーラをお使いください。Mac OS XユーザーはTokaidoをお使いください。(訳注: 具体的なインストール方法についてはRailsチュートリアル 1.2 さっそく動作させるを参照してください)
$ ruby -v ruby 2.0.0p353
自分のPC環境にRubyがインストールされていない場合は、ruby-lang.org を参照して、自分の環境に合うインストール方法を参照してください。
多くのUnix系OSには実用的なバージョンのSQLite3が同梱されています。 Windowsユーザーなどその他の環境の方はSQLite3のインストール方法を参照してください。 正しくインストールされていること、PATH環境変数が正しく通っていることを確認してください。
$ sqlite3 --version
上を実行することでバージョンを確認できます。
Railsをインストールするには、gem installコマンドを実行します。このコマンドはRubyGemsによって提供されます。
$ gem install rails
以下のコマンドを実行することで、すべて正常にインストールできたかどうかを確認できます。
$ rails --version
"Rails 4.2.1"のように表示されれば、次に進むことができます。
Railsには、ジェネレータという多数のスクリプトが付属しており、これらが特定のタスクを開始するために必要なものを自動的に作り出してくれるので、開発が容易になります。その中から、新規アプリケーション作成用のジェネレータを使ってみましょう。これを実行すればRailsアプリケーションの基本的な部分が提供されるので、開発者が自分でこれらを作成する必要はありません。
ジェネレータを実行するには、ターミナルを開き、Railsファイルを作成したいディレクトリに移動して、以下を入力します。
$ rails new blog
これにより、Blogという名前のRails アプリケーションがblogディレクトリに作成され、Gemfileというファイルで指定されているgemファイルがbundle installコマンドによってインストールされます。
rails new -hを実行すると、Railsアプリケーションビルダで使用できるすべてのコマンドラインオプションを確認できます。
ブログアプリケーションを作成したら、そのフォルダ内に移動します。
$ cd blog
blogディレクトリの下には多数のファイルやフォルダが生成されており、これらがRailsアプリケーションを構成しています。このチュートリアルではほとんどの作業をappディレクトリで行いますが、Railsが生成したファイルとフォルダについてここで簡単に説明しておきます。
| ファイル/フォルダ | 目的 |
|---|---|
| app/ | ここにはアプリケーションのコントローラ、モデル、ビュー、ヘルパー、メーラー、そしてアセットが置かれます。以後、本ガイドでは基本的にこのディレクトリを中心に説明を行います。 |
| bin/ | ここにはアプリケーションを起動したりデプロイしたりするためのRailsスクリプトなどのスクリプトファイルが置かれます。 |
| config/ | アプリケーションの設定ファイル (ルーティング、データベースなど) がここに置かれます。詳細についてはRailsアプリケーションを設定する を参照してください。 |
| config.ru | アプリケーションの起動に必要となる、Rackベースのサーバー用のRack設定ファイルです。 |
| db/ | 現時点のデータベーススキーマと、データベースマイグレーションファイルが置かれます。 |
| Gemfile Gemfile.lock |
これらのファイルは、Railsアプリケーションで必要となるgemの依存関係を記述します。この2つのファイルはBundler gemで使用されます。Bundlerの詳細についてはBundlerのWebサイトを参照してください。 |
| lib/ | アプリケーションで使用する拡張モジュールが置かれます。 |
| log/ | アプリケーションのログファイルが置かれます。 |
| public/ | このフォルダの下にあるファイルは外部 (インターネット) からそのまま参照できます。静的なファイルやコンパイル済みアセットはここに置きます。 |
| Rakefile | このファイルには、コマンドラインから実行できるタスクを記述します。ここでのタスク定義は、Rails全体のコンポーネントに対して定義されます。独自のRakeタスクを定義したい場合は、Rakefileに直接書くと権限が強すぎるので、なるべくlib/tasksフォルダの下にRake用のファイルを追加するようにしてください。 |
| README.rdoc | アプリケーションの概要を説明するマニュアルをここに記入します。このファイルにはアプリケーションの設定方法などを記入し、これさえ読めば誰でもアプリケーションを構築できるようにしておく必要があります。 |
| test/ | Unitテスト、フィクスチャなどのテスト関連ファイルをここに置きます。テストについてはRailsアプリケーションをテストするを参照してください。 |
| tmp/ | キャッシュ、pid、セッションファイルなどの一時ファイルが置かれます。 |
| vendor/ | サードパーティによって書かれたコードはすべてここに置きます。通常のRailsアプリケーションの場合、外部からのgemファイルをここに置きます。 |
手始めに、画面に何かテキストを表示してみましょう。そのためには、Railsアプリケーションサーバーを起動しなくてはなりません。
先ほど作成したRailsアプリケーションは、既に実行可能な状態になっています。Webアプリケーションを開発用のPCで実際に動かしてこのことを確かめてみましょう。blogディレクトリに移動し、以下のコマンドを実行します。
$ rails server
CoffeeScriptをJavaScriptにコンパイルするにはJavaScriptランタイムが必要です。ランタイムが環境にない場合はexecjsエラーが発生します。Mac OS XやWindowsにはJavaScriptランタイムが同梱されています。Railsが新規アプリケーション用に生成するGemfileにはtherubyracerというgemがコメントアウトされた状態で含まれており、必要であればこのgemのコメントアウトを解除して有効にすることもできます。therubyrhinoはJRubyユーザー向けに推奨されているランタイムであり、JRuby環境下ではデフォルトでアプリケーションのGemfileに追加されます。サポートされているランタイムの詳細についてはExecJSで確認できます。
Railsで起動されるWebサーバーは、Rubyにデフォルトで付属しているWEBrickです。Webアプリケーションが実際に動作しているところを確認するには、ブラウザを開いて http://localhost:3000 を表示してください。以下のようなRailsのデフォルト情報ページが表示されます。

Webサーバーを停止するには、実行されているターミナルのウィンドウでCtrl + Cキーを押します。コマンドプロンプトのカーソルがふたたび表示されれば、サーバーは停止しています。Mac OS Xを含む多くのUnix系OSではプロンプトとしてドル記号$が使用されます。一般に、Railsの開発モードではファイルに変更を加えた場合でもサーバーを再起動する必要はありません。ファイルの変更は自動的にサーバーに反映されます(訳注: libファイルやapplication.rbなど一部の設定ファイルなどはサーバーを再起動しないと読み込まれません)。
Railsの初期画面である「Welcome aboard」ページは、新しいRailsアプリケーションの スモークテスト として使えます。このページが表示されれば、サーバーが正常に動作していることまでは確認できたことになります。 About your application's environment リンクをクリックすれば、アプリケーション環境の概要を確認できます。
Railsに"Hello"と表示するには、最低でも コントローラ と ビュー が必要です。
コントローラは、アプリケーションに対する特定のリクエストを受け取って処理するのが役割です。ルーティング は、リクエストをどのコントローラに割り振るかを決定するためのものです。1つのコントローラに対して複数のルーティングがあるのはよくあることです。そしてコントローラにはいくつかの アクション があります。いくつかの異なるルーティングに対して、それぞれ異なるアクションを割り当てることができます。それぞれのアクションは、情報を集めてビューに送り出すのが役割です。
ビューの役割は、この情報をユーザーが読める形式で表示することです。ここで気を付けていただきたい重要な違いは、表示する情報を集めるのは コントローラ であって、ビューではないということです。ビューは、コントローラが作成した情報に対して余計なことをせずに表示する必要があります。ビューテンプレートで使用できる言語は、デフォルトではeRuby (ERBとも、Embedded Rubyとも呼ばれます) が使用されます (訳注: 近年はhamlテンプレートがよく使われます)。ERBで書かれたコードは、ユーザーに表示される前のリクエストサイクルでRailsによって処理されます。
コントローラを新規作成するには、コントローラ用のジェネレータを実行します。ここでは以下のように、welcomeという名前のコントローラの中にindexというアクションを作成するよう指定します。
$ rails generate controller welcome index
Railsは指定どおりコントローラを作成し、関連ファイルやルーティングも設定してくれます。
create app/controllers/welcome_controller.rb
route get 'welcome/index'
invoke erb
create app/views/welcome
create app/views/welcome/index.html.erb
invoke test_unit
create test/controllers/welcome_controller_test.rb
invoke helper
create app/helpers/welcome_helper.rb
invoke test_unit
create test/helpers/welcome_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/welcome.js.coffee
invoke scss
create app/assets/stylesheets/welcome.css.scss
この中でもっとも重要なのはもちろんコントローラです。welcomeコントローラはapp/controllers/welcome_controller.rbに作成され、対応するindexビューがapp/views/welcome/index.html.erbに作成されます。
テキストエディタでapp/views/welcome/index.html.erbを開いてみましょう。ファイルの中身をすべて削除し、以下の1行に置き換えてください。
<h1>Hello, Rails!</h1>
以上でコントローラとビューが作成されました。Railsに"Hello, Rails!"と表示させてみましょう。ここでは、サイトのルートURL http://localhost:3000 にアクセスしたときにこのメッセージが表示されるようにします。現時点のルートURLでは、デフォルトの"Welcome aboard"が表示されていますので、これを変更します。
Railsで表示させたい実際のホームページの場所を指定します。
エディタでconfig/routes.rbを開いてください。
Rails.application.routes.draw do get 'welcome/index' # The priority is based upon order of creation: # first created -> highest priority. # # You can have the root of your site routed with "root" # root 'welcome#index' # # ...
上はアプリケーションの ルーティングファイル の内容です。外部からのリクエストをどのようにコントローラとアクションに振り分けるかを、DSL (ドメイン特化言語: domain-specific language) という特殊な言語を使用してこのファイル内に記述します。デフォルトのconfig/routes.rbには多数のルーティングサンプルがコメント行に記載されており、そのうちの1つに、サイトのルートにアクセスがあったときに接続するコントローラとアクションを指定する方法が書かれています。rootで始まっている行を見つけ、コメント記号を外してください。以下のようになるはずです。
root 'welcome#index'
root 'welcome#index'と記述することで、アプリケーションのルートURLへのアクセスをwelcomeコントローラのindexアクションに割り当てるようRailsに指示が伝わります。同様に、get 'welcome/index'はhttp://localhost:3000/welcome/indexというリクエストをwelcomeコントローラのindexアクションに割り当てます。後者は先ほどコントローラ用ジェネレータ (rails generate controller welcome index) を実行した時に自動的に作成されています。
ブラウザでhttp://localhost:3000を表示してみましょう (ジェネレータを実行するためにRailsを止めていた場合はrails serverを再実行してください)。app/views/welcome/index.html.erbの中に書いた"Hello, Rails!"という文字がブラウザ上に表示されるはずです。WelcomeControllerのindexアクションへのルーティングが新たに形成され、ビューが正しく表示されたことがこれで確認できました。
ルーティングの詳細についてはRailsのルーティングを参照してください。
以上で、コントローラとアクションとビューの作成方法を説明いたしました。ここからはもう少しブログらしい体裁を整えていきましょう。
今度はBlogアプリケーションに新しく リソース を作成します。ここで言う「リソース」とは、記事、人、動物などのよく似たオブジェクト同士が集まったものを指します。 リソースに対して作成 (create)、読み出し (read)、更新 (update)、削除 (destroy) の4つの操作を行なうことができるようになっており、これらの操作の頭文字を取って CRUD と呼ばれます。
Railsのルーティングにはresourcesメソッドがあり、これを使用してRESTリソースへの標準的なルーティングを宣言できます (訳注: RESTについてはWikipediaを参照してください)。たとえばconfig/routes.rbで articleリソース を宣言すると以下のようになります。
Rails.application.routes.draw do resources :articles root 'welcome#index' end
コマンドラインでrake routesコマンドを実行すると、標準的なRESTfulアクションへのルーティングがすべて定義されていることが確認できます。以下の出力のprefix列や他の列については後ほど解説しますが、ここでご注目いただきたいのは、Railsは「articles」というリソース名から単数形の「article」を推測し、両者をその意味にそって使い分けているという点です。prefix列で単一の項目には単数形のarticle、複数項目を扱う場合には複数形のarticlesが使われているという具合です。
$ rake routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy root GET / welcome#index
次の節では、アプリケーションで新しい記事を作成してそれを表示する機能を追加しましょう。これはCRUDでいう"C" (作成) と"R" (読み出し) の操作に相当します。作成するフォームは以下のような感じになります。

これだけでは飾り気がなさすぎる感じもしますが、今はこれでよしとします。スタイルの追加はその後に行います。
最初に、新規記事を作成するための場所がアプリケーション内に必要です。置き場所はやはり/articles/newでしょう。ルーティングは既に定義されているので、リクエストはアプリケーションの/articles/newに送られます。ブラウザでhttp://localhost:3000/articles/newを開くと、今はルーティングエラーが表示されます。

このエラーが発生したのは、ルーティングで指定された先に、リクエストを処理するように定義されたコントローラが見つからないためです。この問題を解決するには、それに対応するArticlesControllerを作成すればよいのです。以下のコマンドを実行して解決します。
$ rails g controller articles
今作成されたapp/controllers/articles_controller.rbをエディタで開くと、以下のような空のコントローラが作成されています。
class ArticlesController < ApplicationController end
コントローラは、ApplicationControllerを継承する形で定義されるシンプルなクラスです。コントローラの内側で定義されたメソッドは、コントローラのアクションになります。制作中のブログアプリケーションでは、これらのアクションがarticleに対するCRUD操作を担当します。
Rubyのメソッドはpublic、private、protectedに分けられますが、コントローラのアクションになれるのはpublicメソッドだけです。詳細についてはProgramming Rubyを参照してください。
ブラウザのhttp://localhost:3000/articles/newを再表示すると、今度は別のエラーが表示されます。

生成したArticlesControllerコントローラにnewアクションが見つからないというエラーです。これは、Railsでアクションを指定せずに生成したコントローラは中身が空のままになるためです。
コントローラ内にアクションを手作りするには、単にコントローラ内でメソッドを定義すればよいのです。app/controllers/articles_controller.rbをエディタで開き、ArticlesControllerクラスの内側に以下のようにnewメソッドを作成します。
def new end
ArticlesControllerコントローラにnewメソッドを作成してからブラウザでhttp://localhost:3000/articles/newを再表示すると、今度はまた違うエラーが表示されます。

Railsでは、このシンプルなアクションに関連付けられたビューがあり、そこで情報を表示できることを期待しています。アクションは定義されましたが、これに関連付けられたビューがないのでエラーが表示されます。
なお、上の画像ではエラーメッセージの下の部分は切り捨ててあります。完全なメッセージは以下のような感じになります。
Missing template articles/new, application/new with {locale:[:en], formats:[:html], handlers:[:erb, :builder, :coffee]}. Searched in: * "/path/to/blog/app/views"
何だかたくさんのテキストが表示されました。それぞれの部分がどういう意味なのかを見てみましょう。
最初の部分では、どのテンプレートが見当たらないかが示されています。ここではarticles/newというテンプレートがあるはずだと言っています。Railsは最初にこのテンプレートを探します。見つからない場合は次にapplication/newというテンプレートがあるかどうかを探します。application/newにテンプレートがあるかどうかを探しているのは、ArticlesControllerコントローラはApplicationControllerコントローラを継承しているからです。
次の部分にはハッシュがあります。ハッシュの:localeキーは、単にそのテンプレートが何語向けなのかを示しています。デフォルトでは英語 ("en") テンプレートが使用されます。次の:formatsキーは、応答時に返されるテンプレートのフォーマットを示します。デフォルトのフォーマットは:htmlなので、RailsはHTMLテンプレートを探します。最後の:handlersキーは、テンプレートを描画するときに使用される テンプレートハンドラ を示します。HTMLテンプレートで最もよく使用されるのは:erbです。同様に、XMLテンプレートには:builderが指定が、CoffeeScriptには:coffeeが最もよく使用されます。
最後の部分では、Railsがテンプレートを探した場所が示されています。このブログアプリケーションのようなシンプルなRailsアプリケーションでは、テンプレートの置き場所は1箇所ですが、複雑なアプリケーションではさまざまな場所にテンプレートが置かれることもあります。
この場合、テンプレートをapp/views/articles/new.html.erbに置くのが最もシンプルです。テンプレートのファイル名に付いている拡張子に気を付けてください。1つ目の拡張子はテンプレートの フォーマット を表し、2つ目の拡張子は使用される ハンドラー を示します。Railsは、articles/newというテンプレートをアプリケーションのapp/viewsで探そうとします。ここではテンプレートのフォーマットはHTMLでなければならず、ハンドラーはerb、builder、coffeeのいずれかでないといけないということになります。ここで作成しようとしているのは新しいHTMLフォームなので、ERB言語が使用されます。従って、テンプレートのファイル名はarticles/new.html.erbでなければならず、アプリケーションのapp/viewsディレクトリの下になければならないことになります。
それではapp/views/articles/new.html.erbを作成し、その中に以下のように記入しましょう。
<h1>New Article</h1>
http://localhost:3000/articles/newをブラウザで再表示すると、ページにタイトルが表示されるようになりました。ついに、ルーティングとコントローラとアクションとビューが協調して動作するようになりました。いよいよ新規記事を投稿するフォームを作成することにしましょう。
このテンプレート内にフォームを作成するために、form builder を使用します。Railsにはform_forというヘルパーメソッドがあり、主にこれを使用してフォームを作成します。以下のコードをapp/views/articles/new.html.erbに追加して、form_forメソッドを使用できるようにしましょう。
<%= form_for :article do |f| %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %>
ページをブラウザで再表示すると、先に図に示したフォームの例のとおりにフォームが表示されます。Railsのフォーム作成は非常に簡単です。
form_forメソッドを呼び出すときには、このフォームを識別するためのオブジェクトを渡してください。ここでは:articleというシンボルを渡します。form_forヘルパーは、これを見て何のフォームであるかを知ることができます。このメソッドのブロックの内側はFormBuilderオブジェクトを置きます(fで表すのが通例です)。ここでは2つのラベルと2つのテキストフィールドが置かれ、それぞれタイトルと記事本文になります。最後に、fオブジェクトに対してsubmitを実行すると、フォームの送信ボタンが作成されます。
しかし、このフォームには1つ問題があります。このフォームページのソースを表示して、生成されたHTMLをよく調べてみると、フォームのaction属性の送信先が/articles/newになってしまっています。/articles/newというルーティングは、このフォームを最初に表示するときに使用されるものなので、記入されたフォームの送信先まで同じルーティングにしてしまうのは変です。/articles/newはフォームの表示専用にすべきです。
どうやらフォームの送信先は別のURLにしなければならないようです。送信先の指定はform_forの:urlオプションで簡単に指定できます。Railsでは、新しいフォームの送信先となるアクションは"create"にするのが普通ですので、それに従って送信先を変更しましょう。
app/views/articles/new.html.erbをエディタで開き、form_forの行を以下のように変更します。
<%= form_for :article, url: articles_path do |f| %>
この例では、:urlオプションにarticles_pathヘルパーが渡されています。
このときRailsの内部で何が行われているのかを知るために、rake routesの出力結果をもう一度見てみましょう。
$ rake routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy root GET / welcome#index
articles_pathヘルパーは、articlesという接頭語に関連付けられているURIパターンをフォームの送信先とするようRailsに指示します。そしてこのフォームはデフォルトに従ってPOSTリクエストとしてルーティングに送信されます。そしてこのルーティングは、現在のコントローラであるArticlesControllerのcreateアクションに関連付けられます。
このフォームと、それに関連付けられたルーティングが定義されることで、フォームに記入して送信ボタンをクリックすると新しい記事作成プロセスが開始されるようになります。この状態でフォームを送信すると、既にお馴染みの以下のエラーが表示されます。

そこで今度はArticlesControllerコントローラ内にcreateアクションを作成し、フォームが動作するようにしましょう。
"Unknown action"エラーを解消するには、app/controllers/articles_controller.rbファイル内のArticlesControllerクラス内のnewアクションの下にcreateアクションを追加します。
class ArticlesController < ApplicationController def new end def create end end
修正後フォームを再送信すると、今度はまたしても「a template is missing」エラーが表示されます。ひとまずこのエラーは無視しましょう。createアクションの役割は、記事をデータベースに保存することです。
フォームを送信すると、フォームに含まれるフィールドは パラメータ としてRailsに送信されます。これらのパラメータは、受け取ったコントローラ内のアクションで参照可能になっており、これを使用して特定のタスクを実行します。実際のパラメータがどのようになっているかを確認するために、createアクションに以下の変更を加えてみましょう。
def create render plain: params[:article].inspect end
ここでrenderメソッドは非常に単純なハッシュを引数に取ります。ハッシュのキーはplain、ハッシュの値はparams[:article].inspectです。paramsメソッドは、フォームから送信されてきたパラメータ (つまりフォームのフィールド) を表すオブジェクトです。paramsメソッドはActiveSupport::HashWithIndifferentAccessオブジェクトを返します。文字列またはシンボルを使用して、このオブジェクトのハッシュのキーを指定できます。今回の場合、必要なのはフォームの値のうちの1つだけです。
フォームを再送信してみると、今度はmissing templateエラーが表示されなくなりました。今度は以下が表示されました。
{"title"=>"First article!", "text"=>"This is my first article."}
このアクションは、フォームから送信されたパラメータをそのまま表示するようになりました。しかしこのままでは役に立ちそうにありません。確かにパラメータは表示されるようになりましたが、何の加工もされていません。
Railsのモデルは、単数形の名前を持ち、対応するデータベーステーブル名は複数形で表されるというルールがあります。Railsにはモデル作成用のジェネレータもあり、多くのRails開発者がモデル作成の際に使用しています。モデルを作成するにはターミナルで以下のコマンドを実行します。
$ rails generate model Article title:string text:text
このコマンドを実行すると、Articleモデルが作成されます。その中にはstring型の title 属性とtext型の text 属性が作成されています。これらの属性は、データベースのarticlesテーブルに自動的に追加され、Articleモデルと対応付けられます (訳注: 実際には後述するマイグレーションを行わないとデータベースとの対応付けは完了しません)。
Railsによって多数のファイルが作成されました。ここで必要なのは、app/models/article.rbとdb/migrate/20140120191729_create_articles.rbの2つだけです (後者のファイル名には日付が含まれているのでこれと同じにはなりません)。後者のマイグレーションファイルは、データベース構造を作成するためのものであり、この次に説明します。
Active Recordは、データベースのカラム名とモデルの属性を自動的に対応付けるインテリジェントな機能を有しています。このおかげで、Railsのモデルでは属性をいちいち宣言する必要がありません。そうした作業はActive Recordが自動的にやってくれます。
既に見たようにrails generate modelを実行すると データベースマイグレーション ファイルがdb/migrateの下に作成されます。マイグレーションはRubyのクラスであり、データベーステーブルの作成や変更を簡単に行うためのしくみです。マイグレーションを実行するにはrakeコマンドを実行します。マイグレーションを使用して行ったデータベース構成の変更は、後から取り消すことができます。マイグレーションファイルの名前にはタイムスタンプが含まれており、これに基いて、マイグレーションは作成された順に実行されます。
ここでdb/migrate/20140120191729_create_articles.rb ファイルをエディタで開いてみると (タイムスタンプは各自異なることにご注意ください)、以下のようになっています。
class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.string :title t.text :text t.timestamps end end end
上のマイグレーションファイルにはchangeという名前のメソッドが作成されており、マイグレーションの実行時に呼び出されます。このメソッドで定義されてる操作は取り消しが可能です。つまり、Railsはchangeメソッドで行われたマイグレーションを必要に応じて元に戻すことができます。このマイグレーションを実行すると、articlesというテーブルが作成され、文字列カラムとテキストカラムが1つずつ作成されます。Railsは、マイグレーション時に作成日と更新日を追跡するためのタイムスタンプフィールドを2つ作成します。これは指定がなくても自動的に行われます。
マイグレーションの詳細については、Active Recordマイグレーションを参照してください。
ここでは、以下のようにrakeコマンドでマイグレーションを実行します。
$ rake db:migrate
マイグレーションコマンドによってArticlesテーブルがデータベース上に作成されます。
== CreateArticles: migrating ================================================== -- create_table(:articles) -> 0.0019s == CreateArticles: migrated (0.0020s) =========================================
マイグレーションはデフォルトではdevelopment (開発) 環境で実行されます。そのため、config/database.ymlファイルのdevelopmentセクションで定義されている開発用データベースに対して実行される点にご注意ください。production (本番) 環境など、development以外の環境に対してもマイグレーションを実行したい場合は、rake db:migrate RAILS_ENV=productionのように環境変数を明示的に指定する必要があります。
ふたたびArticlesControllerに戻りましょう。先ほど作成したArticleモデルを使用して、createアクションを変更しなければなりません。app/controllers/articles_controller.rbをエディタで開き、createアクションを次のように変更します。
def create @article = Article.new(params[:article]) @article.save redirect_to @article end
変更内容を説明します。Railsのすべてのモデルは初期化時に属性(フィールド)を与えられ、それらはデータベースカラムに自動的に対応付けられます。メソッドの1行目ではまさにそれが行われています (取り出したい属性はparams[:article]の中にあります)。次の@article.saveで、このモデルをデータベースに保存します。最後に、ユーザーをshowアクションにリダイレクトします (showアクションはこの後定義します)。訳注: モデルを保持している@articleを指定するだけで、そのモデルを表示するためのshowアクションにリダイレクトされる点にご注目ください。
後に解説しますが、@article.saveは保存に成功したかどうかを真偽値 (trueまたはfalse) で返します。
この時点でブラウザでhttp://localhost:3000/articles/newを表示すると、記事の作成が ほぼ 可能な状態になっています。実際にやってみましょう。すると、以下のようなエラーが表示されます。

Railsにはセキュリティの高いアプリケーションを開発するのに便利な機能が多数あり、ここではその機能に引っかかったのです。これはstrong_parametersと呼ばれるもので、コントローラのアクションで本当に使用してよいパラメータだけを厳密に指定することを強制するものです。
なぜそんな面倒なことをしないといけないのでしょうか。コントローラが受け取ったパラメータをノーチェックでまるごと自動的にモデルに渡せるようにする方が確かに開発は楽なのですが、パラメータの渡し方をこのように便利にしてしまうと、パラメータがチェックされていない点を攻撃者に悪用される可能性があります。たとえば、サーバーへのリクエストに含まれる新規投稿送信フォームに、もともとフォームになかったフィールドが攻撃者によって密かに追加され、それがアプリケーションの整合性を脅かす可能性が考えられます。チェックされていないパラメータをまるごとモデルに保存する行為は、モデルに対する「マスアサインメント」と呼ばれています。これが発生すると、正常なデータの中に悪意のあるデータが含まれてしまう可能性があります。
そこで、コントローラで渡されるパラメータはホワイトリストでチェックし、不正なマスアサインメントを防止する必要があるのです。この場合、createでパラメータを安全に使用するために、titleとtextパラメータの利用を「許可」し、かつ「必須」であることを指定したいのです。この指定を文法化するために、requireメソッドとpermitメソッドが導入されました。これに基いて、該当行を以下のように変更します。
@article = Article.new(params.require(:article).permit(:title, :text))
この記法を毎回繰り返すのは煩雑なので、たとえばcreateアクションとupdateアクションで共用できるようにこのメソッドをくくりだしておくのが普通です。くくりだしたメソッドは、マスアサインメントを避けるだけでなく、外部から不正に呼び出されることのないようにprivate宣言の後に置いてください。
修正結果は以下のようになります。
def create @article = Article.new(article_params) @article.save redirect_to @article end private def article_params params.require(:article).permit(:title, :text) end
詳細については、上に挙げた参考資料に加えてStrong Parametersに関する公式ブログの記事 (英語) を参照してください。
現時点の状態でフォームを再度送信すると、showアクションがないというメッセージがRailsから返されます。このままでは実用に耐えないので、showアクションを追加して先に進むことにしましょう。
rake routesの出力結果にもあったようにshowアクションへのルーティングは以下のようになります。
article GET /articles/:id(.:format) articles#show
:idは、ここに:idパラメータが置かれることを指定するための特殊な文法です。この場合は記事のidを表します。
newで既に行ったのと同じ要領で、app/controllers/articles_controller.rbにshowアクションを追加し、対応するビューも追加する必要があります。
def show @article = Article.find(params[:id]) end
ここでいくつか注意すべき点があります。ここではArticle.findを使用して、取り出したい記事をデータベースから探しています。このとき、リクエストの:idパラメータを取り出すためにparams[:id]を引数としてfindに渡しています。そして、取り出した記事オブジェクトへの参照を保持するために、通常の変数ではなく、インスタンス変数 (@が頭に付いているのが印です) が使用されている点にもご注目ください。これは、Railsではコントローラのインスタンス変数はすべてビューに渡されるようになっているからです (訳注: Railsはそのために背後でインスタンス変数をコントローラからビューに絶え間なくコピーし続けています)。
それでは、app/views/articles/show.html.erbファイルを作成し、以下のように記入しましょう。
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p>
上のように変更したことで、新しい記事の作成がようやくできるようになりました。 http://localhost:3000/articles/newをブラウザで開いて試してみましょう。

単独の記事は表示できるようになりましたが、今度は記事の一覧も表示できるようにしてみましょう。
今度もrake routesでルーティングを確認すると、以下のようなルーティングが既にあります。
articles GET /articles(.:format) articles#index
以下のように、このルーティングに対応するindexアクションを、app/controllers/articles_controller.rbのArticlesControllerの中に作成します。
def index @articles = Article.all end
最後に、このアクションに対応するビューをapp/views/articles/index.html.erbに追加します。
<h1>Listing articles</h1> <table> <tr> <th>Title</th> <th>Text</th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> </tr> <% end %> </table>
これで、http://localhost:3000/articlesをブラウザで開くと、作成された記事の一覧が表示されるようになりました。
ここまでで、記事の作成、表示、一覧表示ができるようになりました。今度は、ページ間を移動するためのリンクを追加してみましょう。
app/views/welcome/index.html.erbを開いて以下のように変更してください。
<h1>Hello, Rails!</h1> <%= link_to 'My Blog', controller: 'articles' %>
link_toメソッドは、Railsのビルトインヘルパーの1つです。このメソッドは、指定されたテキストに基いたリンクを作成し、ジャンプ先を表示します。ここでは各記事へのパスを指定します。
他のビューへのリンクも作成してみましょう。"New Article"リンクをapp/views/articles/index.html.erbに追加し、<table>タグの上に置きます。
<%= link_to 'New article', new_article_path %>
このリンクをクリックするとフォームが表示され、そこで新しい記事を作成することができるようになります。
app/views/articles/new.html.erbのフォームの下に、記事を作成せずに元のindexアクションに戻るリンクも作成しましょう。
<%= form_for :article, url: articles_path do |f| %> ... <% end %> <%= link_to 'Back', articles_path %>
最後に、app/views/articles/show.html.erbテンプレートに、indexアクションに戻るためのリンクも追加し、記事単体を見ていたユーザーが元に戻って一覧を参照できるようにします。
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <%= link_to 'Back', articles_path %>
現在と同じコントローラのアクションにリンクする場合は、controllerの指定は不要です。デフォルトでは現在のコントローラが使用されるからです。
developmentモード (これはRailsのデフォルトのモードです) では、Railsはリクエストのたびにアプリケーションを再読み込みします。これは開発をやりやすくするためであり、変更を行なうたびにRailsのWebサーバーを再起動する必要はありません。
モデルファイルapp/models/article.rbの中身は、以下のように驚くほどシンプルです。
class Article < ActiveRecord::Base end
ファイルにはこれしか書かれていませんが、このArticleクラスがActiveRecord::Baseクラスを継承していることにご注目ください。Active Recordは、基本的なデータベースCRUD (Create、Read、Update、Destroy) 操作、データの検証 (バリデーション)、洗練された検索機能、複数のモデルを関連付ける(リレーションシップ) など、きわめて多くの機能をRailsモデルに無償で提供しています。
Railsには、モデルに渡したデータを検証する機能もあります。app/models/article.rbファイルをエディタで開き、以下のように変更します。
class Article < ActiveRecord::Base validates :title, presence: true, length: { minimum: 5 } end
このように変更されると、すべての記事にタイトルが存在し、その長さが5文字以上であることが保証されます。そうでない場合には記事はデータベースに保存されません。Railsには豊富な検証機能があり、存在確認、カラムでの重複確認、フォーマット確認、関連付けられたオブジェクトがあるかどうかの確認などが行えます。検証の詳細についてはActive Record バリデーションを参照してください。
検証機能が追加されたので、検証が通らない内容を持つ@articleに対して@article.saveを実行するとfalseが返されるようになりました。さて、app/controllers/articles_controller.rbを再度開いてみると、残念なことにまだcreateアクションで@article.saveの結果を利用するようになっていません。@article.saveが失敗したらそのことをユーザーに表示してあげないと不親切です。そのためには、app/controllers/articles_controller.rbのnewアクションとcreate`アクションを以下のように変更してください。
def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end private def article_params params.require(:article).permit(:title, :text) end
newで@articleというインスタンス変数が新たに作成されるようになりました。これを何に使うのかはすぐにわかります。
createアクションも、saveの結果がfalseの場合には、redirect_toではなく、newテンプレートに対するrenderを実行するように変更されました。ここでrenderメソッドを使用する理由は、ビューのnewテンプレートが描画されたときに、@articleオブジェクトがビューのnewテンプレートに返されるようにするためです。renderによる描画は、フォームの送信時と同じリクエスト内で行われます。対照的に、redirect_toはサーバーに別途リクエストを発行するようブラウザに対して指示するので、やりとりが1往復増えます。
http://localhost:3000/articles/newをブラウザで再表示し、わざと記事のタイトルを空にして保存してみましょう。Railsは記事入力フォームを再表示するはずです。しかしこれだけではまだ不親切です。入力のどこに問題があったのかをユーザーに通知する必要があります。そこで、app/views/articles/new.html.erbを変更して、エラーメッセージがある場合に表示するようにしてみましょう。
<%= form_for :article, url: articles_path do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved:</h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %>
何やら目新しいコードが追加されています。ここでは、@article.errors.any?でエラーが発生しているかどうかをチェックしています。そしてエラーの場合は@article.errors.full_messagesでエラーメッセージを全文表示します。
pluralizeは、数値を受け取ってそれに応じて英語の「単数形/複数形」活用を行ってくれるRailsのヘルパーメソッドです。数値が1より大きい場合は、引数の文字列を自動的に複数形に変更します(訳注:pluralizeはたいていの不規則活用にも対応しています)。
ArticlesControllerに@article = Article.newを追加した理由は、そうしないとビューで受け取る@articleがnilになってしまい、@article.errors.any?を呼び出すところでエラーになってしまうためです。Articleのインスタンス作成に成功したときは@articleがnilにならないようにしておきたいわけです。
Railsでは、エラーメッセージを含むフィールドは自動的にfield_with_errorsクラスを持つdivタグで囲まれます。これを利用して、エラーメッセージをもっと目立たせるようにcssルールを定義しても構いません。
これで、http://localhost:3000/articles/newのフォームで新しい記事を保存する時にタイトルがなかった場合に、適切なエラーメッセージが表示されるようになりました。

ここまでで、CRUDのうちCとRを実現しました。今度はUの部分、つまり記事の更新を実装してみましょう。
最初に、ArticlesControllerにeditアクションを追加しましょう。
def edit @article = Article.find(params[:id]) end
編集用のビューに含まれるフォームは、記事を作成するときのビューに含まれるフォームと基本的にほとんど同じです。app/views/articles/edit.html.erbというファイルを作成し、以下のコードを入力してください。
<h1>Editing article</h1> <%= form_for :article, url: article_path(@article), method: :patch do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved:</h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %>
このフォームの送信先はupdateアクションになります。今の時点では未定義ですが、この後すぐ定義します。
ここでmethod: :patchというオプションが指定されていますので、PATCHというHTTPメソッドを使用してこのフォームを送信しようとしていることがRailsに伝わります。PATCHメソッドは、RESTプロトコルに基いてリソースを 更新 するために使用されます。
form_forヘルパーメソッドの最初のパラメータには@articleのようなオブジェクトを使用できます。@articleのようなオブジェクトが最初のパラメータとして渡されると、ヘルパーはそのパラメータに含まれているフィールドを使用してフォームの項目を埋めます。ここで面白いのは、@articleのようなインスタンス変数の代わりに同じ名前のシンボル (:articleなど) を渡した場合にも動作はまったく同じであることです。以上がこのコードで行われていることです。詳細については、form_forに関するAPIドキュメント (英語) を参照してください。
続いて、app/controllers/articles_controller.rbにupdateアクションを作成しましょう。
def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render 'edit' end end private def article_params params.require(:article).permit(:title, :text) end
既存のレコードを更新したいときには新たにupdateアクションを使用します。このアクションには、更新後の属性を含むハッシュを渡すことができます。createのときに既に行ったように、記事の更新に失敗してエラーが発生した場合、そのことをユーザーに伝えるようにしましょう。
createアクションで使用したarticle_paramsメソッドをここでも使うことにします。
updateに属性をすべて渡す必要はありません。たとえば、@article.update(title: 'A new title')を実行した場合、Railsはtitle属性のみを更新し、それ以外の属性は変更しません。
最後に、editアクションへのリンクを全記事の一覧に追加しましょう。app/views/articles/index.html.erbに以下のように手を加えて"Show"リンクの隣にEditリンクを追加します。
<table> <tr> <th>Title</th> <th>Text</th> <th colspan="2"></th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> <td><%= link_to 'Edit', edit_article_path(article) %></td> </tr> <% end %> </table>
同様に、app/views/articles/show.html.erbテンプレートにもEditリンクを追加しましょう。こうしておけば各記事のページから編集を行えるようになります。テンプレートの最下部に以下を追加します。
... <%= link_to 'Back', articles_path %> | <%= link_to 'Edit', edit_article_path(@article) %>
ここまでの変更で、アプリケーションの外観は以下のような感じになっているはずです。

さて、editページをよく見ると、newページとほとんど違いがありません。実際、フォームを表示するコードはどちらでもまったく同じになっています。パーシャル(部分テンプレートとも呼ばれます)を使用して、このような無駄な重複を取り除きましょう。Rubyの慣例として、パーシャルのファイル名の先頭にはアンダースコアを追加します。
パーシャルについての詳細は本ガイドのレイアウトとレンダリングを参照してください。
app/views/articles/_form.html.erbという名前のパーシャルファイルを作成し、以下の内容を入力してください。
<%= form_for @article do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved:</h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %>
このコードをよく観察してみると、form_forの宣言部分以外には元のコードとの違いがないことがわかります。他のフォーム内のコードを置き換えるパーシャル内でのform_for宣言がこのように短くて簡潔で済むのは、@articleがRESTfulルーティングの完全なセットに対応する リソース であり、必要なURIとメソッドをRailsがそれに基いて推測できるからです。
form_forの使用法の詳細については、Rails APIのリソース指向のスタイル (英語) を参照してください。
今度はapp/views/articles/new.html.erbビューを完全に書き直して、今作成したパーシャルをここで使ってみましょう。
<h1>New article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %>
続いて、app/views/articles/edit.html.erbビューでも同じ作業を行います。
<h1>Edit article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %>
いよいよCRUDのDまで到達しました。ここでは記事をデータベースから削除します。RESTの慣例に従い、記事の削除に使用するルーティングをrake routesの出力結果から取り出したのが以下です。
DELETE /articles/:id(.:format) articles#destroy
ルーティングメソッドであるdeleteは、リソースを削除するときに使用する必要があります。なお、この削除用ルーティングに通常のgetルーティングが使用されていると、以下のような危険なURLを送信できてしまいます。
<a href='http://example.com/articles/1/destroy'>look at this cat!</a>
リソースの削除にdeleteメソッドが使用され、このルーティングがdestroyアクションに割り当てられる流れになります。このdestroyアクションはまだ作成してなかったのでここで以下の内容で作成しましょう。
def destroy @article = Article.find(params[:id]) @article.destroy redirect_to articles_path end
データベースのレコードを削除したい場合には、Active Recordのdestroyメソッドを呼びます。なお、レコードの削除の場合、それ専用のビューテンプレートは不要です。その代わりに削除後にindexアクションにリダイレクトします。
最後に、 indexアクションのテンプレート(app/views/articles/index.html.erb)に'Destroy'リンクを追加し、機能を完成させましょう。
<h1>Listing Articles</h1> <%= link_to 'New article', new_article_path %> <table> <tr> <th>Title</th> <th>Text</th> <th colspan="3"></th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> <td><%= link_to 'Edit', edit_article_path(article) %></td> <td><%= link_to 'Destroy', article_path(article), method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </table>
上で追加したコードでは、link_toメソッドの使い方がこれまでと違っていることにご注目ください。2番目の引数で名前付きルートを渡している点はこれまでと同じですが、その後に別の引数があります。この:methodオプションと:'data-confirm'オプションはHTML5の属性です。このリンクをクリックすると、本当に削除してよいかどうかを確認するメッセージを表示し、その後deleteメソッドとリンクを送信します。このダイアログボックスの表示はjquery_ujsというJavaScriptファイルによって自動的に行われます。このファイルはアプリケーションの生成時に自動的にアプリケーションレイアウト (app/views/layouts/application.html.erb) に含まれます。このJavaScriptファイルがないと、ダイアログボックスは表示されなくなります。

以上で記事の作成、表示、一覧表示、更新、削除をひととおり実装できました。お疲れさまでした!
Railsでは、ルーティングを1つずつ手作りするよりもresourcesオブジェクトを使用してルーティングを設定することが推奨されています。 ルーティングの詳細については、本ガイドのRailsのルーティングを参照してください。
今度はアプリケーションに第2のモデルを追加しましょう。この第2のモデルでは、記事へのコメントを扱います。
今回のモデルの生成には、Articleモデルを生成したときと同じジェネレータを使用します。作成するCommentモデルは、記事への参照を保持します。以下のコマンドをターミナルで実行してください。
$ rails generate model Comment commenter:string body:text article:references
このコマンドを実行すると、4つのファイルが生成されます。
| ファイル | 目的 |
|---|---|
| db/migrate/20140120201010_create_comments.rb | データベースにコメント用のテーブルを作成するためのマイグレーションファイル (ファイル名のタイムスタンプはこれとは異なります) |
| app/models/comment.rb | Commentモデル |
| test/models/comment_test.rb | Commentモデルをテストするためのハーネス |
| test/fixtures/comments.yml | テストで使用するサンプルコメント |
最初にapp/models/comment.rbを見てみましょう。
class Comment < ActiveRecord::Base belongs_to :article end
Commentモデルの内容は、これまでに見たArticleモデルと非常によく似ています。違いといえば、Active Recordの 関連付け (アソシエーション) を設定するためのbelongs_to :articleという行がある点です。関連付けの詳細については、本ガイドの次の節で説明します。
モデルのファイルの他にマイグレーションファイルも生成されています。マイグレーションファイルは、モデルに対応するデータベーステーブルを生成するために使用されます。
class CreateComments < ActiveRecord::Migration def change create_table :comments do |t| t.string :commenter t.text :body # 以下の行によって`article_id`という整数カラムが追加される t.references :article, index: true t.timestamps end end end
t.referencesという行は、2つのモデルの関連付けを指定するための外部キーを設定します。このとき、関連付け用のインデックスもカラム上に作成されます。それではマイグレーションを実行しましょう。
$ rake db:migrate
Railsは、これまで実行されていないマイグレーションだけを適切に見分けて実行しますので、以下のようなメッセージだけが表示されるはずです。
== CreateComments: migrating ================================================= -- create_table(:comments) -> 0.0115s == CreateComments: migrated (0.0119s) ========================================
Active Recordの関連付け機能により、2つのモデルの間にリレーションシップを簡単に宣言することができます。今回の記事とコメントというモデルの場合、以下のいずれかの方法で関連付けを設定できます。
そして上の方法(における英語の記述)は、Railsで関連付けを宣言するために使用される文法と非常に似ています。Comment モデル (app/models/comment.rb) 内のコードに既に書かれていたように、1つの記事には1つのコメントが属しています。
class Comment < ActiveRecord::Base belongs_to :article end
そして、Articleモデルapp/models/article.rbを編集して、他方のモデルを追加する必要があります。
class Article < ActiveRecord::Base has_many :comments validates :title, presence: true, length: { minimum: 5 } end
2つのモデルで行われているこれらの宣言によって、さまざまな動作が自動化されています。たとえば、@articleというインスタンス変数に記事が1つ含まれているのであれば、@article.commentsと書くだけでその記事に関連付けられているコメントをすべて取得することができるのです。
Active Recordの関連付けの詳細については、Active Recordの関連付け(アソシエーション)ガイドを参照してください。
welcomeコントローラで行ったときと同様、commentsを参照するためにRailsが知っておくべきルーティングを追加する必要があります。再びconfig/routes.rbファイルを開き、以下のように変更してください。
resources :articles do resources :comments end
この設定により、articleの内側に ネストされたリソース としてcommentsが作成されます。これは、モデルの記述とは別の視点から、記事とコメントの間のリレーションシップを階層的に捉えたものであると言えます。
ルーティングの詳細についてはRailsのルーティングを参照してください。
モデルを手作りしたのですから、それに合ったコントローラも作ってみたくなります。ということで再びこれまでと同じジェネレータを使用してみましょう。
$ rails generate controller Comments
上のコマンドを実行すると、6つのファイルと1つの空ディレクトリが作成されます。
| ファイル/ディレクトリ | 目的 |
|---|---|
| app/controllers/comments_controller.rb | コメント用コントローラ |
| app/views/comments/ | コントローラのビューはここにおかれる |
| test/controllers/comments_controller_test.rb | コントローラのテスト用ファイル |
| app/helpers/comments_helper.rb | ビューヘルパー |
| test/helpers/comments_helper_test.rb | ヘルパー用のファイル |
| app/assets/javascripts/comment.js.coffee | コントローラ用のCoffeeScript |
| app/assets/stylesheets/comment.css.scss | コントローラ用のCSS (カスケーディングスタイルシート) ファイル |
一般的なブログと同様、このブログの記事を読んだ人はそこに直接コメントを追加したくなるでしょう。そしてコメントを追加後に元の記事表示ページに戻り、コメントがそこに反映されていることを確認したいはずです。そこで、CommentsControllerを使用してコメントを作成したり、スパムコメントが書き込まれたら削除できるようにしたいと思います。
そこで最初に、Articleのshowテンプレート (app/views/articles/show.html.erb) を改造して新規コメントを作成できるようにしましょう。
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %> | <%= link_to 'Edit', edit_article_path(@article) %>
上のコードでは、Articleのshowページにフォームが1つ追加されています。このフォームはCommentsControllerのcreateアクションを呼び出すことでコメントを新規作成します。form_for呼び出しでは配列を1つ渡しています。これは/articles/1/commentsのような「ネストしたルーティング (nested route)」を生成します。
今度はapp/controllers/comments_controller.rbのcreateアクションを改造しましょう。
class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end
上のコードは、Articleコントローラのコードを書いていたときよりも何だか複雑に見えます。これはネスティングを使用したことによって複雑さが増したのです。コメント関連のリクエストでは、コメントが追加される先の記事がどれであったかを忘れないようにしておく必要があります。そこで、Articleモデルのfindメソッドを最初に呼び出し、リクエストで言及されている記事(のオブジェクト)を取得して@articleに保存しています。
さらにこのコードでは、関連付けによって使用できるようになったメソッドをいくつも利用しています。@article.commentsに対してcreateメソッドを実行することで、コメントの作成と保存を同時に行っています(訳注: buildメソッドにすれば作成のみで保存は行いません)。この方法でコメントを作成すると、コメントと記事が自動的にリンクされ、指定された記事に対してコメントが従属するようになります。
新しいコメントの作成が完了したら、article_path(@article)ヘルパーを使用して元の記事の画面に戻ります。既に説明したように、このヘルパーを呼び出すとArticlesControllerのshowアクションが呼び出され、show.html.erbテンプレートが描画されます。この画面にコメントを表示できるようにしたいので、app/views/articles/show.html.erbに以下のコードを追加しましょう。
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <% @article.comments.each do |comment| %> <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <% end %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit Article', edit_article_path(@article) %> | <%= link_to 'Back to Articles', articles_path %>
以上で、ブログに記事やコメントを自由に追加して、それらを正しい場所に表示できるようになりました。

さて、ブログの記事とコメントが動作するようになったので、ここでapp/views/articles/show.html.erbテンプレートを見てみましょう。何やらコードがたくさん書かれていて読みにくいように思えます。ここでもパーシャルを使用してコードをきれいにしましょう。
最初に、特定記事のコメントをすべて表示する部分を切り出してコメントパーシャルを作成しましょう。app/views/comments/_comment.html.erbというファイルを作成し、以下のコードを入力します。
<p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p>
続いて、app/views/articles/show.html.erbの内容を以下のように変更しましょう。
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <%= render @article.comments %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit Article', edit_article_path(@article) %> | <%= link_to 'Back to Articles', articles_path %>
これにより、app/views/comments/_comment.html.erbパーシャルが、@article.commentsコレクションに含まれているコメントをすべて出力するようになりました。renderメソッドが@article.commentsコレクションに含まれる要素を1つ1つ列挙するときに、各コメントをパーシャルと同じ名前のローカル変数に自動的に割り当てます。この場合はcommentというローカル変数が使用され、これはパーシャルでの表示に使用されます。
今度はコメント作成部分もパーシャルに追い出してみましょう。app/views/comments/_form.html.erbファイルを作成し、以下のように入力します。
<%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %>
続いてapp/views/articles/show.html.erbの内容を以下のように変更しましょう。
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <%= render @article.comments %> <h2>Add a comment:</h2> <%= render "comments/form" %> <%= link_to 'Edit Article', edit_article_path(@article) %> | <%= link_to 'Back to Articles', articles_path %>
2番目のrenderは、描画したいパーシャルテンプレートであるcomments/formを単純に定義しているだけです。comments/formと書くだけで、Railsは区切りのスラッシュ文字に気付き、app/views/commentsディレクトリの_form.html.erbパーシャルを描画すればよいということを理解し、実行してくれます。app/views/comments/_form.html.erbなどと書く必要はありません。
@articleオブジェクトはインスタンス変数なので、ビューで出力されるどのパーシャルからもアクセスできます。
スパムコメントを削除できるようにするのも、このブログでは重要な機能です。そのためのビューを作成し、CommentsControllerにdestroyアクションを作成する必要があります。
最初にapp/views/comments/_comment.html.erbパーシャルに削除用のリンクを追加しましょう。
<p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <p> <%= link_to 'Destroy Comment', [comment.article, comment], method: :delete, data: { confirm: 'Are you sure?' } %> </p>
この新しい"Destroy Comment"リンクをクリックすると、DELETE /articles/:article_id/comments/:idというリクエストがCommentsControllerに送信されます。コントローラはそれを受け取って、どのコメントを削除すべきかを検索することになります。それではコントローラ (app/controllers/comments_controller.rb) にdestroyアクションを追加しましょう。
class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end def destroy @article = Article.find(params[:article_id]) @comment = @article.comments.find(params[:id]) @comment.destroy redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end
destroyアクションでは、まずどの記事が対象であるかを検索して@articleに保存し、続いて@article.commentsコレクションの中のどのコメントが対象であるかを特定して@commentに保存します。そしてそのコメントをデータベースから削除し、終わったら記事のshowアクションに戻ります。
ある記事を削除したら、その記事に関連付けられているコメントも一緒に削除する必要があります。そうしないと、コメントがいつまでもデータベース上に残ってしまいます。Railsでは関連付けにdependentオプションを指定することでこれを実現しています。Articleモデルapp/models/article.rbを以下のように変更しましょう。
class Article < ActiveRecord::Base has_many :comments, dependent: :destroy validates :title, presence: true, length: { minimum: 5 } end
このブログアプリケーションをオンラインで公開すると、このままでは誰でも記事を追加/編集/削除したり、コメントを削除したりできてしまいます。
Railsではこのような場合に便利な、非常にシンプルなHTTP認証システムが用意されています。
ArticlesControllerでは、認証されていない人物がアクションに触れないようにブロックする必要があります。そこで、Railsのhttp_basic_authenticate_withメソッドを使用することで、このメソッドが許可する場合に限って、リクエストされたアクションにアクセスできるようにすることができます。
この認証システムを使用するには、ArticlesControllerコントローラの最初の部分で指定します。今回は、indexアクションとshowアクションは自由にアクセスできるようにし、それ以外のアクションには認証を要求するようにしたいと思います。そこで、app/controllers/articles_controller.rbに次の記述を追加してください。
class ArticlesController < ApplicationController http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show] def index @articles = Article.all end # (以下省略)
コメントの削除も認証済みユーザーにだけ許可したいので、CommentsController (app/controllers/comments_controller.rb) に以下のように追記しましょう。
class CommentsController < ApplicationController http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy def create @article = Article.find(params[:article_id]) ... end # (以下省略)
ここで記事を新規作成しようとすると、以下のようなBASIC http認証ダイアログが表示されます。

もちろん、Railsでは他の認証方法を使用することもできます。Railsにはさまざまな認証システムがありますが、その中で人気が高い認証システムはDeviseとAuthlogic gemの2つです。
セキュリティ、それもWebアプリケーションのセキュリティは非常に幅広く、かつ詳細に渡っています。Railsアプリケーションのセキュリティの詳細については、本ガイドのRailsセキュリティガイドを参照してください。
以上で、Railsアプリケーションを初めて作るという試みは終わりです。この後は自由に更新したり実験を重ねたりできます。もちろん、何の助けもなしにWebアプリケーションを作らなければならないなどということはありません。Railsを使用してWebアプリケーションを立ち上げたり実行したりするうえで助けが必要になったら、以下のサポート用リソースを自由に参照できます。
Railsには、rakeコマンドラインユーティリティを使用して生成できるビルトインヘルプもあります。
rake doc:guidesを実行すると、本Railsガイドの完全なコピーがアプリケーションのdoc/guidesフォルダに生成されます。ブラウザでdoc/guides/index.htmlを開くことでガイドを参照できます。rake doc:railsを実行すると、Rails APIドキュメントの完全なコピーがアプリケーションのdoc/apiフォルダに生成されます。ブラウザでdoc/api/index.htmlを開いてAPIドキュメントを参照できます。doc:guides rakeタスクを使用してRailsガイドをローカル生成するには、RedCloth gemをインストールする必要があります。RedCloth gemをGemfileに追記してbundle installを実行することで利用できるようになります。
Railsでの無用なトラブルを避けるための最も初歩的な方法は、外部データを常にUTF-8で保存することです。このとおりにしないと、RubyライブラリやRailsはネイティブデータをたびたびUTF-8に変換しなければならず、しかもときに失敗することがあります。外部データを常にUTF-8にしておくことをぜひお勧めします。
外部データのエンコードが不統一な場合によく起きる症状としては、たとえば画面に黒い菱型◆と疑問符が表示されるというものがあります。他にも、"ü"という文字のはずが"ü"という文字に変わっている、などの症状もあります。Railsではこうした問題を緩和するため、問題の原因を自動的に検出して修正するために内部で多くの手順を行っています。しかし、UTF-8で保存されていない外部データがあると、Railsによる自動検出/修正が効かずに文字化けが発生することがあります。
UTF-8でないデータの主な原因は以下の2つです。
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。