現在Railsアプリを作成しています。
現在1つのControllerのindexアクションの行数が多くなりすぎており、モデルに切り出そうと考えたのですが、
切り出したい処理が
・特定のクラスに属するインスタンスではない
ためモデルに処理を切り出せません。
以下のようなコードの場合はどこに、どのように処理を切り出せばよいでしょうか?
複数のレコード情報をもつインスタンスにメソッドを作成できればいいのですが、それに関する該当するような記事を見つけることができませんでした。
もしわかる方がいらっしゃればご教授いただきますようよろしくお願いいたします(m_ _m)
動作環境
Ruby: 2.5.7
Rails: 5.1.7
期待する動作
- Controllerから処理の部分を別の部分へ切り出せること
- 切り出す前と同じ動作ができること
処理の内容
todaysmenusが存在する場合
・@stocks,@todaysmenusをそれぞれrawmaterial_idごとに合算して、まとめる
・@stocksから@todaysmenusの内容を引き算した結果を@stocks_not_plan_to_consume
に格納する
todaysmenusが存在しないばあい場合
・@stocksのkey(rawmaterial_id)とvalue(quantity)を@stocks_not_plan_to_consume
に格納する
試したこと
- modelに
get_remaining_stocks
というメソッドを作成して切り出そうとしたが、`NoMethodError at /stocks
undefined method get_remaining_stocks'
のエラーが発生する
該当しそうなコード
app/controllers/stocks_controllers.rb(1/4)
ruby
1# app/controllers/stocks_controllers.rb 2 def index 3 @stocks = current_user.stocks.includes(:rawmaterial, { rawmaterial: :unit }).unused 4 @todaysmenus = current_user.todaysmenus.includes(:cuisine, cuisine: :foodstuffs).search_in_today 5 6 # begin 切り出したいコード 7 # 残るstocksがある場合は@stocks_not_plan_to_consumeに値が格納されている 8 @stocks_not_plan_to_consume = {} 9 # @stocks_not_plan_to_consume = get_remaining_stocks(@stocks, @todaysmenus) 10 if @todaysmenus.present? 11 stocks = Hash[@stocks.pluck(:rawmaterial_id, :quantity).to_h.map { |key, val| [key, Rational(val)] }] 12 todaysmenus = @todaysmenus.create_hash_todaysmenus(@todaysmenus) 13 stocks_results = @stocks.remaining_amount(stocks, todaysmenus) 14 @stocks_not_plan_to_consume = stocks_results 15 else 16 @stocks_not_plan_to_consume = Hash[@stocks.pluck(:rawmaterial_id, :quantity).to_h.map { |key, val| [key.to_s, Rational(val)] }] 17 end 18 # end 切り出したいコード 19 20 end
app/models/stock.rb(2/4)
ruby
1# app/models/stock.rb 2 def self.remaining_amount(stocks, todaysmenus = nil) 3 stocks_result = {} 4 stocks.each do |st| 5 todaysmenus.each do |tm| 6 stocks_result.store(st[0].to_s, st[1] - tm[1]) if st[0] == tm[0] 7 end 8 stocks_result.store(st[0].to_s, st[1]) unless stocks_result.key?(st[0].to_s) 9 end 10 stocks_result.delete_if { |_key, value| value <= 0 } 11 end 12 13 # begin 追加した部分(NoMethodError at /stocks undefined method get_remaining_stocks が発生する) 14 def get_remaining_stocks(stocks, todaysmenus) 15 stocks_remainings = {} 16 binding.pry 17 if todaysmenus.present? 18 stocks = Hash[stocks.pluck(:rawmaterial_id, :quantity).to_h.map { |key, val| [key, Rational(val)] }] 19 binding.pry 20 todaysmenus = @todaysmenus.create_hash_todaysmenus(@todaysmenus) 21 stocks_results = @stocks.remaining_amount(stocks, todaysmenus) 22 binding.pry 23 @stocks_not_plan_to_consume = stocks_results 24 else 25 @stocks_not_plan_to_consume = Hash[@stocks.pluck(:rawmaterial_id, :quantity).to_h.map { |key, val| [key.to_s, Rational(val)] }] 26 end 27 end 28 # end 追加した部分
app/models/todaysmenu.rb(3/4)
ruby
1# app/models/todaysmenu.rb 2 def self.create_hash_todaysmenus(todaysmenus) 3 quantities = [] 4 todaysmenus.each do |tm| 5 c = tm.cuisine 6 # binding.pry 7 c.foodstuffs.each do |fs| 8 quantities.push([fs.rawmaterial_id, Rational(fs.quantity) * tm.serving_count]) 9 end 10 end 11 tmp_grouped_todaysmenus = quantities.group_by do |r| 12 r.first 13 end 14 tmp_grouped_todaysmenus.each do |k, v| 15 tmp_grouped_todaysmenus[k] = v.inject(0) do |sum, arr| 16 sum += Rational(arr.last) 17 end 18 end 19 grouped_todaysmenus = tmp_grouped_todaysmenus 20 end
app/models/todaysmenu.rb(4/4)
ruby
1# db/schema.rb 2 3ActiveRecord::Schema.define(version: 2021_07_16_093528) do 4 5 create_table "cuisines", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 6 t.string "name", null: false, comment: "料理名" 7 t.bigint "genre_id" 8 t.integer "difficulty", limit: 1, default: 0, null: false, comment: "料理の難易度(enumで、低・中・高)" 9 t.string "calories", comment: "摂取カロリー" 10 t.integer "cooking_time", null: false, comment: "調理時間" 11 t.string "description" 12 t.string "main_image", null: false, comment: "メイン画像" 13 t.datetime "created_at", null: false 14 t.datetime "updated_at", null: false 15 t.index ["genre_id"], name: "index_cuisines_on_genre_id" 16 t.index ["name"], name: "index_cuisines_on_name", unique: true 17 end 18 19 create_table "foodcategories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 20 t.string "name", null: false, comment: "食材区分名(肉、野菜、魚、炭水化物など)" 21 t.datetime "created_at", null: false 22 t.datetime "updated_at", null: false 23 t.index ["name"], name: "index_foodcategories_on_name", unique: true 24 end 25 26 create_table "foodstuffs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 27 t.string "quantity", comment: "数量" 28 t.bigint "cuisine_id", comment: "料理id" 29 t.bigint "rawmaterial_id", comment: "原材料id" 30 t.integer "row_order" 31 t.datetime "created_at", null: false 32 t.datetime "updated_at", null: false 33 t.index ["cuisine_id"], name: "index_foodstuffs_on_cuisine_id" 34 t.index ["rawmaterial_id"], name: "index_foodstuffs_on_rawmaterial_id" 35 end 36 37 create_table "genres", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 38 t.string "name", null: false 39 t.datetime "created_at", null: false 40 t.datetime "updated_at", null: false 41 t.integer "cuisines_count", default: 0, null: false 42 end 43 44 create_table "rawmaterials", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 45 t.string "name", null: false, comment: "原材料名" 46 t.string "hiragana" 47 t.bigint "unit_id" 48 t.bigint "foodcategory_id" 49 t.integer "expiry_period", default: 1, null: false 50 t.integer "foodstuffs_count", default: 0, null: false 51 t.datetime "created_at", null: false 52 t.datetime "updated_at", null: false 53 t.index ["foodcategory_id"], name: "index_rawmaterials_on_foodcategory_id" 54 t.index ["name"], name: "index_rawmaterials_on_name", unique: true 55 t.index ["unit_id"], name: "index_rawmaterials_on_unit_id" 56 end 57 58 create_table "stocks", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 59 t.string "quantity", null: false 60 t.bigint "rawmaterial_id" 61 t.bigint "user_id" 62 t.date "rotted_at", default: "2021-07-16", null: false 63 t.datetime "consumed_at" 64 t.boolean "abandoned", null: false 65 t.datetime "created_at", null: false 66 t.datetime "updated_at", null: false 67 t.index ["rawmaterial_id"], name: "index_stocks_on_rawmaterial_id" 68 t.index ["user_id"], name: "index_stocks_on_user_id" 69 end 70 71 create_table "todaysmenus", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 72 t.bigint "cuisine_id" 73 t.bigint "user_id" 74 t.integer "serving_count", default: 1, null: false 75 t.integer "cooked_when" 76 t.datetime "created_at", null: false 77 t.datetime "updated_at", null: false 78 t.index ["cuisine_id"], name: "index_todaysmenus_on_cuisine_id" 79 t.index ["user_id"], name: "index_todaysmenus_on_user_id" 80 end 81 82 create_table "units", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 83 t.string "name" 84 t.datetime "created_at", null: false 85 t.datetime "updated_at", null: false 86 end 87 88 add_foreign_key "cuisines", "genres" 89 add_foreign_key "favorites", "cuisines" 90 add_foreign_key "favorites", "users" 91 add_foreign_key "rawmaterials", "units" 92 add_foreign_key "stocks", "rawmaterials" 93 add_foreign_key "stocks", "users" 94 add_foreign_key "todaysmenus", "cuisines" 95 add_foreign_key "todaysmenus", "users" 96end
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/07/17 11:37