この記事を書いた目的
Railsでコードを書く際にモデルにインタンスメソッドを定義をして、コントローラで呼び出すことがよく行われるということを学びました。少し調べてみると、このことは主にファットコントローラを避けることを目的として行われているようです。
ただ、初心者の私からすると「コントローラの流れすら追うのに苦労しているというのに、別の場所に定義したメソッドを呼び出すなんて、わけわかめ!」ということで、実際にコンソールを動かしてどういった動きをしているのか確かめてみました。
今回検証したコード
掲示板作成アプリ内のお気に入り登録ができる機能に関わる箇所です。該当のコントローラとモデル内のインスタンスメソッドは下記の通りです。
def create
board = Board.find(params[:board_id])
current_user.bookmark(board)
#...
end
def bookmark(board)
bookmark_boards << board
end
- Userモデル内に作成したbookmarkの登録用メソッドを、bookmarksコンローラで呼び出すという流れです
Bookmarkテーブル作成時のマイグレーションファイル
class CreateBookmarks < ActiveRecord::Migration[7.0]
def change
create_table :bookmarks do |t|
t.references :user, null: false, foreign_key: true
t.references :board, null: false, foreign_key: true
t.timestamps
t.index [:user_id, :board_id], unique: true
end
end
end
UserテーブルとBoardテーブルの中間テーブルです。また、同じユーザーが同じ投稿に対して2度ブックマーク登録を行うことのないよう、user_id
とboard_id
にユニーク制約をかけることで、データベースレベルで一意性を保つようにしてあります。
rails consoleの起動(Docker使用時)
$ docker compose run web bin/rails console
RailsConsoleで流れを確認する
今回コンソールで検証するuser_id=1とboard_id=1の組み合わせでは、ブックマークが作成されていません。では、先ほどのコントローラー流れを1行ずつコンソールで確かめていきましょう。
board = Board.find(params[:board_id])
irb(main):002:0> sample_board = Board.find_by(id: 1)
Board Load (1.1ms) SELECT `boards`.* FROM `boards` WHERE `boards`.`id` = 1 LIMIT 1
- Boardモデルからid=1のデータを取得し、sample_boardという変数に代入します
current_user.bookmark(board)
irb(main):003:0> User.find_by(id: 1).bookmark(sample_board)
こちらで実行した内容としては下記の通りです。
- Userモデルからid=1のデータを取得します(コントローラではsorceryのメソッドcurrent_userで呼び出しています)
- 上のuserのデータに対して、引数sample_boardとってbookmarkメソッドを呼び出します
ではコンソールの実行結果を見ていきます。
User Load (1.2ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
TRANSACTION (0.4ms) BEGIN
- Userモデルからid=1のデータを取得します
Bookmark Exists? (0.4ms) SELECT 1 AS one FROM `bookmarks` WHERE `bookmarks`.`user_id` = 1 AND `bookmarks`.`board_id` = 1 LIMIT 1
- 同じ
user_id
とboard_id
の組み合わせが既にBookmarkテーブルにないかを確認しています
Bookmark Create (1.0ms) INSERT INTO `bookmarks` (`user_id`, `board_id`, `created_at`, `updated_at`) VALUES (1, 1, '2024-03-31 11:40:52.618794', '2024-03-31 11:40:52.618794')
TRANSACTION (1.2ms) COMMIT
- ここでbookmarkメソッドが呼び出されています
- <<演算子はhas_many関連付けで使用可能になるメソッドです
4.3.1.2 collection<<(object, ...)
Array#<< (Ruby 3.3 リファレンスマニュアル) -
bookmark_boards << board
は、bookmarks.create!(board_id: board.id)
と同様の処理が行われるため、SQLでCREATE文が発行されます - コミットすることでBookmarkテーブルにデータが保存されました
まとめ
rails consoleで実際の流れを把握することで、コードに対する理解が深まったように感じました。まだまだ理解のできてない箇所があるので、誤っている点などあれば教えていただけると嬉しいです!
参考