Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MealPostのサブ項目としてFoodItemを追加する #13

Merged
merged 29 commits into from
Jun 18, 2020

Conversation

kudojp
Copy link
Owner

@kudojp kudojp commented Apr 26, 2020

概要

  • MealPostのサブ項目としてFoodItemを追加する
  • MealPost投稿時にFoodItemを一品以上追加することを必須とする
  • 各MealPostの詳細ページから、編集ができるようにする

仕様

MealPost投稿時

  • MealPostを投稿する際には1つ以上のFoodItemを登録する
  • FoodItemは以下の項目からなる
    • 食品名(string, not null) (例)カレーライス, 餃子
    • 量(string, null許可) (例)一杯、4個、たくさん、300g
    • 総カロリー(unsigned int, null許可、単位はカロリー) (例)500

MealPostカード

Homeページのタイムライン、User詳細ページのMealPost一覧ページの各MealPostカードでは(とりあえず)FoodItemの詳細な一覧は表示ない。ただし、品目数とカロリーの合計値は表示する。

  • カロリーに関しては、MealPostに所属する全てのFoodItemのカロリーが入力されている場合には540kcalと、全て入力されていない場合には、540+kcalと、一つも入力されていない場合には+kcalと表示する

MealPost詳細ページ

  • MealPostの詳細ページではFoodItemの一覧が表示される。

設計

FoodItemsテーブルの作成

フィールド名 データ型 制約
id unsigned int  PK
name string not null
amount string  
calory int (unsigned)  
meal_post_id int (unsigned) not null, FK: MealPost(id)

MealPostsテーブルの更新

  • calories_sumというカラムを作る
    • カウンターカルチャーでMealPostが登録、変更された際には自動更新される。

更新後のテーブルは以下。

フィールド名 データ型 制約
id unsigned int PK
time datetime not null
user_id unsigned int FK: user(id), not null
num_items unsigned int not null
sum_calories unsigned int  
is_all_calory_sum Boolean not null

@kudojp kudojp self-assigned this Apr 26, 2020
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc April 26, 2020 06:14 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from 0a626cd to 9e6dd40 Compare April 26, 2020 09:05
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc April 26, 2020 09:05 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc April 29, 2020 06:16 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from 2903ffd to 88ad010 Compare May 3, 2020 18:25
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 3, 2020 18:25 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 3, 2020 19:22 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 4, 2020 06:38 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 4, 2020 08:16 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 4, 2020 08:38 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from a99cbb9 to af5a3a1 Compare May 4, 2020 08:41
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 4, 2020 08:41 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from af5a3a1 to 2f3e124 Compare May 4, 2020 08:43
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 4, 2020 08:43 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from 2f3e124 to f60e7d3 Compare May 4, 2020 12:47
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 4, 2020 12:48 Inactive
@kudojp kudojp temporarily deployed to diet-app-2020 May 4, 2020 12:48 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from f60e7d3 to 011da22 Compare May 16, 2020 03:46
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 16, 2020 03:46 Inactive
@kudojp
Copy link
Owner Author

kudojp commented May 17, 2020

MealPostsのUpdate(nestされたFoodItemsを含めて)がうまくいかない

ログ

app/controllers/meal_posts_contoroller.rb

class MealPostsController < ApplicationController
  before_action :authenticate_user!, only: %i[create destroy update]

  def create
    @new_meal_post = current_user.meal_posts.build(meal_post_params)

    # meal_post object used for rendering partial form after successfully creating meal_post
    @next_meal_post = current_user.meal_posts.new
    3.times { @next_meal_post&.food_items&.build }

    if @new_meal_post.save
      return respond_to do |format|
        # TODO: friendly forwardingを実装
        format.html { redirect_to root, notice: 'You successfully made a meal post.' }
        format.js
      end
    end

    respond_to do |format|
      # TODO: friendly forwardingを実装
      # TODO: errorを伝搬するなりして、alertをもう少しdescriptiveにする
      format.html { redirect_to root, alert: 'You could not make a meal post.' }
      format.js do
        render partial: 'meal_posts/create_failure', status: :bad_request
      end
    end
  end

  def update
    @meal_post = MealPost.find(params[:id])
    return redirect_to root_path, alert: 'You are not authorized to update the post' if @meal_post.user_id == current_user

    if @meal_post.update(meal_post_params)
      return respond_to do |format|
        # TODO: friendly forwardingを実装
        format.html { redirect_to root, notice: 'You have successfully updated a meal post.' }
        format.js
      end
    end

    respond_to do |format|
      # TODO: friendly forwardingを実装
      # TODO: errorを伝搬するなりして、alertをもう少しdescriptiveにする
      format.html { redirect_to root, alert: 'You could not make a meal post.' }
      format.js do
        render partial: 'meal_posts/create_failure', status: :bad_request
      end
    end
  end

  private

  def meal_post_params
    params.require(:meal_post).permit(:content, :time, food_items_attributes: %i[name amount calory _destroy])
  end

app/views/meal_posts/_edit.html.erb

<%= form_for(meal_post, html: { method: :patch }, remote: true) do |f| %>
  <div class="field">
    <%= f.text_field :content, placeholder: 'メニュー名' %>
  </div><br>

  <div class="fields">
    <%= f.fields_for :food_items do |fi_field| %>
      <%= render partial: 'meal_posts/food_item_fields', locals: {f: fi_field} %>
    <% end %>
    <div class='links'>
      <%= link_to_add_association '', f, :food_items, partial: 'meal_posts/food_item_fields', class: "fas fa-plus-circle" %>
    </div>
  </div><br>

  <div class="field">
    <%= f.text_field :time, class: 'datetimepicker', placeholder: '食べた日時を選択' %>
  </div>

  <!-- TODO: 画像もアップロードできるようにする -->

  <%= f.submit "投稿する" %>
