#400 What's New in Rails 4
- Download:
- source codeProject Files in Zip (42.4 KB)
- mp4Full Size H.264 Video (47.9 MB)
- m4vSmaller H.264 Video (23.6 MB)
- webmFull Size VP8 Video (24.5 MB)
- ogvFull Size Theora Video (52.5 MB)
Railsの次のメジャーバージョンの公開がいよいよ近づいてきました。今回のエピソードはちょうど第400回なので、Rails 4.0の新機能を取り上げるいい機会でしょう。この記事の公開時にはまだgemのプレリリース版は出ていません。中身を見てみるにはマスターブランチをチェックアウトする必要があるので、Githubからcloneします。次にディレクトリを移動して、bundleコマンドを実行して依存関係をインストールします。Rails 4を実行するためには、Ruby 1.9.3以上が必要なので注意してください。
$ git clone https://github.com/rails/rails.git $ cd rails $ bundle
Bundlerのバージョンが正しくないというエラーが出た場合は、次の方法でプレリリース版をインストールします。
$ gem install bundler --pre
インストールができたら再度bundle
を実行します。それが完了したら、最初のRails 4アプリケーションを作成することができます。ダウンロードしたRailsのrailties/bin/
ディレクトリからrails
コマンドを実行して、Edge Railsを使用するよう指定して、blog
という名前の新規のアプリケーションを作成します。後でPostgres関連の新しい機能を試すのでデータベースはPostgresを指定します。
$ railties/bin/rails new ~/code/blog --edge -d postgresql
Rails 4 gemのプレリリース版が公開されたらこの作業はずっと簡単になるでしょう。gem install rails --pre
のようなコマンドを実行して通常の方法でRails 4のアプリケーションを作成することができるようになります。このgemをインストールしたら、バージョン番号を指定することで新規のRails 3.2のアプリケーションを作成することもできます。
$ rails _3.2.10_ new my_app
Postgres関連の新機能
Rails 4アプリケーションを新規作成する方法がわかったら、次にその中身を見ていきましょう。新機能を見る前にデータベースを設定します。まず最初に、database.yml
ファイルの各データベースからユーザ名のオプションを削除して、アプリケーションがPostgresデータベースに接続できるようにします。これでrake db:create
を実行することでアプリケーションのデータベースを作成することができます。(RailsアプリケーションでPostgresqlを使用するための設定方法についての詳細はエピソード342を参照してください。)
次にArticle
のscaffoldを作成して、アプリケーションになんらか操作を行なうための対象を準備します。Rails 4はPostgresのネイティブのデータ型をサポートします。多くの型がサポートされていますがここではその中の2つ、arrayとhstoreについて紹介します。arrayを文字列型のカラムに保存する場合には、型をhstoreに設定します。
$ rails g scaffold article name content:text published_on:date tags properties:hstore
データベースのマイグレーションを行なう前に、migrationファイルを少し修正して、 tags
カラムをarrayとして処理するようにします。そのためにarray
オプションを追加してtrue
に設定します。hstoreを利用できるようにするためには、テーブルを作成する前にexecute "create extension hstore"
を実行します。
class CreateArticles < ActiveRecord::Migration def change execute "create extension hstore" create_table :articles do |t| t.string :name t.text :content t.date :published_on t.string :tags, array: true t.hstore :properties t.timestamps end end end
rake db:migrate
を実行するとテーブルが作成されます。Rails 4でPostgresデータベース用にマイグレーションを実行すると、ログメッセージが表示されなくなったので以前のように画面がうるさくなくなりました。次にコンソールでこれらのデータ型がどう処理されるかを見てみましょう。まず最初にArticle
を新規に作成します。tags
にRuby arrayを渡すとPostgres arrayに変換され、properties
に対してはhashを渡します。
>> Article.create! name:"Hello", tags: %w[ruby rails], properties: {author:"Eifion"}
これらの属性を後で取得すると、arrayとhashが得られますが、どちらに対しても問題なくやり取りができます。テキストカラムをシリアライズするやり方でも確かに同じことをできますが、このアプローチの方がこれらのカラムとのやり取りをずっと効率的に処理できます。hstoreの詳細についてはエピソード345を参照してください。
ActiveRecordの新機能
次にActiveRecordに関するいくつかの新機能を見ていきます。まず最初はall
メソッドです。このメソッドは今までは結果のarrayを返していましたが、新たにActiveRecord relationを返します。つまりlazy loadingされるようになったことで、実際に必要になったときに初めてデータベースクエリが起動されます。これによって機能が置き換えられることになるscoped
の存在意義はなくなります。もし結果のarrayを取得するために古い機能が必要な場合には、ActiveRecord relationに対してto_a
を呼び出します。これは以前のバージョンのRailsのallと同じことを行ないます。
これと一緒に準備されたもう一つの新しいメソッドがload
です。これはデータベースクエリを起動しますが、結果のarrayの代わりにActiveRecord relationを返します。これは例えば、キャッシュ的な振る舞いのためにクエリを起動したいが結果としてはrelationを返してほしい、という場合には便利です。また、新たにレコードがないActiveRecord relationを返すnone
メソッドも準備されました。レコードを返したくはないが他のscopeを呼び出すために何かが必要なときに、これは役に立ちます。scopeに関してもう一つ言えば、where scopeに対してnotを呼び出して結果を反転できるようになりました。
>> Article.where.not(name: "Hello") Article Load (107.6ms) SELECT "articles".* FROM "articles" WHERE ("articles"."name" != 'Hello')
order
句がhashを受け付けるようになったので、カラム名とソート順を渡して結果を得ることができるようになりました。また複数のカラム名を渡して、ソートをかけることも可能になりました。もう一つの便利な新しいメソッドがfind_by
です。今までも、find_by_name
のようなdynamic finderを使用することはできましたが、これらはmethod_missing
に依存していて、あまりきれいな実装ではありませんでした。Rails 4では、hashを渡すことができるfind_by
メソッドが導入されました。例を以下に示します。
>> Article.find_by name: "Hello"
また新たにfind_or_create_by
とfind_or_inititalize_by
の各メソッドが準備されたので、こちらを使用することが推奨されます。
ActiveModel::Model
もうひとつの興味深い新機能は、ActiveModel::Model
と呼ばれる新しいモジュールです。例えば新規にActiveModelオブジェクトのようなクラスを作成してその属性をフォームから更新したいが、データベースには置きたくないという場合があるとします。クラス内でActiveModel::Model
をincludeしたら、そのメソッドに対して自由にattr_accessors
を設定でき、ActiveRecordに対してのようにvalidationを追加することも可能です。そしてこのクラスのインスタンスを作成して、その属性とやり取りすることができます。実際は単なるRubyクラスであるにも関わらず、ActiveRecordモデルと同じように扱えます。
>> class Message >> include ActiveModel::Model >> attr_accessor :name, :content >> end => nil >> m = Message.new(name: "foo") => #<Message:0x007ff5dca1e760 @name="foo"> >> m.name => "foo"
これは以前はActiveModelを使用することで可能でしたが、各種のモジュールをincludeする必要がありました。Rails 4ではこれはずっと簡単になりました。form_for
の呼び出しにカスタムクラスを渡したい場合には特に便利です。
Gemfileの変更点
コンソールの話題はここまでにして、新規のアプリケーションのホームページにアクセスしたときに表示されるwelcomeページを見てみましょう。このページは前と同じように見えますが、Rails internalによって動的に生成されています。これによって、アプリケーションからpublic/index.html
ページを削除する必要がなくなりました。次にgemfileを見ていきます。デフォルトのgemfileは以下のようになっています。
source 'https://rubygems.org' gem 'rails', github: 'rails/rails' gem 'arel', github: 'rails/arel' gem 'activerecord-deprecated_finders', github: 'rails/activerecord-deprecated_finders' gem 'pg' # Gems used only for assets and not required # in production environments by default. group :assets do gem 'sprockets-rails', github: 'rails/sprockets-rails' gem 'sass-rails', github: 'rails/sass-rails' gem 'coffee-rails', github: 'rails/coffee-rails' # See https://github.com/sstephenson/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby gem 'uglifier', '>= 1.0.3' end gem 'jquery-rails' # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks gem 'turbolinks' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 1.0.1' # To use ActiveModel has_secure_password # gem 'bcrypt-ruby', '~> 3.0.0' # Use unicorn as the app server # gem 'unicorn' # Deploy with Capistrano # gem 'capistrano', group: :development # To use debugger # gem 'debugger'
最初の3つのgemは、Edge Railsを使用しているために含まれているものです。assetsグループにsprockets-rails
gemが新たに加わりました。これはSprocketsのリファクタリングによってその一部が独立したgemに切り離されたからです。gemfileにはさらに新たにturbolinks
gemが含まれています。このgemの詳細についてはエピソード390を参照してください。turbolinksはデフォルト状態では有効化されていますが、削除するのは簡単です。gemfileからgemを削除し、app/assets/javascripts/application.js
ファイルからturbolinksの行を削除して、最後にアプリケーションのレイアウトファイルからdata-turbolinks-track
への参照を削除します。この属性はエピソード390が書かれた後に追加された新しいものです。Turbolinkはこの属性でアセットを監視し、変更を見つけたらページ全体をリロードします。
次にコントローラを確認して、scaffoldで何が生成されたかを見てみましょう。
class ArticlesController < ApplicationController before_action :set_article, only: [:show, :edit, :update, :destroy] # Some methods omitted. # PATCH/PUT /articles/1 # PATCH/PUT /articles/1.json def update respond_to do |format| if @article.update(article_params) format.html { redirect_to @article, notice: 'Article was successfully updated.' } format.json { head :no_content } else format.html { render action: 'edit' } format.json { render json: @article.errors, status: :unprocessable_entity } end end end private # Use callbacks to share common setup or constraints between actions. def set_article @article = Article.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def article_params params.require(:article).permit(:name, :content, :published_at) end end
ここでは多くの変更が行なわれています。scaffoldはレコードをbefore filterをつかってロードするようになりました。ただし名前がbefore_filter
ではなくbefore_action
に変わります。実行される内容は同じです(希望すればbefore_filter
を使い続けることも可能です)がbefore_action
が新しい標準になりそうです。次の標準ということで言えば、updateアクションはPUTリクエストかPATCHリクエストのいずれかにレスポンスを返すようになります。PATCHの方がupdateアクションの振る舞いによりフィットしているように思いますが、PUTが使われなくなるまでにはまだ時間がかかるでしょう。アクションでは、モデルに対するupdate_attributes
メソッドの名前がupdate
に変更されました。ただし、update_attributes
の方もまだdeprecation warning(非推奨の警告)なしに利用できます。最後に、strong parameterのサポートが標準になりました。このアプローチの方がattr_accessible
よりもずっと優れたソリューションです。これについてはエピソード371で説明しました。strong parameterに関する情報を得るためにぜひ参照することをお勧めします。これによってモデル内のattr_accessible
の行は不要になりました。ただしこの機能を戻したいという場合はProtected Attributes gemを使って追加することができます。
モデルの話が出たところで、scopeについても触れておきます。以前は、例えば以下のように、別のscopeを2つ目の引数として渡すことができました。
class Article < ActiveRecord::Base scope :sorted, order(:name) end
今後は呼び出し可能なオブジェクト(例えばlambda)を2番目のオブジェクトとして渡す必要があります。これは、2番目の引数に例えばcurrent timeのような動的な値を無意識に使用してしまうケースが頻繁に起こってしまったことへの対策で、これがランタイム時に常に評価されるようになったことでその問題を回避できるようになりました。
class Article < ActiveRecord::Base scope :sorted, -> { order(:name) } end
Concern
controllers
とmodels
の各ディレクトリの下に新たにconcerns
というディレクトリができました。これはモデル内をモジュール化することによって、モデルのサイズを減らすことを目的としたものです。同じ目的のための異なるアプローチの一つにservice objectがあります。これについてはエピソード398を参照してください。concernを強制的に使用しなくてはいけない理由はないので、不要であればconcernsディレクトリを削除しても問題ありません。
ビュー関連の変更点
ビューは何が変わったのでしょうか? フォームフィールドを生成するための新しいヘルパーメソッドが追加されたことにより、かなり機能が増えました。collection用のメソッドもその中の一つです。従来は関連(association)からselect menuを作成するためのcollection_select
というヘルパーメソッドがありました。collection_check_boxes
とcollection_radio_buttons
を利用して、関連のデータからのチェックボックスやラジオボタンのリストを生成することができます。チェックボックスのリストを生成する機能は、多対多の関連のため、あるいはArticle
のtagsのようなarray型の属性のためには便利です。属性の名前、値のコレクション、名前とidを渡します。
<div class="field"> <%= f.collection_check_boxes :tags, %w[ruby rails design], :to_s, :to_s %> </div>
これで、記事を編集あるいは新規作成するときに、タグを設定するためのチェックボックスのリストを表示することができます。
多対多の関連をチェックボックスで処理することが、これによってずっと簡単になりました。
別のHTML 5のインプット型用のヘルパーメソッドもあります。例えば、date_select
フィールドをdate
フィールドに変更します。これはあるブラウザではテキストフィールドとして表示されますが、その他のブラウザでは日付セレクタとして処理されます。例えばChromeでは、ドロップダウンカレンダーが表示されてそこから日付を選択できます。ここでRailsは特別なことをしている訳ではなく、input
要素にdate
型を付けて出力しているだけで、特別な処理はすべてブラウザ側で行なわれます。
Template handlerは、ビュー関連のもう一つの便利な新機能です。edit.html.erb
のファイル名をedit.html.ruby
(Mustacheテンプレートと衝突しないようここはrb
ではなくruby
となっている)に変更すると、純粋なRubyコードをテンプレートで使用でき、返される文字列がそのままレンダリングされます。
content_tag(:h1, "Edit") + render("form")
表示される編集用ページは以前と同じです。唯一違うところは、それが純粋なRubyコードで生成されるという点だけです。HTMLを出力するための用途としては限定的かも知れませんが、JSONフォーマットの処理のためにはこれは非常に便利です。詳細についてはエピソード379を参照してください。
Rails 4のビューに関するもう一つの新機能が、cache digestあるいはRussian doll cachingと呼ばれる機能です。詳細についてはエピソード387を参照してください。
Routes
次にアプリケーションのroutesファイルについても、いくつかの変更があったので見てみましょう。もっとも大きな新機能は、concernの追加です。これによりroutes内の重複が削減されます。例えばarticles
の下にネストされたcomments
リソースがあり、同じくphotos resource
にもネストされたcomments
があるとします。Rails 3アプリケーションでは、これらのリソースへのroutesは次のようになります。
resources :articles do resources :comments end resources :photos do resources :comments end
Rails 4では、commentsをcommentable
という名前をつけたconcernに移動させることによって、この重複を排除できます。concernの振る舞いをブロックに入れて、concerns
を呼び出すことでresourcesに追加します。
concern :commentable do resources :comments end resources :articles, concerns: :commentable resources :photos, concerns: :commentable
これは、例えばAPIを多く提供する複雑なルートのセットがあってそれら相互に重複があるという場合には、とても便利な機能です。ですが先ほどの例のように単純なものであれば、ネストされたリソースを使用したほうがいいかもしれません。
GET、POSTあるいはその他の動詞のいずれのリクエストのタイプもサポートするように、match
メソッドが利用されてきましたが、これはサポートされないことになりました。これはワールドカードによる一致をできないようにすることで、受け付けるリクエストのタイプを開発者が正しく特定することを奨励するための措置です。今後はその代わりにget
かpost
のいずれかのメソッド(あるいは新たにサポートされるpatch
)を使用するべきです。
最後に残ったのが、ルーティングに関するもっとも重要な新機能の一つです。ルートにconstraintを指定すると、URLを生成するときにそれらが自動的にデフォルトの属性になります。以下にサンプルを示します。
get 'foo', to: 'articles#index', constraints: {protocol: "https", subdomain: "test"}
以前はアプリケーションでfoo_url
を呼び出してもこの制限は含まれませんでしたが、新たに含まれるようになりました。
>> app.foo_url
=> "https://test.example.com/foo"
その他の変更点
まだいくつか紹介するものが残っています。まず最初はアプリケーションの設定ファイルです。ここで、console
の呼び出しをブロックと共に渡せるようになりました。ブロックの内容は、コンソールからRailsの環境をロードしたときに評価されます。Pryを使用する場合などのためにコンソール特有の設定を追加できます。(この設定を機能させるためにはgemfileにPryを追加する必要があります。)
console do require 'pry' config.console = Pry end
次にproductionの設定ファイル、特に以下の行を見てみましょう。
config.eager_load = true
これによってRailsアプリケーションの全体とすべてのクラスが、autoloadではなく、eager-loadされることによりthread-safeになります。以前はこの振る舞いはthreadsafe!
と呼ばれるオプションを使用することで有効化していましたが、これはユーザを新しい方法に移行させるために非推奨になりました。詳細についてはエピソード365を参照してください。
テスト
次に我々が見るのはtest
ディレクトリです。ここは構造が新たに少し変更されました。unit
とfunctional
の各ディレクトリの代わりに、RSpecと同じようにcontrollers
、models
などで構成されるようになりました。また新たにMiniTestが採用されました。
最後にdevelopmentの新しい例外エラーのページを見てみましょう。見た目が変わり、ルーティングエラーが投げられた場合に有効なルートのリストを表示するようになったのが便利です。
developmentでルーティング情報を得るもう一つの方法として、/rails/info
にアクセスします。すると同じルーティング情報の表が表示され、これとアプリケーションのプロパティの間でトグルできます。
Rails 4の紹介は以上です。優れた機能が多く含まれていますが、すべてを紹介できませんでした。Santiago Pastorinoによるこのすばらしいブログ記事に、Rails 4の新機能についての数多くの情報へのリンクがまとめられています。
Rails 4で削除された機能もいくつかあります。ActiveResource、モデルオブザーバー、ページキャッシュ、アクションキャッシュが削除され、Rack::Cache
はデフォルトでは無効化されました。これらの機能がどうしても必要という場合は、すべて各種のgemを利用することで元に戻すことができます。今回取り上げられなかった機能が、ActionController::Live
です。これについては、一回のエピソードを要する大きいテーマのため、将来のエピソードで改めて詳しく解説する予定です。非同期メールをサポートしたキューイングAPIを期待していたユーザもいたかも知れませんが、Rails 4.0からは除かれました。おそらくRails 4.1に含まれることになるでしょう。