最近Ruby on Railsばかりなので、今回もRailsのお話。
何も考えずに特定のIDのレコードを見つける際は、「ActiveRecord::Base#find」という超基本メソッドを使うけれど、同時に、XXXというフィールドに対して「ActiveRecord::Base#find_by_XXX」なるメソッドも定義されているので、「ActiveRecord::Base#find_by_id」でも同じようにidに紐付けて見つけ出せる。
以上は当たり前の話だが、この同じような2つ、重要なところが違う。すなわち、そのIDに紐付くレコードが存在しない場合。
「ActiveRecord::Base#find」は例外が生じる。
1 2 3 4 5 6 7 | Post.find(1) #=> ActiveRecord::RecordNotFound: Couldn't find Post with ID=1 # from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1586:in `find_one' # from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1569:in `find_from_ids' # from /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:616:in `find' # from (irb):6 # from :0 |
「ActiveRecord::Base#find_by_id」は nil を返す。
1 2 | Post.find_by_id(1) #=> nil |
このお話はそれなりに有名なようですが、find_by_idを使えば、例えばこういうコードが書けて気分がいいですね。
1 | (m = ItemMaster.find_by_id(params[:id])) ? m.item_name : params[:id] |
このワンライナーが多発するぐらいなら、item_master.rb にクラスメソッドを定義するべきだとは思うけど。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class PostController < ApplicationController #例えばブログで def show @post = Post.find_by_id(params[:id]) if !@post flash[:notice] = "ブログ記事が存在しません: #{params[:id]}" redirect_to :action => :index return end respond_to do |format| format.html #... end end end |
こっちは幾分か実用的な気がする。IDが存在しないだけで 503 500 になって精神衛生状態が悪くなるのを回避できます。むしろ404を返してもいい(参考: http://d.hatena.ne.jp/NeoCat/20080604/1212599193)。
この挙動は、少なくともRails 2.2.2とRails 2.3.5でこうなることを確認しています、よしなに。
あと、ちゃんとソース読んでないのでなんですが、「find_by_XXX」系メソッドは内部でmethod_missingを呼んでるとかいう話なので、当然ただのfindよりオーバヘッドがかかります(特にRuby 1.9系)。なんでもfind_by_idに置き換えるべきではないでしょう。
Pingback: method_missing内でsuperすると « **deadwinter**