入力と出力を意識しよう

June 14, 2020

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

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

ことの発端のエラー

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

https://qiita.com/DaichiSaito/items/52448ebfcb0db768dcf3

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

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

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 クラスのインスタンスを返しているということだ! という当たり前のことに気づいたのです。

戻り値

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

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

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

最後に

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

参考文献

https://railsguides.jp/association_basics.html#belongs-to%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89

https://qiita.com/DaichiSaito/items/52448ebfcb0db768dcf3