<% end %>

これだとcreateはうまくいくが、updateはうまくいかない。

コンソールログ

create時

Started POST "/meal_posts" for ::1 at 2020-05-17 19:57:17 +0900
Processing by MealPostsController#create as JS
  Parameters: {"meal_post"=>{"content"=>"new post", "food_items_attributes"=>{"0"=>{"name"=>"カレー", "amount"=>"", "calory"=>"", "_destroy"=>"false"}, "1"=>{"name"=>"", "amount"=>"", "calory"=>"", "_destroy"=>"false"}, "2"=>{"name"=>"", "amount"=>"", "calory"=>"", "_destroy"=>"false"}}, "time"=>"2020-05-04 12:00"}, "commit"=>"投稿する"}
(以下略)

update時

ArgumentError (When assigning attributes, you must pass a hash as an argument, NilClass passed.):
  
app/controllers/meal_posts_controller.rb:50:in `update'
Started PATCH "/meal_posts/260" for ::1 at 2020-05-17 19:55:53 +0900
Processing by MealPostsController#update as JS
  Parameters: {"meal_post"=>{"content"=>"カレー", "food_items_attributes"=>{"0"=>{"name"=>"チョコ", "amount"=>"100", "calory"=>"", "_destroy"=>"1", "id"=>"225"}}, "time"=>"2020-04-26 12:00"}, "commit"=>"投稿する", "id"=>"260"}
  User Load (0.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  MealPost Load (0.7ms)  SELECT "meal_posts".* FROM "meal_posts" WHERE "meal_posts"."id" = $1 ORDER BY "meal_posts"."time" DESC LIMIT $2  [["id", 260], ["LIMIT", 1]]
  ↳ app/controllers/meal_posts_controller.rb:30:in `update'
Unpermitted parameter: :id
   (0.1ms)  BEGIN
  ↳ app/controllers/meal_posts_controller.rb:33:in `update'
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/meal_posts_controller.rb:33:in `update'
  FoodItem Load (0.3ms)  SELECT "food_items".* FROM "food_items" WHERE "food_items"."meal_post_id" = $1  [["meal_post_id", 260]]
  ↳ app/controllers/meal_posts_controller.rb:33:in `update'
   (0.1ms)  COMMIT
  ↳ app/controllers/meal_posts_controller.rb:33:in `update'
No template found for MealPostsController#update, rendering head :no_content
Completed 204 No Content in 64ms (ActiveRecord: 6.7ms | Allocations: 27869)

わかったこと

子モデルをnestする親モデルはcreate時とupdate時でparamsの中身が違うようだ。以下のようにブラウザからの送信時にはrequest bodyは同形式であるが、PATCHメソッドではRails側でこれを配列と解釈してparamsへと変換することができていない。(この質問と同じじ状況)
create
image

update
image

解決策

以下のようにstrong parameterを設定して解決。
app/controllers/meal_posts_contoroller.rb

  private

  def new_meal_post_params
    params.require(:meal_post).permit(:content, :time, food_items_attributes: %i[name amount calory _destroy])
  end

  def update_meal_post_params
    # patchメソッドだとRailsアプリケーションでrequest_bodyの配列をうまく解釈できない(hashになる)ため
    params[:meal_post][:food_items_attributes] = params[:meal_post][:food_items_attributes].values
    params.require(:meal_post).permit(:content, :time, food_items_attributes: %i[name amount calory _destroy id])
  end

@kudojp kudojp force-pushed the topic-food-items branch from 011da22 to f06adf1 Compare May 17, 2020 13:47
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 17, 2020 13:48 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from f06adf1 to cc257b8 Compare May 17, 2020 16:46
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 17, 2020 16:46 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 17, 2020 17:01 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 17, 2020 17:36 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from 0942aa5 to 8e3347b Compare May 17, 2020 17:50
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 17, 2020 17:51 Inactive
@kudojp kudojp force-pushed the topic-food-items branch from 8e3347b to 9cb1578 Compare May 17, 2020 18:25
@kudojp kudojp force-pushed the topic-food-items branch from 9cb1578 to 3975eb5 Compare May 19, 2020 12:49
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 19, 2020 12:50 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-chat-0vta9k May 19, 2020 12:50 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 19, 2020 12:51 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-chat-0vta9k May 19, 2020 13:42 Inactive
@kudojp kudojp temporarily deployed to diet-app-2020 May 23, 2020 12:37 Inactive
@kudojp kudojp temporarily deployed to diet-app-pip-topic-food-bgt2gc May 26, 2020 15:09 Inactive
@kudojp kudojp temporarily deployed to diet-app-2020 May 26, 2020 15:10 Inactive
@kudojp kudojp merged commit 5df7742 into master Jun 18, 2020
@kudojp kudojp temporarily deployed to diet-app-2020 June 22, 2020 13:55 Inactive
@@ -3,5 +3,6 @@ def index
@user = current_user
@meal_posts = @user&.meal_posts_feed&.includes(:user)
@new_meal_post = @user&.meal_posts&.new
3.times { @new_meal_post&.food_items&.build }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

モデルに定数化したいかも

Suggested change
3.times { @new_meal_post&.food_items&.build }
MealPost::DEFAULT_FOOD_NUM.times { @new_meal_post&.food_items&.build }


# meal_post object used for rendering partial form after successfully creating meal_post
@next_meal_post = current_user.meal_posts.new
3.times { @next_meal_post&.food_items&.build }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらも定数化すると二重管理を防げる

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants