質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.86%

Ruby on Railsでformで値を送信するが、保存されない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 101

nissyan

score 5

Ruby on Railsでショッピングカート機能を実装しています。
商品一覧画面から、商品の個数を選択してcartテーブルに保存したい状況です。
※cartテーブルはsessionで仮に商品を保存するためのテーブルとなってます。

そして商品一覧indexのコントローラーで、cart.newを記述して、cartのコントローラーで
createメソッドに飛ばしています。

環境:
rails 5.2.3
gem devise機能を使用


index前のコントローラーになります。
class BoxlunchesController < ApplicationController
  def index
    @boxlunches = Boxlunch.all
    @cart = Cart.new
  end

  def show
  end
end

課題:
商品一覧画面から、商品の個数(boxlunch_quantity)を選択し、formで値を送信するが、boxlunch_quantityのみ保存されない
※boxlunch_idはcart_itemテーブルに保存されます。

  index.html.haml

 = render 'layouts/header'
= render "./template/menu_selections"
.menu-container
  %h2 Boxlunch Menu
  .menu-contents
    - @boxlunches.each do |boxlunch|
    #cart_index_pathでcartのcreateに飛びます
      = form_for @cart, url: cart_index_path(boxlunch_id: boxlunch.id), method: :post do |f|
        .menu-package
          .menu-image
            = link_to "boxlunch/#{boxlunch.id}" do
              = image_tag boxlunch.image, width:"200px", height:"150px"
            %h4
              = link_to do
                = boxlunch.name
            .count-price-container
              .count-price
                .price
                  %p ¥#{boxlunch.price}(税込)
                .count
                  %label
                    =f.select :boxlunch_quantity, options_for_select(1..10), include_blank: '0'
              =f.submit "カートの中に入れる"
= render 'layouts/footer'

エラー内容
ブラウザーではエラーは表示されていないので
ターミナルでの記載になります。

