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

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

ただいまの
回答率

87.77%

Ruby on Rails 1対多の関係のデータを取得して表示したい

解決済

回答 2

投稿 編集

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

score 13

実現したいこと:

イメージ説明

上記のER図で、menuテーブルとcartテーブルが1対多の関係で構成されており、menu一覧画面から
カートに入れるをクリックすると、cartテーブルにデータが入るように組み立てました。

ユーザーがcartテーブルに入れたデータを、cartコントローラーのshowアクションで、cartカラムのmenu_idを使用してmenuテーブルに入っているデータを一覧としてcartのshowページで表示したいと思っています。


現状のコード

class Menus::ApplicationController < ApplicationController
end
class Menus::CartsController < Menus::ApplicationController

  def create
    order = current_user.prepare_order
    menu = Menu.find(params[:menu_id])
    @cart = order.carts.new(cart_params)
    @cart[:menu_id] = menu.id
    if @cart.save
      redirect_to cart_path(current_user)
    else
      render :new
    end
  end


  def destroy 
  end

  private
    def cart_params
      params.require(:cart).permit(:quantity).merge(user_id: current_user.id);
    end

end
class CartsController < ApplicationController
    def new 
      @cart = Cart.new
    end

    def show
      @cart = Cart.where(user_id: current_user.id)
      @menu = Cart.all.includes(:menu)
    end
  end
class Cart < ApplicationRecord
  belongs_to :order
  has_many :menus
end
class Menu < ApplicationRecord
  belongs_to :cart, dependent: :destroy
  belongs_to :category
end

エラー内容

Cartコントローラーshowアクションのページ

<%= render 'layouts/header' %> 

<div class="cart-container">
  <div class="cart-history">
    <h3>注文履歴</h3>
  </div>

  <div class="cart-selection">
    <section>
      <ul>
        <li><a href="#">カート</a></li>
        <li><a href="#">注文済み</a></li>
        <li><a href="#">キャンセルされた注文</a></li>
      </ul>
    </section>
  </div>

<% @cart.each do |cart|%>
 <form action="#" method="post">
  <div class="cart-content">
    <div class="cart-details-top">
      <ul>
        <li>注文日:<br><span></span></li>
        <li>配達予測時間:<br><span></span></li>
        <li>お届け先:<br><span></span></li>
        <li>金額<br><span>¥</span></li>
      </ul>
    </div>

    <div class="cart-details-under">
      <div class="in-cart-name">
        <p>商品名:<span><%= @menu.name %></span></p>
        <p>個数:<span><%= cart.quantity %></span></p>
        <img src="" alt="image" width="180px" height="150px">
      </div>
      <div class="cart-important">
        <p>アレルギー物質表示:</p>
        <p>商品説明</p>
        <p>食材</p>
      </div>
    </div>
  </div>
</div>
<% end %>

<div class="price-container">
     <h3>合計金額: ¥</h3>
     <button type="submit" name="buy">注文する</button>
  </form>
</div>

<div class="image-box">
  <div class="main-image">
    <%= link_to do %><%= image_tag asset_path("main-menu.png"), alt:"main-menu", width:"30px" %><% end %>
  </div>

  <div class="single-box">
    <%= link_to do %><%= image_tag asset_path("single-menu.png"), alt:"main-menu", width:"30px" %><% end %>
  </div>

  <div class="drink-box">
    <%= link_to do %><%= image_tag asset_path("drink-menu.png"), alt:"main-menu", width:"30px" %><% end %>
  </div>

  <div class="reservation-box">
    <%= link_to do %><%= image_tag asset_path("reservation-menu.png"), alt:"main-menu", width:"40px", height:"20px" %><% end %>
  </div>
</div>

<%= render 'layouts/footer' %>

商品名を出力すると、名前が出力されずに、"Cart"という文字が出力されます。

予備情報

イメージ説明
Cartテーブルには、データが入っています。

イメージ説明
Menuテーブルを同様です。


分かる方知識を貸してください。
すみませんが、宜しくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • winterboum

    2020/01/20 20:01

    載せるプログラムを適当に削除するのはなしに。
    controllerのcreate確認したいし、viewも途中で切れている。
    このviewがshowならエラーになると思うのだがなっていない。 のが不思議

    キャンセル

  • nissyan

    2020/01/21 00:54

    @winterboumさん
    いつもありがとうございます。
    引き続きショッピングカート機能を実装しています。
    情報不足の部分追記させていただきました。

    "載せるプログラムを適当に削除するのはなしに。"
    →以前の質問の際はすみません!

    お忙しいこと申し訳ありませんが、ご確認していただけたら嬉しいです。

    キャンセル

回答 2

checkベストアンサー

+1

