📖

findとfind_byについて(セキュリティ面)

2024/04/27に公開

findを主に使用していましたが、find_byというものを知り、役割の区別がつきにくかったので、
理解のために残します。

find メソッド
IDに基づいてレコードを検索する。
見つからない場合、ActiveRecord::RecordNotFound を発生させます。

このメソッドは、主にIDを使ってデータベースからレコードを検索する際に使用されます。
例えば User.find(3) というコードは、IDが3のUserを検索し、

存在しない場合は ActiveRecord::RecordNotFound というエラーを発生させます。

このエラーは、レコードが見つからない場合に表示されます。

find_by メソッド
指定された条件にマッチする最初のレコードを返します.
見つからない場合は nil を返します。

この違いは、エラーハンドリングの戦略を決定する際に重要です。
例えば User.find_by(name: 'Kaushik') というコードは、nameが 'Kaushik' のUserを検索し、存在しない場合は nil を返します。
これにより、エラーを発生させずに、レコードが存在しない場合の条件分岐を簡単に記述できます。

エラーページを表示したい場合は find を使用します。これにより、IDに基づいてレコードが確実に存在することを保証し、存在しない場合はエラーを吐いてくれます。

エラーを回避したい場合は find_by を使用します。
これにより、例外ハンドリングを行わずに、nil チェックをすることで処理を分岐できます。
find_byを使用するのは、showとかに使用します。

この例では、

def show
  @user = User.find_by(id: params[:id])
  unless @user
    redirect_to root_path, alert: "指定されたユーザーは存在しません。"
  end
end

を使用してユーザーを検索し、ユーザーが見つからない場合にはルートパスにリダイレクトしてアラートを表示します。

セキュリティ観点からの選択

find`メソッド: IDに基づいてデータベースから直接レコードを取得しようとします。レコードが見つからない場合はエラーがでます(URLに直接番号を変更させるなどしてURLを変更した場合)

find_by`メソッド: より柔軟に条件を指定でき、レコードが見つからない場合には nil を返すため、例外ハンドリングの必要がありません。これは、ユーザーが存在しない可能性がある場合や、エラーを起こさず指示したルートに戻ります。
(URLに直接番号を変更した場合、指定したページに戻る)

補足
結論、どっちが良い?となれば、僕はfindで使用しています。理由はその次の記事に載せます。
不慣れでかなり文字が増えたので、よりもっと簡単に。という方は下の記事を参考にしてください。

https://zenn.dev/sudoukky/articles/30bfd60239d88c
https://zenn.dev/ganmo3/articles/70102aad10710e

Discussion