ターミナル
Started POST "/cart?boxlunch_id=1" for ::1 at 2020-01-13 23:49:36 +0900
Processing by CartController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"O5g+me6pcK+uueZYWtdRBmkFdj+TzXqkyZRyw+q5KvkcqQ3wGLzM05qi79LfoOL9vd7aI54B78hSBNdXYOML2A==", "cart"=>{"boxlunch_quantity"=>"1"}, "commit"=>"カートの中に入れる", "boxlunch_id"=>"1"}
  Order Load (2.0ms)  SELECT  "orders".* FROM "orders" WHERE "orders"."id" IS NULL LIMIT $1  [["LIMIT", 1]]
  ↳ app/controllers/application_controller.rb:16
   (0.8ms)  BEGIN
  ↳ app/controllers/application_controller.rb:17
   (1.1ms)  ROLLBACK
  ↳ app/controllers/application_controller.rb:17
  Boxlunch Load (0.7ms)  SELECT  "boxlunches".* FROM "boxlunches" WHERE "boxlunches"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/cart_controller.rb:4
  Order Load (1.6ms)  SELECT  "orders".* FROM "orders" WHERE "orders"."id" IS NULL LIMIT $1  [["LIMIT", 1]]
  ↳ app/controllers/application_controller.rb:16
   (1.8ms)  BEGIN
  ↳ app/controllers/application_controller.rb:17
   (0.4ms)  ROLLBACK
  ↳ app/controllers/application_controller.rb:17
   (1.0ms)  BEGIN
  ↳ app/controllers/cart_controller.rb:6
  Cart Create (0.5ms)  INSERT INTO "carts" ("boxlunch_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["boxlunch_id", 1], ["created_at", "2020-01-13 14:49:36.819147"], ["updated_at", "2020-01-13 14:49:36.819147"]]
  ↳ app/controllers/cart_controller.rb:6
   (1.9ms)  COMMIT
  ↳ app/controllers/cart_controller.rb:6
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/cart_controller.rb:7
Redirected to http://localhost:3000/cart/1
Completed 302 Found in 46ms (ActiveRecord: 12.1ms)


Started GET "/cart/1" for ::1 at 2020-01-13 23:49:36 +0900
Processing by CartController#show as HTML
  Parameters: {"id"=>"1"}
  Rendering cart/show.html.haml within layouts/application
  Rendered cart/show.html.haml within layouts/application (1.9ms)
Completed 200 OK in 63ms (Views: 60.4ms | ActiveRecord: 0.0ms)

アプリケーションコントローラーのコード
※current_cartを定義しています。

  class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
    before_action :authenticate_user!


  def after_sign_in_path_for(resource)
    root_path # ログイン後に遷移するpathを設定
  end

  def after_sign_out_path_for(resource)
    root_path # ログアウト後に遷移するpathを設定
  end

  private
  def current_cart
    @current_cart = Order.find_by(id: session[:order_id])
    @current_cart = Order.create unless @current_cart
    session[:order_id] = @current_cart.id 
    @current_cart
  end
end

![Model ER図改正]イメージ説明

カートのモデルコード

class Cart < ApplicationRecord
  belongs_to :order
  has_many :boxlunches


  def add_boxlunch(boxlunch_id)
    cart.find_or_initialize_by(boxlunch_id: boxlunch_id)
    end

    def add_single_menu(single_menu_id)
      cart.find_or_initialize_by(single_menu_id: single_menu_id)
    end
end

カートのコントローラーのコード

class CartController < ApplicationController
    def create
      cart = current_cart
      boxlunch = Boxlunch.find(params[:boxlunch_id])
      @cart = current_cart.add_boxlunch(boxlunch.id)
      if @cart.save
        redirect_to cart_path(current_user)
      else
        render :new
      end
    end

    private
    def cart_params
      params.require(:cart).permit(:boxlunch_quantity);
    end
  end

以上のような状況です。
お忙しい中ですが、教えていただけますと助かります。

宜しくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • nissyan

    2020/01/13 19:42 編集

    モデルの関係性をER図で書きましたので、一度ご確認していただけたら
    嬉しいです。

    cart_itemの方は、index.htmlに遷移する前のコントローラーで,
    cart_item.newをしています。
    order.newも必要でしょうか?
    index.htmlの前のコントローラもコードを追記しておきます。

    すみませんが、ご確認お願いいたします。

    キャンセル

  • winterboum

    2020/01/13 19:53

    Boxlunch と Order をつなぐものが CartItemというのはいただけません。
    CarItemという名前からは CartとItemをつなぐものと誤解されます、
    これは直したほうがよい

    キャンセル

  • winterboum

    2020/01/13 20:11

    OrderとAddressの関連はない方が自然です。
    Addressが沢山Orderをもつとか、Orderがaddressに属するというのは不自然。
    Orderの送り先という考えかと思いますが、OrderしたのはUser,そのaddressへ送ればよいのです

    キャンセル

回答 1

checkベストアンサー

+1

application_controller.rb の 15,16,17行目ってこれですか?

@current_cart = Order.find_by(id: session[:order_id])
@current_cart = Order.create unless @current_cart
session[:order_id] = @current_cart.id 


この session[:order_id] が最初に代入されるのはいつ、どのfileのどのmethodでしょう?
もしかして この17行目?
すると最初に 15行目に来た時はまだ未定義ですから@carrent_cartはnilです。
もしかするとloginの時に定義してますか?
そこを確認してください

追記
不思議、、、、
(0.2ms)  BEGIN
↳ app/controllers/cart_items_controller.rb:7
CartItem Create (0.9ms)  INSERT INTO "cart_items" ("boxlunch_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["boxlunch_id", 2], ["created_at", "2020-01-12 14:54:40.381901"], ["updated_at", "2020-01-12 14:54:40.381901"]]
↳ app/controllers/cart_items_controller.rb:7
(0.5ms)  COMMIT
とあるのでCartItemは作られています。ただ見て判るように order がなになのかわからない状態で。
ところが、CartItemは belongs_to :order になっているので、order_idなしにsave出来ないはずです。
もしかしてこのlogを取った時は載せているプログラムとは違ってる?

追記2
>①order_idが代入されるのは、17行目のsession[:order_id] = @current_cart.id です。
>loginの時に定義しておりません。
とすると current_cart は永遠に nil です。

どこかで order なり cart なり確定する必要があります。

User, Order, Cart の関係を教えてください。

追記の3
モデル間の関連やモデル名の不自然なところはコメントで指摘しています。
さて
Orderが1:多だとすると、Order_idが決まるのはいつ、どこでですか?
その設計が無いようです。

n~~~結構厄介そう
Userと1:1なCartを作り、CartBoxLunchで注文を取り、注文確定したらOrderを作る
のほうが作りやすそう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/15 09:21

    @winterboumさん
    winderboumさんのおかげで、自分でもすっきりにER図を整理できたと感じています。
    1)Orderで仮注文→Cartにいれると考えでしたが、Cartに入れる→注文決定Orderの方がわかりやすそうですね!
    変更します。
    2)各4つの商品をまとめるテーブル(Productテーブル)を作成するやり方はどうでしょうか?

    キャンセル

  • 2020/01/15 11:04

    2)わたしでしたら、商品は全部一つのtableにして、商品カテゴリを示す項目を増やします。

    キャンセル

  • 2020/01/15 19:51

    @winterboumさん
    ご回答ありがとうございます。
    勉強不足でした。
    そうゆうやり方があるのですね!

    そのやり方を調べて実装してみます。
    長い間お付き合い本当にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる