##実現したいことについて
- オリジナルアプリを作っています。
- 現在、チェックボタンにチェックをし、上の「SAVE」ボタンを押すと
enum
を使ってデータベースに保存されるようになっています。(チェックしたものは「1」、チェックがないものは「0」として、保存される) - 下の丸い部分について、「カレントユーザーの情報のみ」かつ「今までのカウント合計をカテゴリーごとに出す」実装を行っています。
- 今回悩んでいることは、コントローラーが肥大化しており、カウント数を取得する部分についてモデルに記述したいものの、実装が上手くいかないことです。
##現在のコントローラー(カウント数を取得することも記述しており、肥大化している・・改善できないか??????)
ruby
1class HabitsController < ApplicationController 2 before_action :authenticate_user! 3 4 def index 5 @habit = Habit.new 6 @count_1 = Habit.includes(:habits).where(user_id: current_user.id).where(count_1: 1).size 7 @count_2 = Habit.includes(:habits).where(user_id: current_user.id).where(count_2: 1).size 8 @count_3 = Habit.includes(:habits).where(user_id: current_user.id).where(count_3: 1).size 9 @count_4 = Habit.includes(:habits).where(user_id: current_user.id).where(count_4: 1).size 10 @count_5 = Habit.includes(:habits).where(user_id: current_user.id).where(count_5: 1).size 11 @restart_1 = Habit.includes(:habits).where(user_id: current_user.id).where(restart_1: 1).size 12 @restart_2 = Habit.includes(:habits).where(user_id: current_user.id).where(restart_2: 1).size 13 @restart_3 = Habit.includes(:habits).where(user_id: current_user.id).where(restart_3: 1).size 14 @restart_4 = Habit.includes(:habits).where(user_id: current_user.id).where(restart_4: 1).size 15 @restart_5 = Habit.includes(:habits).where(user_id: current_user.id).where(restart_5: 1).size 16 end 17 18 def new 19 end 20 21 def create 22 habit = Habit.create(habit_params) 23 end 24 25 private 26 27 def habit_params 28 params.require(:habit).permit(:count_1, :count_2, :count_3, :count_4, :count_5, :restart_1, :restart_2, :restart_3, :restart_4,:restart_5).merge(user_id: current_user.id) 29 end 30end
##現在のモデル(アソシエーションを組んでいる)
ruby
1# ユーザーモデル 2class User < ApplicationRecord 3 has_many :habits 4end
ruby
1# habitモデル 2class Habit < ApplicationRecord 3 belongs_to :user 4end
##現在のマイグレーションファイル
ruby
1class CreateHabits < ActiveRecord::Migration[6.0] 2 def change 3 create_table :habits do |t| 4 t.references :user,null: false, foreign_key: true 5 t.boolean :count_1 6 t.boolean :restart_1 7 t.boolean :count_2 8 t.boolean :restart_2 9 t.boolean :count_3 10 t.boolean :restart_3 11 t.boolean :count_4 12 t.boolean :restart_4 13 t.boolean :count_5 14 t.boolean :restart_5 15 t.timestamps 16 end 17 end 18end
##調べたこと(仮説と実証しているが上手くいかないこと)
まずはコントローラーの記述をリファクタリングできないか?と考えました。
###仮説1 N+1問題を解消するために、includes
を使用する
ビフォー
ruby
1 @count_1 = current_user.habits.where(count_1: 1).size
アフター(現在のコード)
ruby
1 @count_1 = Habit.includes(:habits).where(user_id: current_user.id).where(count_1: 1).size
includes
を使用したとしても、カテゴリーごとにcount
やsize
をしようとすると、複数行になってしまう。
###仮説2 ハッシュを使い、複数行になってしまっているカラムを一行にする
こちらの記事を参考に、下記の通り実装するも、データを取得することができない。
ruby
1 @habits = current_user.habits.includes(:habits{count_1: 1, count_2: 1, count_3: 1, count4: 1, count_5: 1, restart_1: 1,(省略)}).size
(補足)その後、ハッシュを使うのは、ネストされているとき(through
オプションなどを使用して、複数アソシエーションを組んでいるとき)時の話ではないか?と気がつきました。
ここからは、そもそもコントローラーとモデルの役割ってどういう立ち位置?と調べ直しました。その結果、DBのデータを扱うメソッド(検索メソッド、レコード取得メソッド、レコード更新メソッド)などはモデルに記述するのが適切では?と思いました。
###仮説3 モデルに記述する
ruby
1# モデル(まずは一つ目のカテゴリーを取得できるか実験) 2def self.count_habit 3 Habit.includes(:habits).where(user_id: current_user.id).where(count_1: 1).size 4end
ruby
1# コントローラー 2 def index 3 @habit = Habit.new 4 Habit.count_habit 5 end
としてbinding.pry
を使用したところ、下記のようなエラー。
terminal
1NameError: undefined local variable or method `current_user' for #<Class:0x00007fc2023e19f0> 2Did you mean? current_scope
terminal
1# カレントユーザーを外すと上手くいく 2[3] pry(Habit)> Habit.includes(:habits).where(count_1: 1).size 3 CACHE (0.0ms) SELECT COUNT(*) FROM `habits` WHERE `habits`.`count_1` = TRUE 4 ↳ (pry):3:in `count_habit' 5=> 146
という状況です・・。
そこから、カレントユーザーに関しては、コントローラーで使えるものであって、モデルでは使用できないという事を知りました。
こちらの記事を参考に、application_controller.rb
のビフォーアクションで、「カレントユーザーを前提にする方法」も試してみましたが、思った通りのデータを取得することができません。
##教えていただきたいこと
- そもそも、上記のコントローラーの状況は良くないのでモデルに書きたいという方向性は合っているのでしょうか?
(初めは、ビューで<%= "通算#{@user.where(count_3: 1).count}回" %>
のような表現をしていたのですが、今後JavaScriptで非同期通信を行いたい時に困ると感じ、コントローラーにまず移しました。)
- そして「カレントユーザーの情報のみ」かつ、「今までのカウント合計をカテゴリーごとに出す」モデルの記述方法がわからず苦戦しております????記述方法のヒントだけでも、教えていただけると嬉しいです????
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/11 13:00
2021/02/11 13:58
2021/02/12 14:26