🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

1回答

2467閲覧

【Rails】カート機能で、ユーザーに紐づいたカートidを取得できない。

is02

総合スコア17

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2020/11/26 17:45

編集2020/12/21 14:47

前提

新規登録/ログイン機能はdeviseを使用しています。

###実現したいこと

カート機能で、ユーザーに紐づいたカートidを取得したいです。

発生している問題・エラーメッセージ

イメージ説明
上記画像のように、ユーザーに紐づいているカートidを取得できません。

登場モデル

ユーザー: User
カート: Cart
カート内商品: CartItem
商品: Product

該当のソースコード

####モデル

User

1class User < ApplicationRecord 2 3 # Include default devise modules. Others available are: 4 # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable 5 devise :database_authenticatable, :registerable, 6 :recoverable, :rememberable, :validatable 7 8 has_one :cart, dependent: :destroy 9 accepts_nested_attributes_for :cart 10 11end

Cart

1class Cart < ApplicationRecord 2 3 belongs_to :user 4 has_many :products, through: :cart_items 5 6end

CartItem

1class CartItem < ApplicationRecord 2 3 belongs_to :product 4 belongs_to :cart 5 6end

Product

1class Product < ApplicationRecord 2 3 has_many :carts, through: :cart_items 4 5end

####コントローラー

ApplicationController

1class ApplicationController < ActionController::Base 2 before_action :configure_permitted_parameters, if: :devise_controller? 3 protect_from_forgery with: :exception 4 5 helper_method :current_cart 6 7 def current_cart 8 user = User.find_by(id: current_user.id) 9 session[:cart_id] = user.cart.id 10 if session[:cart_id] 11 cart = Cart.find(session[:cart_id]) 12 else 13 cart = Cart.create 14 end 15 end 16 17 protected 18 19 def configure_permitted_parameters 20 devise_parameter_sanitizer.permit(:sign_up, keys: [cart_attributes: [:id]]) 21 end 22end

CartsController

1class CartsController < ApplicationController 2 3 def show 4 @cart_items = current_cart.cart_items 5 end 6 7 def add_item 8 @cart_item = current_cart.cart_items.build(product_id: params[:product_id]) if @cart_item.blank? 9 if @cart_item.save 10 redirect_to current_cart 11 else 12 redirect_to controller: "products", action: "show" 13 end 14 end 15 16end

####ビュー

ProductShow

1<h1>商品詳細</h1> 2 3商品名:<%= @product.name %><br> 4商品説明文:<%= @product.description %><br> 5 6<%= button_to "カートに入れる", add_item_path(product_id: @product.id) %>

#####新規登録時にcart.idも一緒に登録されるようにしています。
#####devise/user/registration_controller.rb

DeviseUserRegistration

1# frozen_string_literal: true 2 3class Users::RegistrationsController < Devise::RegistrationsController 4 # before_action :configure_sign_up_params, only: [:create] 5 # before_action :configure_account_update_params, only: [:update] 6 7 # GET /resource/sign_up 8 def new 9 @user = User.new 10 @cart = @user.build_cart 11 end 12 13 # POST /resource 14 # def create 15 # super 16 # end 17 18 # GET /resource/edit 19 # def edit 20 # super 21 # end 22 23 # PUT /resource 24 # def update 25 # super 26 # end 27 28 # DELETE /resource 29 # def destroy 30 # super 31 # end 32 33 # GET /resource/cancel 34 # Forces the session data which is usually expired after sign 35 # in to be expired now. This is useful if the user wants to 36 # cancel oauth signing in/up in the middle of the process, 37 # removing all OAuth session data. 38 # def cancel 39 # super 40 # end 41 42 # protected 43 44 # If you have extra params to permit, append them to the sanitizer. 45 # def configure_sign_up_params 46 # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) 47 # end 48 49 # If you have extra params to permit, append them to the sanitizer. 50 # def configure_account_update_params 51 # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) 52 # end 53 54 # The path used after sign up. 55 # def after_sign_up_path_for(resource) 56 # super(resource) 57 # end 58 59 # The path used after sign up for inactive accounts. 60 # def after_inactive_sign_up_path_for(resource) 61 # super(resource) 62 # end 63end

####users/sign_up

DeviseRegistration

1<h2>Sign up</h2> 2 3<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 4 <%= render "devise/shared/error_messages", resource: resource %> 5 6 <%= f.fields_for :cart do |f| %> 7 <div class="field"> 8 <%= f.hidden_field :id, value: @cart.id %> 9 </div> 10 <% end %> 11 12 <div class="actions"> 13 <%= f.submit "Sign up" %> 14 </div> 15<% end %> 16 17<%= render "devise/shared/links" %>

####ルーティング

routes

