以下の内容はhttps://kamatimaru.hatenablog.com/entry/2026/01/03/223221より取得しました。


RailsでActiveRecordのfind_byにモデルのインスタンスを渡すとidに変換される

RailsActiveRecordのfind_byにモデルのインスタンスを渡すとidに変換されるという仕様を発見しました。実務に役立つことはあまりなさそうですが、面白かったのでメモしておきます。

検証

まずは任意のモデルのインスタンスを取得します。

app(dev):004> o1 =  Restaurant.find(1)
  Restaurant Load (36.1ms)  SELECT "restaurants".* FROM "restaurants" WHERE "restaurants"."id" = 1 LIMIT 1 /*application='App'*/
=>
#<Restaurant:0x0000ffff83253a18
...

次にfind_byでキーにid、値にモデルのインスタンスであるo1を渡します。

Restaurant.find_by(id: o1)

idの値が不適切ということでエラーが送出されるのかと思いきや、以下のようにモデルのインスタンスのidに変換してSQLを発行してくれています。

app(dev):009> Restaurant.find_by(id: o1).id
  Restaurant Load (3.2ms)  SELECT "restaurants".* FROM "restaurants" WHERE "restaurants"."id" = 1 LIMIT 1 /*application='App'*/
=> 1
app(dev):010>

キーがidである必要もありません。

app(dev):007> Restaurant.find_by(name: o1)
  Restaurant Load (11.5ms)  SELECT "restaurants".* FROM "restaurants" WHERE "restaurants"."name" = '1' LIMIT 1 /*application='App'*/
=> nil

ちなみにfindメソッドの対して同様のことを試すとエラーになります。

app(dev):005> Restaurant.find(o1)
(app):5:in '<main>': You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (ArgumentError)

          raise ArgumentError, <<-MSG.squish
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Railsソースコードの裏付け

Rails本体のソースコードを読むと、以下の辺りで検索条件の値がidメソッドを持っている場合はそれを呼ぶということをやっているのが伺えます。

def find_by(*args) # :nodoc:
  # 省略
  if !reflection
    value = value.id if value.respond_to?(:id)
  elsif reflection.belongs_to? && !reflection.polymorphic?
    key = reflection.join_foreign_key
    pkey = reflection.join_primary_key

github.com

きっかけ

Sidekiqのワーカーの引数にオブジェクトを渡しているコードのリファクタリングで、エラーになるはずと思っていたコードがなぜか通ったことから不思議に思い調べました。




以上の内容はhttps://kamatimaru.hatenablog.com/entry/2026/01/03/223221より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14