tawara's blog

雑記。個人の見解です。

入力と出力を意識しよう

こんちには、たわらです。

本記事は、メソッドをつくるのに入力値と出力値を意識するようになった、という記事です。

ことの発端のエラー

通っているスクールの講師のかたが書いたこちらの記事に、初学者にありがちなパターンのひとつに「入力と出力」を意識するように、という箇所があります。

qiita.com

一度読んだときに、なるほどなーと思ったのですが、その必要性を実感することがありました。

掲示板アプリを作っていて、ブックマークした掲示板のブックマークをはずす、という機能を実装しようとしているときに、こんなエラーに出会ったからです。

ActiveRecord::AssociationTypeMismatch - Board(#70289979952320) expected, got #<Bookmark id: 1, user_id: 12, board_id: 52, created_at: "2020-06-12 08:36:02", updated_at: "2020-06-12 08:36:02"> which is an instance of Bookmark(#70289983892620):

該当箇所のソースはこちら。current_user.unbookmark(board)の部分。

def destroy
  board = current_user.bookmarks.find(params[:id])
  current_user.unbookmark(board)
  redirect_back fallback_location: root_path, success: t('.success')
end

要するに、エラーが言っているのは、current_user.unbookmark(board)boardBoardクラスのオブジェクトが期待されてるのに、Bookmarkクラスのオブジェクトになってしまっていますよ、とのことです。

つまり、ブックマークをはずすboardをきちんと特定できていないということです。

board = current_user.bookmarks.find(params[:id]).board

とすればよかったのです。

戻り値を気にする

初学者あるあるなのか、リソースの指定は(params[:id])で終わるべきだ、という謎の固定概念も理解の邪魔になっていました。

で、この.boardとは何か? これがわかりませんでした。

調べてみると、Bookmarksテーブルはbelong_toの引数にboardを入れているので、associationメソッド(assosicationaはプレースホルダー)として使えるのですね。

ここで、なるほどー、と思うことがありました。

.boardはBookmarksクラスのインスタンスに対して使えるメソッドなんだ! という至極当たり前のことです。

ということはつまり、bookmarks.find(params[:id])はBookmarksクラスのインスタンスを返しているということ! だと至極当たり前のことに気づき、

そしてそういえば確かに、bookmarksはUserクラスとhas_manyで関連付けているから、Userクラスのインスタンスに使用できるメソッドであることに気づき、

ということはつまり、current_userはUserクラスのインスタンスを返しているということだ! という当たり前のことに気づいたのです。

戻り値

戻り値がどのクラスのインスタンスなのか、ということを理解できていれば、最初のエラーが出たときに、リソースの特定ができていないんだな、ともっと早く気づいたはずです。

そして、モデルの関連付けによって使用可能になったオプションメソッドで、解決することができたはずです。

しかし、今回はのエラーの対策を通して、入力値と出力値を意識する重要性が身に沁みてわかりました。適当にメソッドをつないでれば、エラーは出てしまいますよね。気をつけます。

最後に

読んでくださったかた、ありがとうございます。

参考文献

railsguides.jp

qiita.com