💎

ActiveRecordのfindには"123ABC"という文字列を渡しても動く

2022/04/27に公開

結論

モデルのPrimary Keyが整数の場合、Person.find("123ABC")という文字列を渡すとto_iで数値に変換され、Person.find(123)と評価される。

Person.find("123ABC")
↓ 
Person.find(123)

経緯

仮にPersonというモデルがあり、Primary Keyが整数、/persons/:idの形式で渡されるIDを使ってPerson.find(params[:id)のようにクエリを投げている処理があるという前提。

アクセスログを眺めていたら/persons/123ABCのように文字列を入れてアクセスしてきているケースがあった。
ActiveRecordのfindでは指定されたIDを持つレコードが見つからなければActiveRecord::RecordNotFoundがraiseされるはずが、普通にアクセスできてしまうことに気付く。(ID = 123のレコードのデータが表示されている)

よくよくドキュメントを読んでみると以下の記載があった。

Person.find(1)          # returns the object for ID = 1
Person.find("1")        # returns the object for ID = 1
Person.find("31-sarah") # returns the object for ID = 31

If the primary key is an integer, find by id coerces its arguments by using to_i.

https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find

to_iで数値に変換できる文字列ならいいので以下の形でも動く

Person.find(' 10')
Person.find('-10')
Person.find('+10')
Person.find('00010')
Person.find('+00010ABCDE')
↓ 全て以下と同じ結果になる
Person.find(10)

Person.find("1")のように文字列で指定しても動くのは知ってたけど、Person.find("31-sarah")のように数値以外の文字が含まれていても動くのは知らなかったので備忘録。

Discussion