

railsは勿論プログラミング初心者です。

今回「Railsによるアジャイルwebアプリケーション開発（第４版）」という本を参考にしてecサイトアプリを作っているのですが、記述通りに作成しているのに不具合が起きて自分では対処できないので質問させていただきました。

手順としましては、簡単な商品投稿と一覧と詳細が見れるサイト作り、カート機能追加し、オーダー機能を追加という感じです。  
カート機能追加まではうまくいってたのですが、オーダー機能の追加の際にカートに商品を入れられなくなる現象が起こりました。controllerはapplication,orders,carts,line_items,store,productsの６つ。modelは、order,cart,line_item,productの４つです。問題箇所だと思われる中身を載せてみます  
・carts_controller.rb

[code]

    class CartsController < ApplicationController
                  # before_action :set_cart, only: [:show, :edit, :update, :destroy]
    
                  def index
                    @carts = Cart.all
    
                    respond_to do |format|
                      format.html # index.html.erb
                      format.json { render json: @carts }
                    end
                  end
    
                  def show
                    begin
                        @cart = Cart.find(params[:id])
                    rescue ActiveRecord::RecordNotFound
                        logger.error "無効なカート#{params[:id]}にアクセスしようとしました"
                        redirect_to store_url, notice: '無効なカートです'
                    else
                        respond_to do |format|
                            format.html #show.html.erb
                            format.json { render json: @cart }
                        end
                    end
                  end
    
                  def new
                    @cart = Cart.new
    
                    respond_to do |format|
                      format.html # new.html.erb
                      format.json { render json: @cart }
                    end
                  end
    
                  def edit
                    @cart = Cart.find(params[:id])
    
                  end
    
                  def create
                    @cart = Cart.new(params[:cart])
    
                    respond_to do |format|
                      if @cart.save
                        format.html { redirect_to @cart, notice: 'Cart was successfully created.' }
                        format.json { render json: @cart, status: :created, location: @cart }
                      else
                        format.html { render :new }
                        format.json { render json: @cart.errors, status: :unprocessable_entity }
                      end
                    end
                  end
    
                  def update
                    @cart = Cart.find(params[:id])
    
                    respond_to do |format|
                      if @cart.update_attributes(params[:cart])
                        format.html { redirect_to @cart, notice: 'Cart was successfully updated.' }
                        format.json { head :ok }
                      else
                        format.html { render :edit }
                        format.json { render json: @cart.errors, status: :unprocessable_entity }
                      end
                    end
                  end
    
                  def destroy
                    @cart = current_cart
                    @cart.destroy
                    session[:cart_id] = nil
                    respond_to do |format|
                      format.html { redirect_to store_url }
                      format.json { head :ok }
                    end
                  end
    
                  # private
    
                  #   def set_cart
                  #     @cart = Cart.find(params[:id])
                  #   end
    
                  #   def cart_params
                  #     params.fetch(:cart, {})
                  #   end
                end
    
[/code]

・orders_controller.rb

[code]

          class OrdersController < ApplicationController
                  def new
                    @cart = current_cart
                    if @cart.line_items.empty?
                        redirect_to store_url, notice: "カートは空です"
                        return
                    end
    
                    @order = Order.new
    
                    respond_to do |format|
                        format.html
                        format.json { render json: @order }
                    end
                  end
    
                  def create
                    @order = Order.new(params[:order])
                    # @order = params[:order].permit(:name, :address, :email, :pay_type)
                    # Order.new(@order)
                    @order.add_line_items_from_cart(current_cart)
    
                    respond_to do |format|
                        if @order.save
                            Cart.destroy(session[:cart_id])
                            session[:cart_id] = nil
                            format.html {redirect_to store_url, notice: 
                                'ご注文ありがとうございます＾＾'}
                            format.json { render json: @order, status: :created, location: @order}
                        else
                            @cart = current_cart
                            format.html {render action: "new"}
                            format.json {render json: @order.errors,
                                status: :unprocessable_entity}
                        end
                    end
                  end
    
                  def index
                    @orders = Order.all
    
                    respond_to do |format|
                      format.html
                      format.json { render json: @orders }
                    end
                  end
    
                  def show
                    @order = Order.find(params[:id])
    
                    respond_to do |format|
                      format.html
                      format.json { render json: @order }
                    end
                  end
    
                  def edit
                    @order = Order.find(params[:id])
                  end
    
                  def update
                    @order = Order.find(params[:id])
    
                    respond_to do |format|
                      if @order.update_attributes(params[:order])
                        format.html { redirect_to @order, notice: 'Order was successfully updated.' }
                        format.json { head :ok }
                      else
                        format.html { render action: "edit" }
                        format.json { render json: @order.errors, status: :unprocessable_entity }
                      end
                    end
                  end
    
                  def destroy
                    @order = Order.find(params[:id])
                    @order.destroy
    
                    respond_to do |format|
                      format.html { redirect_to orders_url }
                      format.json { head :ok }
                    end
                  end
                end
    
[/code]

・line_items_controller.rb

