Upgrading to Rails4 がとてもよい

書店に行ったらまだ未発売の パーフェクト Ruby on Rails が並んでいたので購入してみました。これから読んで行きます。楽しみ。

さて本題

Upgrading to Rails 4

Rails4絡みの記事 をいくつか書いてますが、いろいろ知らなかったことがあったので、個人的にはとても良かったです。Release Notes に記載がないものや、より詳細な内容や注意点と合わせてコードが掲載されていて
これからRails4 やりますみたいな人はさらっと見てみるとよいかもしれません。
 
内容としては以下のような者が掲載されています。
・Rails4へのupgrade方法
・depricationsや削除された機能
・gem化された機能の紹介
・追加された機能
・Upgrad時のエラーと対応のまとめ
 
以下気になったところをメモ。

ActiveRecord

Relation#order (p.29)

orderのchain時に発行されるORDER BYの順序が変わります。これは注意が必要。

Comment.order("replies_count DESC").order(:created_at)

-- Rails3
SELECt * FROM comments ORDER BY replies_count DESC, created_at

-- Rails4
SELECt * FROM comments ORDER BY created_at, replies_count DESC

-- Rails3/4
Comment.order("replies_count DESC", :create_at)

 

validates_format_of with ^ and $ (P31)

# app/models/post.rb
class Post < ActiveRecord::Base
  # only alphanumeric chars and the hypen allowed
  validates_format_of :slug, with: /^A[A-Za-z0-9-]+$/
end

ruby正規表現の話ですがsecurity risk軽減のために厳しくなったようです。
行の開始終了判定に^',$'を使うとArgumentErrorになります。
^',$'を利用すると改行を含めてチェックするため改行以降に
悪意のあるコードを突っ込まれる可能性があるためこれを回避するように
\A',\z'を推奨するようになっています。
改行込みのときは、:multiline => true を設定することで対応可能。
ですので、基本的には書き換えが必要と。
(まぁ、メッセージ見りゃ分かるんですが)
安全側に倒すようになっていますね。

validates_confirmation_of (P.32)

パスワード確認用項目ですが、エラーのattribute名(とデフォルトのエラーメッセージ)が変更されています。 password -> password_confirmation

# Rails3
> user.valid?
false
> user.errors[:password]
["doesn't match confirmation"]


# Rails4
> user.valid?
false
> user.errors[:password_confirmation]
["doesn't match Password"]

ですので、通常エラーメッセージ変更していると思いますので、ここも変更が必要です。
 

JSON Serialization (p.33)

to_json時の挙動が変更されています。
デフォルト config.active_support.escape_html_entities_in_json = true
がセットされるようになったため、htmlを含む場合escapeされます。
 

ActionController and ActionView

Strong Parameter (P.39)

機能については省略しますが、attr_accessible が無くなっています。strong parameter使えよってことのようです。一応、protexted_attributes gem が用意されています。

Caching

page / action cacheingは無くなりました。一応以下のgemが用意されています。
actionpack-action_caching gem
actionpack-page_caching gem

russian doll caching については Cache Digests にて後述。  

ActiveSupport

Object#try (P.46)

receiverがnilでない場合の挙動が変更されています。

# Rails3
>> nil.try(:name)
=> nil

>> "abc".try(:name)
NoMethodError: undefined method `name' for "abc":String
# Rails4
# これは一緒
>> nil.try(:name)
=> nil

# nilが返る
>> "abc".try(:name)
=> nil

# rails3と同じ挙動にしたい場合 try!
>> "abc".try!(:name)
NoMethodError: undefined method `name' for "abc":String

 

Thread Safety

defaultでthread safeが有効になっているようです。
(Rainbows!やpumaなどthread safeに対応したwebサーバが必要です。)  

config.threadsafe! and config.eager_load (P.48)

Rails3にあったconfig.threadsafe!がなくなり、以下のoptinoが設定されています。
config.cache_classes = true
config.eager_load = true
 
eager_load をfalseにすると必要になったときに読み込まれるようで
development/test はfalseになっています。しかし、thread safeでどうささせるためにはこれが有効とのこと。  

ActionController and ActionView (P.62)

ActionController::live

ActionController::Live を試す - rochefort's blog
 

Cache Digests (P.65)

fragment cacheの利用時にキー(以下の例ではv1)を設定し、変更が発生したタイミングでキーを変更する必要がありました。Rails4では、このキーを自動で設定してくれるという機能です。便利!!(というかこれまでが使いにくかった)

# Rails3
<%# app/views/whishlists/show.html.erb %>
<%- cache ["v1", @wishlist] do %>
  <h1><%= @wishlist.title %></h1>
  
  <ul>
    <%= render @wishilist.items %>
  </ul>
<%- end %>


<%# app/views/sishlists/_item.html.erb %>
<%- cache ["v1", @item] %>
  <li><%= @item.name %>(<%= @item.price %>)</li>
<%- end %>

Russian Doll Cashingについてですが、外側のkeyが変更されると自動で内側のkeyも変更されていましたが、その逆の場合、つまり内側のkeyが変更された場合、外側のkeyが変更されませんでした。
 
Rails4では、以下のように記載すればokです。

# Rails4
<%# app/views/whishlists/show.html.erb %>
<%- cache @wishlist do %>
  <h1><%= @wishlist.title %></h1>
  
  <ul>
    <%= render @wishilist.items %>
  </ul>
<%- end %>


<%# app/views/sishlists/_item.html.erb %>
<%- cache @item %>
  <li><%= @item.name %>(<%= @item.price %>)</li>
<%- end %>

 

See Also

ActionController::Live を試す
Rails 4.1 の新機能 - rochefort's blog
Ruby on Rails 4.1 Release Notes #1(Rails4.1へのupgrade方法)
"rails4" - 記事一覧