大きく二つ[1]システムのモデリング [2]Cartという文字が出る
[1]
nissyanさんのイメージしている世界がどうもうまく頭に入ってきません。

  1. menuとCategoyはマスターとしてある。全てのuserや注文に共通で使われる。
    は合っているとおもうのですが
  2. Menuがbelongs_to :cartというのが?? これは1)とは矛盾。
    CartMenuという中間tableが必要なのでは?そこに個数などが入る
  3. Cart が   belongs_to :order と言うことは注文ごとにCartが作成される?
    ですとCartとOrderを分ける必要はないのでは?
    前回の質問の時にCartに取り込んで発注したらOrderに、とコメントしたのは、前回はCartがいつ作られるのかはっきりしていなかったので、User毎に専用に11台割り当てておくことを考えての、コメントです。
    そこ(Cartを適切なタイミングで用意する)は今回クリアできたみたいですから、==Orderで良さそうです。

3)はついで、で2)が今回のコメントの一番気になっている所です

[2]>"Cart"という文字が出力されます。 多分それ以外にも前後に出ていると想うのですがそれを見えるようにするかどうかで、回答の質が変わります。
肝心なところを省略してくださる。エラー関係は編集しない方が良いです
で、@menu.name とあたかも@menuは一つのMenuのような顔をしていますが、実体は@menu = Cart.all.includes(:menu) すなわちCartのrelationです。ですので、「Cartのrelation」のnameがでています。

ここは Cartにある複数のmenuのnameでしょうから

def show
   @cart = Cart.includes(:menu).where(user_id: current_user.id)
end


とし、<div class="cart-details-under"> </div>のなかに
@cart.menus.each do |menu|  end のloopを作ってその中に
商品名、個数、アレルギー物質表示、商品説明、食材 などを表示。
ここで今のモデリングだと 個数が困る。
Menuに個数はありえない。共通で使うtableだから
cartのquantityをつかってますがこれもありえない。注文した全商品が全部同じ数とは限らない。

ので、[1]の2になります。
@cart.cart_menus.each do |cart_menu|  cart_menu.menu.name
って感じ。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/23 03:59 編集

    @winterboumさん
    いつも本当にありがとうございます。
    返事が遅くなり申し訳ありません。

    [1]に対しての回答ですが、応急としてcartテーブルを中間テーブルとして
    menuとorderの間に作りました。

    [2]提示の内容によって、回答の質が変わるとの指摘ありがとうございます。
    もう少し回答する側の立場になってできるよう考えます。
    そして、showコントローラーの記述とeach文の通りにすると無事表示できました。
    本当にありがとうございます。

    最後に質問ですが、表示できたコードは、間違ったコードやER図を消して記載しなおしたほうがいいですか?
    問題を抱えた人が見れるようにしたほうがわかりやすいかと思いました。

    キャンセル

  • 2020/01/23 05:51

    元になったコードはそのままにし、解決したcodeを「これで解決」と載せるのが良いのでは。
    全部かどこが異なるか判るようにか、は場合で

    キャンセル

  • 2020/01/23 19:24

    @winterboumさん
    そうですね!
    アドバイスありがとうございました。

    キャンセル

0

アドバイスにより解決しましたので、修正したコードを記載しておきます。
※変更点のみ記載しています。

まずはER図から

イメージ説明
↑CartテーブルをMenuテーブルとOrderテーブルの中間テーブルとしています。

そしてテーブルの関係性をモデルに記入しました。

//Menuモデル
class Menu < ApplicationRecord
  has_many :carts,  dependent: :destroy
  has_many :orders,  through: :carts
  belongs_to :category
end

//Cartモデル(中間テーブル)
class Cart < ApplicationRecord
  belongs_to :order
  belongs_to :menu
end

//Orderモデル
class Order < ApplicationRecord
  has_many :carts, dependent: :destroy
  has_many :menus, through: :carts
end

//Userモデルは追加記載
class User < ApplicationRecord
 ・
 ・
 ・
  def prepare_order  #メソッドはカートコントローラに記載
    order || create_order
  end
end

次はコントローラーです。

//Cartコントローラー

class CartsController < ApplicationController

    def new 
      @cart = Cart.new
    end

    def show  
      @cart = Cart.includes(:menu).where(user_id: current_user.id)
    end
  end

最後にviewです。

 <form action="#" method="post">
 <% @cart.each do |cart| %>
  <div class="cart-content">
    <div class="cart-details-top">
      <ul>
        <li>注文日:<br><span><%= cart.created_at.to_s(:published_on) %></span></li>
        <li>配達予測時間:<br><span><%= cart.created_at.to_s(:datetime_jp) %></span></li>
        <li>お届け先:<br><span></span></li>
        <li>金額<br><span>¥<%= cart.menu.price %></span></li>
      </ul>
    </div>

    <div class="cart-details-under">
      <div class="in-cart-name">
        <p>商品名:<span><%= cart.menu.name %></span></p>
        <p>個数:<span><%= cart.quantity %></span></p>
        <%= image_tag asset_path(cart.menu.image), alt:"image", width:"180px", height:"150px" %>
      </div>
      <div class="cart-important">
        <p>アレルギー物質表示: &nbsp;&nbsp;&nbsp;<%= cart.menu.allergy %></p>
        <p>商品説明: &nbsp;&nbsp;&nbsp;<%= cart.menu.description %></p>
        <p>食材: &nbsp;&nbsp;&nbsp;<%= cart.menu.ingredient %></p>
      </div>
    </div>
</div>
</div>
 <% end %>


以上になります。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

同じタグがついた質問を見る