[code]

     class LineItemsController < ApplicationController
                  before_action :set_line_item, only: [:show, :edit, :update, :destroy]
    
                  def index
                    @line_items = LineItem.all
                  end
    
                  def show
                    @line_item = LineItem.find(params[:id])
    
                    respond_to do |format|
                      format.html # show.html.erb
                      format.json { render json: @line_item }
                    end
                  end
    
                  def new
                    @line_item = LineItem.new
    
                    respond_to do |format|
                      format.html # new.html.erb
                      format.json { render json: @line_item }
                    end
                  end
    
                  def edit
                    @line_item = LineItem.find(params[:id])
                  end
    
                  def create
                    @cart = current_cart
                    product = Product.find(params[:product_id])
                    @line_item = @cart.add_product(product.id)
    
                    respond_to do |format|
                      if @line_item.save
                        # format.html { redirect_to store_url, notice: 'Line item was successfully created.' }
                        format.html { redirect_to store_url}
                        format.js { @current_item = @line_item}
                        format.json { render json: @line_item, status: :created, location: @line_item }
                      else
                        format.html { render action: "new" }
                        format.json { render json: @line_item.errors, status: :unprocessable_entity }
                      end
                    end
                  end
    
                  def update
                    @line_item = LineItem.find(params[:id])
    
                    respond_to do |format|
                      if @line_item.update(line_item_params)
                        format.html { redirect_to @line_item, notice: 'Line item was successfully updated.' }
                        format.json { render :show, status: :ok, location: @line_item }
                      else
                        format.html { render :edit }
                        format.json { render json: @line_item.errors, status: :unprocessable_entity }
                      end
                    end
                  end
    
                  def destroy
                    @line_item = LineItem.find(params[:id])
                    @line_item.destroy
                    respond_to do |format|
                      format.html { redirect_to store_url, notice: 'Line item was successfully destroyed.' }
                      format.json { head :no_content }
                    end
                  end
    
                  def decrease
                    @cart = current_cart
                    @line_item = @cart.decrease(params[:id])
    
                    respond_to do |format|
                        if @line_item.save
                            format.html{redirect_to store_url}
                            format.json{head :ok}
                        else
                            format.html{render action: "edit"}
                            format.json{render json: @line_item.errors, status: :unprocessable_entity}
                        end
                    end
                  end
    
                  def increase
                    @cart = current_cart
                    @line_item = @cart.increase(params[:id])
    
                    respond_to do |format|
                        if @line_item.save
                            format.html{redirect_to store_url}
                            format.json{head :ok}
                        else
                            format.html{render action: "edit"}
                            format.json{render json: @line_item.errors, status: :unprocessable_entity}
                        end
                    end
                  end
    
                  private
                    def set_line_item
                      @line_item = LineItem.find(params[:id])
                    end
    
                    def line_item_params
                      params.fetch(:line_item, {})
                    end
                end
    
[/code]

・cart.rb

[code]

    class Cart < ApplicationRecord
                    has_many :line_items, dependent: :destroy
    
                    def add_product(product_id)
                        current_item = line_items.find_by_product_id(product_id)
                        if current_item
                            current_item.quantity += 1
                        else
                            current_item = line_items.build(product_id: product_id)
                        end
                        current_item        
                    end
    
                    def decrease(line_item_id)
                        current_item = line_items.find(line_item_id)
                        if current_item.quantity > 1
                            current_item.quantity -= 1
                        else
                            current_item.destroy
                        end
                        current_item
                    end
    
                    def increase(line_item_id)
                        current_item = line_items.find(line_item_id)
                        current_item.quantity += 1
                        current_item        
                    end
    
                    def total_price
                        line_items.to_a.sum { |item| item.total_price }
                    end
                end
    
[/code]

・order.rb

[code]

    class Order < ApplicationRecord
                    PAYMENT_TYPES = ["現金","クレジットカード","注文書"]
                    has_many :line_items, dependent: :destroy
    
    
                    validates :name, :address, :email, presence: true
                    validates :pay_type, inclusion: PAYMENT_TYPES
    
                    def add_line_items_from_cart(cart)
                        cart.line_items.each do |item|
                            item.cart_id = nil
                            line_items << item
                        end
                    end
                end
    
[/code]

・line_item.rb

[code]

                class LineItem < ApplicationRecord
                    belongs_to :order
                    belongs_to :product
                    belongs_to :cart
    
                    def total_price
                        product.price * quantity
                    end
                end
    
[/code]

以上です。

色々試してみたところ、line_item.rbのbelongs_to
:orderを消すとカート機能はうまくいきます。ですがオーダー機能がうまく行かなくなるので、やはりbelongs_to
:orderは必要なのかなと思ってきてはいるのですがどうしたらいいものか。。。という現状です。

ちなみにカートに追加した時のターミナルの記述には rollback transaction が発生しております。  
後、参考にしている本ではscaffoldを使っているのですが自分はscaffold使わないようにしていますのでそのら辺での不具合もあるのかもしれません。

以上です。気になるところなどアドバイスいただけると幸いです。よろしくお願いしますm(_ _)m


CC BY-SA 3.0
2018-02-10T11:47:04.853
41630
2018-05-21T11:22:09.333
27359
question
ruby-on-rails
rails esサイト　カート機能とオーダー機能での不具合


自己解決できました。コメント欄にしか書いていなかったので回答します

line_itemとorderのアソシエーションを外して、`orders_controller`のcreateに`Order.new`を入れるオブジェクトを１つ増やしてそれを中継するような形で今の所解決できた気がします。

[code]

    ＠order = params[:order].permit(:name, :address, :email, :pay_type)
    ＠example = Order.new(@order)
    ＠example.add_line_items_from_cart(current_cart) 
    
[/code]

ありがとうございましたm(_ _)m

それと別のやり方ですが、アソシエーションが必要な場合。そのままの記述で、line_itemがcreateの際に`@line_item.save(validate:
false)`と記述します。saveの時のvalidateを外すというやり方です。こちらの方が自分的には都合良かったのであとで変えました！


CC BY-SA 4.0
2018-05-21T09:32:52.333
44132
2018-05-21T11:22:09.333
2018-05-21T11:22:09.333
3068
27359
41630
answer