1Rails.application.routes.draw do 2 3 devise_for :users, controllers: { registrations: 'users/registrations' } 4 resources :users 5 resources :carts, only: [:show] 6 post '/add_item' => 'carts#add_item' 7 8end

試したこと

helper_method :current_cart def current_cart user = User.find_by(id: current_user.id) # ログインユーザーのid session[:cart_id] = user.cart.id # ログインユーザーに紐づいているカートのidをセッションに保存 if session[:cart_id] cart = Cart.find(session[:cart_id]) else cart = Cart.create end end

@cart_item = current_cart.cart_items.build(product_id: params[:product_id]) if @cart_item.blank?

で、ログインユーザーに紐づいているカートオブジェクトをひっぱってきて、カート追加した時に商品追加される

というイメージなのですが、エラーが発生します。

セッションにカートidを保存したのは、そのままひっぱってくると、数値になってしまいオブジェクトが持ってこれなかったためです。

おそらく、解釈の違いが発生していると思いますが、

いくつか参考にさせて頂いてもうまく行かないので、ご教授いただけると幸いです。

補足情報(FW/ツールのバージョンなど)

ruby: 2.5.8
rails: 5.2.4

参考にさせて頂いた記事

【Rails5でカート機能を作るためのロジックを作ってみた】
https://qiita.com/Coolucky/items/89ce3a0f25c9dfdb38c1

【deviseのフォームで2つのモデルに同時に値を送る方法(例: UserモデルとProfileモデル)】
https://qiita.com/wonder_meet/items/9238d9bedea542ab975b

【ECサイトのカート機能】
https://qiita.com/kenzo-ta/items/b45994c5f3fdd87b6c50

###追記(2020/12/07)
users/registrations_controller.rb

def create super @user = User.new(configure_sign_up_params) @cart = @user.build_cart @cart.save @user.save end

これを追加すると、rails cで確認した時に、Cartにuser_idが入っているのですが、

Product/show.erb

<h1>商品詳細</h1> 商品名:<%= @product.name %><br> 商品説明文:<%= @product.description %><br> <%= button_to "カートに入れる", add_item_path(product_id: @product.id) %>

商品詳細のカートに入れるを押したあと、Carts#additemにて、user.cartを取得する方法がわかりません。

class CartsController < ApplicationController def show @cart = Cart.find(params[:id]) end def add_item @user = current_user @cart = @user.cart.id @cart_item = @cart.cart_items.build(product_id: params[:product_id]) if @cart_item.blank? @cart_item.save redirect_to cart_path end end

上記のように記載するとundefined method cart_items for 2:Integerという表示が出てしまいます。
おそらく、@user.cart.idがただの整数値だからひっぱってこれていないのかと思っています

ご教授いただけますと幸いです。

###関連付け
user.rb

has_one :cart, dependent: :destroy accepts_nested_attributes_for :cart

cart.rb

class Cart < ApplicationRecord belongs_to :user has_many :products, through: :cart_items end

product.rb

has_many :carts, through: :cart_items

12/21追記

以下のように変更したら、とりあえずカートページに商品を追加することができました。
####cart.rb

belongs_to :user has_many :cart_items

####cart_item.rb

belongs_to :product belongs_to :cart

####product.rb

has_many :cart_items

####cart_controller.rb

def index @cart = current_user.cart @cart_items = @cart.cart_items end def add_item @cart = current_user.cart @cart_item = @cart.cart_items.build(product_id: params[:product_id]) @cart_item.save redirect_to carts_path end

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

  1. registrationのnewでbuildしてもできていません。createかUsermodelのafter_create フックで作ってください
  2. そうできていれば current_cart は不要です。常に user.cartで得られます。sessionに残すこともない

3.def current_cart の elseで cart = Cart.create してますが、作成に失敗してます。user_idが渡っていないから。1してあれば不要

とりあえずこの辺りまで直して試してください

=============
いくつか問題があります
1 @cart = @user.cart.id => @cart = @user.cart
1 @cart_item = @cart.cart_items.build cart に productを載せるのですから、@item = @cart.products.buildのほうが本質です。中間tableを触るのはそこに付加情報があるのでなければ忘れる
1 それを可能にするにはclass Cartにhas_many :cart_itemsが必要。

投稿2020/11/26 23:15

編集2020/12/09 09:24
winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

is02

2020/12/07 10:45

ご回答ありがとうございます。 追記に、試したこと記載しました。 お手隙の際に見ていただけますと幸いです。
winterboum

2020/12/07 11:23

ですから registrationのnewでbuildしてもできていません。createかUsermodelのafter_create フックで作ってください
is02

2020/12/07 13:32

追記いたしました。間違った解釈で進めていましたらすみません。
winterboum

2020/12/07 22:40

modelに関連定義してますか
is02

2020/12/09 05:09

関連付けも追記しました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問