Я следовал этому руководству , чтобы построить магазин с функциональностью корзины. Учебное пособие на этом закончилось, и я немного не готов к этому следующему шагу. Если бы кто-нибудь мог дать мне какое-то руководство по этому вопросу, я был бы очень признателен.
В настоящее время у меня есть товары, которые я могу добавить в корзину как line_items. Я не могу понять, как взять эти line_items из корзины и передать их в заказ. После того, как заказ сохранен / размещен, я хочу уничтожить корзину и начать все сначала, пока заказ обрабатывается.
Мои предположения ?: брать позиции из корзины в виде массива / га sh и добавить его в заказ, но как?
Rails 6.0.2.2 ruby 2.7.1p83 (редакция 2020-03-31 a0c7c23c9 c) [x86_64-linux] rbenv 1.1.2-28-gc2cfbd1
Модель тележки
class Order < ApplicationRecord
has_one :cart
# has_many :order_items, dependent: :destroy
# has_many :products, through: :order_items
# def add_cart(cart)
# current_cart = Cart.find(session[:cart_id])
# current_cart.line_items
# end
# def total_price
# line_items.to_a.sum { |item| item.total_price }
# end
end
Текущие проблемы с тележками в моделях
module CurrentCart
private
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
end
Модель LineItem
class LineItem < ApplicationRecord
belongs_to :product
belongs_to :cart
def total_price
product.price * quantity
end
end
Модель заказа
class Order < ApplicationRecord
belongs_to :cart
# has_many :order_items, dependent: :destroy
# has_many :products, through: :order_items
# def add_cart(cart)
# current_cart = Cart.find(session[:cart_id])
# current_cart.line_items
# end
# def total_price
# line_items.to_a.sum { |item| item.total_price }
# end
end
Контроллер тележки
class CartsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
#before_action :authenticate_user!, except: [:index, :show]
before_action :set_cart, only: [:show, :edit, :update, :destroy]
# GET /carts
# GET /carts.json
def index
@carts = Cart.all
end
# GET /carts/1
# GET /carts/1.json
def show
end
# GET /carts/new
def new
@cart = Cart.new
end
# GET /carts/1/edit
def edit
end
# POST /carts
# POST /carts.json
def create
@cart = Cart.new(cart_params)
respond_to do |format|
if @cart.save
format.html { redirect_to @cart, notice: 'Cart was successfully created.' }
format.json { render :show, status: :created, location: @cart }
else
format.html { render :new }
format.json { render json: @cart.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /carts/1
# PATCH/PUT /carts/1.json
def update
respond_to do |format|
if @cart.update(cart_params)
format.html { redirect_to @cart, notice: 'Cart was successfully updated.' }
format.json { render :show, status: :ok, location: @cart }
else
format.html { render :edit }
format.json { render json: @cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
@cart.destroy if @cart.id == session[:cart_id]
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to root_path, notice: 'Cart was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cart
@cart = Cart.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def cart_params
params.fetch(:cart, {})
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to root_path, notice: "That cart doesn't exist"
end
end
Контроллер LineItem
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
before_action :set_cart, only: [:create]
# GET /line_items
# GET /line_items.json
def index
@line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
@line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
@line_item = LineItem.find(params[:id])
end
# POST /line_items
# POST /line_items.json
def create
product = Product.find(params[:product_id])
@line_item = @cart.add_product(product)
respond_to do |format|
if @line_item.save
format.html { redirect_to @line_item.cart, notice: 'Item added to cart.' }
format.json { render :show, status: :created, location: @line_item }
else
format.html { render :new }
format.json { render json: @line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if @line_item.update(line_item_params)
format.html { redirect_to @line_item, notice: '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
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
@cart = Cart.find(session[:cart_id])
@line_item.destroy
respond_to do |format|
format.html { redirect_to cart_path(@cart), notice: 'Item successfully removed.' }
format.json { head :no_content }
end
end
def add_quantity
@line_item = LineItem.find(params[:id])
@line_item.quantity += 1
@line_item.save
redirect_to root_url
end
def reduce_quantity
@line_item = LineItem.find(params[:id])
if @line_item.quantity > 1
@line_item.quantity -= 1
end
@line_item.save
redirect_to root_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
@line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:product_id)
end
end
OrderController
class OrdersController < ApplicationController
before_action :set_cart, only: [:new, :create]
before_action :set_order, only: [:show, :edit, :update, :destroy]
# GET /orders
# GET /orders.json
def index
@orders = Order.all
end
# GET /orders/1
# GET /orders/1.json
def show
end
# GET /orders/new
def new
@order = Order.new
@order = @cart.line_items
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
@order = Order.new(order_params)
respond_to do |format|
if @order.save
format.html { redirect_to @order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: @order }
else
format.html { render :new }
format.json { render json: @order.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /orders/1
# PATCH/PUT /orders/1.json
def update
respond_to do |format|
if @order.update(order_params)
format.html { redirect_to @order, notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: @order }
else
format.html { render :edit }
format.json { render json: @order.errors, status: :unprocessable_entity }
end
end
end
# DELETE /orders/1
# DELETE /orders/1.json
def destroy
@order.destroy
respond_to do |format|
format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
@order = Order.find(params[:id])
end
# Only allow a list of trusted parameters through.
def order_params
params.fetch(:order, {})
end
end
Схема
ActiveRecord::Schema.define(version: 2020_04_22_162713) do
create_table "carts", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "line_items", force: :cascade do |t|
t.integer "product_id", null: false
t.integer "cart_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "quantity", default: 1
t.index ["cart_id"], name: "index_line_items_on_cart_id"
t.index ["product_id"], name: "index_line_items_on_product_id"
end
create_table "orders", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "cart_id"
t.index ["cart_id"], name: "index_orders_on_cart_id"
end
create_table "products", force: :cascade do |t|
t.string "product_type"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "length"
t.integer "width"
t.decimal "price", precision: 10, scale: 2
t.decimal "depth", precision: 3, scale: 3
end
create_table "themes", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "line_items", "carts"
add_foreign_key "line_items", "products"
add_foreign_key "orders", "carts"
end
Маршруты
Rails.application.routes.draw do
resources :orders
devise_for :users
resources :themes
resources :line_items
# resources :carts
resources :products
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
root "themes#index"
get 'carts/:id' => "carts#show", as: "cart"
delete 'carts/:id' => "carts#destroy"
post 'line_items/:id/add' => "line_items#add_quantity", as: "line_item_add"
post 'line_items/:id/reduce' => "line_items#reduce_quantity", as: "line_item_reduce"
post 'line_items' => "line_items#create"
delete 'line_items/:id' => "line_items#destroy"
end