お待たせしました。後編です。一週間で書くつもりが一ヶ月かかりました><
Rails 3.0 リリースノート和訳 - 前編 - おもしろWEBサービス開発日記
7 Action Pack
Action Packには重要な変更が(内部的にも外部的にも)あるよ。
7.1 Abstract Controller
Abstract Controller は Action Controller の一般的な部分を取り出して他のライブラリでも使えるモジュールにしたものだよ。これによって他のライブラリで
- render template
- render partials
- helpers
- translations
- logging
- リクエストがきてレスポンスを返すサイクル全般
ができるようになったよ。この抽象化によって ActionMailer::Base が AbstractControllerを継承して Mail gem に Rails DSLを単にラップしたものになったよ。
また抽象化の過程でAction Controllerのソースが綺麗になったよ。
Abstract Controller は ユーザが叩けるAPIは提供してないよ。普通にRailsを使ってる限りはAbstract Controllerのことを意識することはないよ。
詳しくはこちら
7.2 Action Controller
cookie関連の修正
注意: この章は意訳やid:willnetの個人的な追記部分が強めです
が追加されたよ。
下記はCHANGE LOGの抜粋です。
cookies.permanent[:prefers_open_id] = true # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT cookies.signed[:discount] = 45 # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/ cookies.signed[:discount] # => 45 (if the cookie was changed, you'll get a InvalidSignature exception) cookies.permanent.signed[:remember_me] = current_user.id # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
上記のCHANGE LOGを見るとわかるように、
- cookies.parmanentを使うとexpiresが20年後に設定される
- cookies.signedを使うとcookieが暗号化され、署名が付けられる
- cookies.signed利用時に改ざん検知するとInvalidSignature
- cookies.parmanent.signedとすることで両方同時に使える
となるようです。また、cookies.signedの署名に使われる鍵は initializers/cookie_verification_secret.rb で設定されています
参考
Commit 0200e20f148c96afceeebc4da7b5985643f9f707 to rails's rails - GitHub
has_many :bugs, :through => :rails: Signed and Permanent cookies in Rails 3
config 関連の修正
session_store の設定は initializers/session_store.rb に移動したよ
respond 関連の修正
:notice => 'This is a flash message' や :alert => 'Something went wrong'が respond_to ブロックの中の format call に渡せるようになったよ。これまでのflash[]もまだ使えるよ。
たぶんこういう感じで使うはず・・(ぐぐっても情報無かったので間違ってたらすいません><)
class UsersController < ApplicationController def index @users = User.all respond_to do |format| format.html(:notice => 'This is a flash message') # format.html(:alert => 'Something went wrong') format.xml { render :xml => @users } format.json { render :json => @users } end end end
respond_with メソッドがControllerに追加されたよ。 これでこれまで下記のように書いていたのが
class UsersController < ApplicationController def index @users = User.all respond_to do |format| format.html format.xml { render :xml => @users } format.json { render :json => @users } end end end
下記のように書けるようになってすっきりするよ。
class UsersController < ApplicationController respond_to :html, :xml, :json def index @users = User.all respond_with(@users) end end
新しく追加された ActionController::Responder を使うと responseを作るのが楽になるよ
その他
application_controller.rb は protect_from_forgery がデフォルトでonだよ
class ApplicationController < ActionController::Base protect_from_forgery end
rails3.0のapplication_controller.rbやたらすっきりしましたね
非推奨になったもの
パスワードなどそのままログに出力すると問題のある文字列を"[FILTERED]"のように置換してくれるメソッド filter_parameter_logging が config.filter_parametters << :password になったよ
詳しくはこちら
Render Options in Rails 3
Three reasons to love ActionController::Responder
7.3 Action Dispatch
Action DispatchはRails3.0で新しく提供された、きれいなルーティング用の実装だよ。
railsのルーティング用の実装を書き直した結果、rack_mountというRack用のスタンドアローンなソフトウェアにRailsのDSLを乗っけたものになったよ。
それぞれのアプリのルーティングの定義はアプリケーションのモジュールの中の名前空間で分けられるよ。つまりもともと下記のように書いてたのが
ActionController::Routing::Routes.draw do |map| map.resources :posts end
こんな風に書けるようになったよ
AppName::Application.routes do resources :posts end
ルーティング定義用に match メソッドが追加されたよ。このメソッドで、マッチしたルートに対してRackアプリを割り当てることができるよ。→下記のように書くと/homeにリクエストを投げたときにHomeApp(Sinatra)を動かすことが出来るみたいです。
class HomeApp < Sinatra::Base get "/" do "Hello World!" end end Basecamp::Application.routes do match "/home", :to => HomeApp end
matchメソッドを使った通常のRailsのルーティングは下記のような感じになるようです。
Basecamp::Application.routes do match "/main/:id", :to => "main#home" # => MainController#homeが実行される end
ルーティング定義用に constraints メソッドが追加されたよ。制限を定義してルーティングを守ることが出来るよ。→下記のように、constraintsメソッドでsubdomainのルーティングが出来るみたいです。
Basecamp::Application.routes do constraints(:subdomain => "support") do match "/foo/bar", :to => "foo#bar" end end
scopeメソッドが追加されたよ。異なる言語やaction用に名前空間ルーティングを定義できるよ。
scopeメソッドの例
scope 'es' do resources :projects, :path_names => { :edit => 'cambiar' }, :as => 'projeto' end # edit アクションは /es/projeto/1/cambiar として定義される
root メソッドが match '/', :to => pathの省略形として追加されたよ
matchメソッドの中でオプションのパスを設定できるようになったよ。下記の例で括弧でくくられた部分はオプションになるよ。
match "/:controller(/:action(/:id))(.:format)"
ルーティングはブロック経由でも表現できるよ。
例: 下記の二つは同じ。インラインでも書けるし
match "/:action", :to => "main"
ブロックでも書ける
controller :home { match ‘/:action’ }
これまでのmapメソッドを使ったやり方はまだ使えるけど3.1では出来なくなるよ。
非推奨なもの
- RESTでないルーティング(/:controller/:action/:id)はコメントアウトしたよ
- :path_prefixは無くなったよ。
- :name_prefixは自動的に"_"が最後につくようになったよ。
詳しくはこちら
The Rails 3 Router: Rack it Up « Katz Got Your Tongue?
Revamped Routes in Rails 3 | Rizwan Reza
Generic Actions in Rails 3 « Katz Got Your Tongue?
7.4 Action View
Action Viewのヘルパーで主に書き直されたのは、Unobtrusive JavaScript(UJS)のフックの実装と古いインラインAJAXメソッドを削除したとこ。これによりヘルパー内でUJSのドライバーが使えるようになったよ。
ちなみにUnobtrusive JavaScriptとは、簡単に言うと"HTMLからJavaScriptを分離してHTMLを綺麗に保つ"みたいな考え方です。
remote_ なヘルパーはRailsコアから削除してprototype_legacy_helperに入れたよ。UJSのフックが欲しいときには
form_for @post, :remote => true
のようにする。そうすると下記のようなHTMLが出力されるよ。
<form action="http://host.com" id="create-post" method="post" data-remote="true">
上記HTML中の"data-remote"はHTML5のカスタム属性で、"true"に設定されているとAJAXでリクエストをすることを示すようです。設定しておけばあとはブラウザが勝手にリクエストを投げてくれる訳ではなく、実際の動作はJavaScriptで定義することになるようです(たぶん)
HTMLの出力をエスケープするために、これまではhメソッドを使ってたけど、hメソッドがデフォルトになったので明示的に使う必要はなくなったよ。エスケープしたくないときにはraw()メソッドを使うといいよ。
ヘルパーの出力はデフォルトでHTML5だよ
label ヘルパーは引数が一つの時I18nで翻訳した結果を返すよ。f.label :nameだったら :name の翻訳を出力するよ
:en.support.select が :en.helpers.selectに変わったよ
ERbの改行を削除するために<% -%>の"-"をする必要がなくなったよ
grouped_collection_select ヘルパーが追加されたよ(訳注:2.3.5にも同名のヘルパーメソッドがあるようなのですが・・・何か変更されたんでしょうかね?)
javascript_include_tag と stylesheet_include_tagで宣言されたファイルが見つからない時は例外を出すよ
content_for? メソッドが追加されて、viewを描画する前にcontentが存在するかチェックするよ。
8 Active Model
Active ModelはRails3.0で新しく登場したよ。Active Modelのインターフェースを使うことで、RailsでいろんなORMのライブラリが使えるようになるよ。
8.1 ORM の抽象化と Action Pack のインターフェース
疎結合の結果 Active Record と Action Pack は完全に切り離されたよ。全てのORMプラグインはActive Model のインターフェースだけ叩けば Action Pack ともシームレスに動くよ。
詳しくはこちら
8.2 Validations
validationsはActive RecordからActive Modelに移されたよ。ORMライブラリのインターフェースを提供するよ。
validates :attributes options_hash という既存の validates_xxx 系のメソッドのショートカットとなるメソッドが追加されたよ。オプション引数は下記のようなものがとれるよ
key | value |
---|---|
:acceptance | boolean |
:confirmation | boolean |
:exclusion | {:in => Enumerable } |
:inclusion | {:in => Enumerable } |
:format | { :with => Regexp, :on => :create} |
:length | {:maximum => Fixnum} |
:numericality | boolean |
:presence | boolean |
:uniqueness | boolean |
rails 2.3スタイルのvalidationメソッドは3.0でも使えるよ。validatesメソッドはあくまで新しく追加されたメソッドで、これまでのメソッドを置き換えるものではないよ。
validatorオブジェクトはActive Modelを使うオブジェクト間で再利用できるよ
class TitleValidator < ActiveModel::EachValidator Titles = ['Mr.', 'Mrs.', 'Dr.'] def validate_each(record, attribute, value) unless Titles.include?(value) record.errors[attribute] << 'must be a valid title' end end end
上記のような TitleValidator クラスを定義すると、下記のように ActiveModel::Validations を includeしているクラスで validatesメソッドを :title => true の引数付きで実行したときに、TitleValidatorクラスのvalidate_eachメソッドが実行されるようです。
class Person include ActiveModel::Validations attr_accessor :title validates :title, :presence => true, :title => true end # Active Recordの場合はこう書ける class Person < ActiveRecord::Base validates :title, :presence => true, :title => true end
これにより複数クラス間でcustom validationを使い回すことが出来ます。
詳しくはこちら
9 Active Record
Active Record は Rails 3.0 で、 Active Modelに抽象性を移行させたのと、クエリのインタフェースをArelを使って更新させたこと、validation のアップデートと多くの修正とエンハンスで注目の的だよ。全てのRails 2.x のAPIは3.1まで互換性をサポートされるよ。
9.1 Query Interface
Arelを使ってるActive Recordは、コアメソッドを使うと関連を返すよ。Rails 2.3.xのAPIはまだサポートされて、3.1までは非推奨にはならないよ。でも 3.2では削除されるよ。新しいAPIは、下記のメソッドを提供するよ。これらのメソッドは関連を返してメソッドチェーンできるよ。メソッドの説明は名前の通りなので省略します。
- where
- select
- group
- having
- joins
- order
- limit
- from
- clause
- includes
- lock
- readonly
- scope
- with_scope
- default_scope
詳しくはこちら
9.2 Enhancements
9.3 Patches and Deprecations
Active Recordはたくさん修正されてるよ
- SQLite2のサポートが無くなったよ。SQLite3使ってね。
- MySQLがcolumn orderをサポートするよ。
- PostgreSQL adapterはTIME ZONEサポートを修正して、不正確な値が入らないようになったよ。
- PostgreSQLでテーブル名に複数のスキーマをサポートするようになったよ。
- PostgreSQLでXML data型のカラムをサポートするようになったよ
- table_nameがキャッシュされるよ
- Oracle adapterがいろいろ修正されてたくさんバグが直ってるよ
named_scopeはscopeに名前が変わったよ。scopeメソッドは下記のような感じで使うよ。
scope :since, lambda { |time| where("created_at > ?", time) }
save(false)が非推奨になって、save(:validate => false)になったよ
ActiveRecordのI18nでのエラーメッセージの定義はen.activerecord.errors.templateからen.errors.templateに変わったよ。
model.errors.onは非推奨になって、model.errors[]になったよ
validates_presence_of がvalidates ... :presence => trueになったよ
ログに色を付けてくれる設定の ActiveRecord::Base.colorize_logging と config.active_record.colorize_logging が非推奨になって、Rails::Subscriber.colorize_logging か config.colorize_logging に変わったよ
Stete Machineの実装が数ヶ月されてたけど、3.0の時点では削除されているよ。
10 Active Recource
Acrive Recource もまたActive ResourceオブジェクトをAction Packでシームレスに使うために ActiveModel に切り出されたよ。
validations は Active Model に追加されたよ
- observing hooksが追加されたよ
- HTTP proxyをサポートするよ
- digest autehticationのサポートを追加したよ
- modelの名前をActive Modelに移動したよ
- 通常のアクセスでのActive Recourceの属性をHashに変更したよ
- first, last, allメソッドを追加したよ
- find_every は何も返さないときにResourceNotFoundエラーを返さなくなったよ
- save! オブジェクトが追加されたよ。オブジェクトがvalid?でfalseになるときに RecourceInvalidになるよ。
- Active Recource modelにupdate_attribute とupdate_attributesが追加されたよ
- exists?メソッドが追加されたよ
- SchemaDefinitionがSchemaに変更されたよ
- define_schemaがschemaに変更されたよ
- load errorの時に、content-typeを使うのではなくてActive Recourceのformatメソッドを使ってね
- schemaブロックではinstance_evalを使ってね
- @responseがcodeメソッドかmessageメソッドを持たない場合のActiveResource::ConnectionError#to_sを修正してRuby1.9互換にしたよ。
- JSONフォーマットのエラーサポートを追加したよ
- loadメソッドが数値の配列を確実に返すようにしたよ
- リソースが削除されたときに410のレスポンスを返すよ
- Active Recourceの接続にSSLオプションが追加できるようになったよ
- connection timeoutの設定がNet::HTTPのopen_timeoutに影響するよ
非推奨になったもの
11 Active Support
Active Supportは超がんばったおかげで好きな部分を使えるようになったよ。つまりActive Supportライブラリの一部を使いたいときに、Active Supportを全部requireする必要がないってことだよ。これによりRailsコアコンポーネントをスリムに出来るよ。
Active Supportの主な変更は下記だよ
- ライブラリ中の使ってないメソッドを削除したよ
- Active SupportはもうTZInfo, Memcache ClientとBuilderを提供しないよ。これらは全て独立していて、bundle installでインストールするよ。
- ActiveSupport::SafeBufferにsafe bufferが実装されたよ
- Array.uniq_by とArray.uniq_by!が追加されたよ
- TimeZone.seconds_to_utc_offsetが間違った値を返すバグを修正したよ
- ActiveSupport::Notifications middlewareを追加したよ
- ActiveSupport.use_standard_json_time_formatがデフォルトでtrueだよ
- ActiveSupport.escape_html_entities_in_jsonがデフォルトでfalseだよ
- Intenger#multiple_of? が0を引数として受け取って、レシーバが0出なければfalseを返すよ
- string.charsがstring.mb_charsに変わったよ
- ActiveSupport::OrderdHashはYAMLをデシリアライズできるよ
- XmlMini用のSAXベースのパーサを追加したよ。LibXMLとNokogiriを使ってるよ。
- Object#presenceが追加されたよ。object#present?がtrueだったらobjectを返してそうでなければnilを返すよ。
- String#exclude?が追加されたよ。include?の逆を返すよ。
- DateTimeにto_iが追加されたので、modelのDateTime属性でto_yamlが正しく動くよ。
- Enumerable#exclude?が追加されたよ。Enumerable#include?の逆だよ
- XSSエスケープがデフォルトに変わったよ
- ActiveSupport::HashWithIndifferentAccessで深いmergeをサポートしたよ
- Enumerable#sumが全てのenumerableで(sizeが無くても)動くようになったよ。
- 0.seconds などの 0の時間の長さのオブジェクトのinspectメソッドは空文字列でなくて'0 seconds'を返すよ。
- Modelnameのメソッドとしてelementとcollectionが追加されたよ(:例 Post.model_name.collection # => "posts")
- String#to_timeとString#to_datetimeがコンマ秒以下を扱うよ。
- beforeメソッドとafterメソッドを定義している around filter オブジェクトのための新しいコールバックをサポートするよ。
- ActiveSupport::OrderdHash#to_aメソッドが整列された配列を返すよ。Ruby1.9のHash#to_aに合わせているよ。
- MissingSourceFileは定数として存在するけど今はLoadErrorと同じだよ。
- クラスレベルの属性の値をサブクラスで継承/オーバライド可能にするためにClass#class_attributeが追加されたよ。
- ActiveRecord::Associations中のDeprecatedCallbackがついに削除されたよ。
下記のメソッドはRuby1.8.7や1.9で使えるので削除されたよ
- Integer#even? と Integer#odd?
- String#each_char
- String#start_with? と String#end_with? (starts_with? と ends_with?はそのまま使えるよ)
- String#bytesize
- Object#tap
- Symbol#to_proc
- Object#instance_variable_defined?
- Enumerable#none?
REXMLのセキュリティパッチはActive Supportに残ってるよ。理由は若いpatchlevelのRuby 1.8.7にはまだ必要だからだよ。Active Supportはそれが適用される必要があるか無いかを知ってるよ。
下記のメソッドは使う必要がもう無いので削除されたよ。
12 Action Mailer
Action Mailer は 利用するライブラリが TMail から Mail に変わって、新しいAPIになったよ。Action Mailerはほぼ全部書き換えられたよ。結果としてAction Mailerは単純にAbstract Controllerを継承して、Mail gemにRails DSLをラップしたものになったよ。これで他のライブラリとの重複が減ってコードの量が減ったよ。
- 全てのmailerはデフォルトでapp/mailersに配置されるよ。
- メール送信に新しい三つのメソッドが使えるよ。attachments, headers, mailの三つ。
- Action Mailer のメールメソッドは Mail::Message オブジェクトを返すようになったよ。このオブジェクトは deliver メソッドで自分自身を送るよ。
- 全ての送信系のメソッドは抽象化されて Mail gem へ移されてるよ
- 全ての送信系のメソッドはvalidなメールヘッダと値のハッシュを受け取るよ。
- 送信系のメソッドはAction Controllerのrespond_toと同じような方法で動くよ。明示的でも暗黙的でもtemplatesが使えるよ。Action Mailerは必要に応じてmultipart emailになるよ。
- mail ブロックの中で、format.mime_typeを使ったり、render でテキストを指定したりlayoutsやtemplateを指定したり出来るよ。procの中にrenderが書けるのはAbstract Controllerからきていて、サポートしてるoptionも同じだよ。
- mailerのunit testはfunctional testに移動したよ。
非推奨になったもの
- :charset, :content_type, :mime_version, :implicit_parts_order は全て非推奨で、ActionMailer.default :key => value のスタイルがが推奨だよ。
- create_メソッド名 と deliver_メソッド名 は非推奨で、単に メソッド名 を使ってMail::Messageオブジェクトを取得するようにするのが推奨だよ。
- ActionMailer.deliver(message)は非推奨で、message.deliverが推奨だよ。
- template_root は非推奨で、mailを生成するブロック中のformat.mime_typeメソッドに渡すブロック中のrenderにオプションを渡すのが推奨だよ。
- インスタンス変数をbodyメソッド中で使う形 (body {:ivar => value} の形) は非推奨になったよ。インスタンス変数はメソッド中で直接宣言すればviewの中で使えるようになったよ。
- Mailerは app/models から app/mailersに移行したよ。
詳しくはこちら