我正在开发一个示例项目,允许创建订单,由许多产品组成,通过LineItems关联(请参阅我最近在Should I include other fields in a HABTM table?提出的问题)。
一旦我对新对象的视图被渲染,我就可以访问@orders对象了,看起来我应该像往常一样收集@line_items。问题是,@ orders对象尚未保存。
到目前为止,我在网上找到的最好的例子是a Railscasts writeup,它似乎鼓励在会话中存储对象参数:
def new
session[:order_params] ||= {}
@order = Order.new(session[:order_params])
@order.current_step = session[:order_step]
end
当我处理每个订单存储多个产品(通过LineItem)时,我只是不确定如何最好地支付这个费用。我想到的一件事是在数据库中创建并保存对象,但只有在用户实际保存它时才将其标记为“真实”(而不仅仅是在订单中添加项目) - 但是给出了放弃率等等,似乎我可能会得到太多的垃圾。
是否有一个被广泛接受的惯例来接受未保存的新订单并“正确地”构建一个has_many产品列表?为了记录,我试图使用RoR复制project I built in PHP,如果这有助于提供我的最终游戏的上下文。
我的架构(旨在支持为多个属性订购礼品卡)看起来像:
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 3) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "line_items", id: false, force: true do |t|
t.integer "order_id"
t.integer "product_id"
t.decimal "pay_cost", precision: 8, scale: 2, null: false
t.decimal "pay_discount", precision: 8, scale: 2, default: 0.0
t.decimal "pay_linetotal", precision: 8, scale: 2, null: false
t.text "note"
end
add_index "line_items", ["order_id", "product_id"], name: "index_line_items_on_order_id_and_product_id", unique: true, using: :btree
create_table "orders", force: true do |t|
t.string "order_id", null: false
t.integer "property_id"
t.string "order_status", default: "new"
t.string "email_address"
t.string "bill_name"
t.string "bill_address1"
t.string "bill_address2"
t.string "bill_city"
t.string "bill_state"
t.string "bill_zip"
t.string "ship_name"
t.string "ship_address1"
t.string "ship_address2"
t.string "ship_city"
t.string "ship_state"
t.string "ship_zip"
t.string "pay_cardtype"
t.string "pay_pastfour"
t.text "order_summary"
t.boolean "is_gift", default: false
t.text "order_message"
t.boolean "pay_live", default: false
t.boolean "pay_paid", default: false
t.boolean "pay_refunded", default: false
t.decimal "pay_total", precision: 8, scale: 2, null: false
t.decimal "pay_discount", precision: 8, scale: 2, default: 0.0
t.integer "stripe_fee"
t.string "stripe_token"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "orders", ["order_id"], name: "index_orders_on_order_id", unique: true, using: :btree
add_index "orders", ["order_status"], name: "index_orders_on_order_status", using: :btree
create_table "products", force: true do |t|
t.string "name", null: false
t.decimal "price", precision: 8, scale: 2, null: false
t.boolean "active", default: true
end
create_table "products_properties", id: false, force: true do |t|
t.integer "product_id"
t.integer "property_id"
end
add_index "products_properties", ["product_id", "property_id"], name: "index_products_properties_on_product_id_and_property_id", unique: true, using: :btree
create_table "properties", force: true do |t|
t.string "name", null: false
t.string "slug", null: false
t.string "prefix", null: false
t.string "phone"
t.text "address"
t.string "email"
t.boolean "visible", default: true
end
add_index "properties", ["prefix"], name: "index_properties_on_prefix", unique: true, using: :btree
add_index "properties", ["slug"], name: "index_properties_on_slug", unique: true, using: :btree
create_table "properties_users", id: false, force: true do |t|
t.integer "user_id"
t.integer "property_id"
end
add_index "properties_users", ["user_id", "property_id"], name: "index_properties_users_on_user_id_and_property_id", unique: true, using: :btree
create_table "users", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "email", null: false
t.string "encrypted_password", default: "", null: false
t.datetime "locked_at"
t.boolean "active", default: true, null: false
t.boolean "superuser", default: false, null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
end
答案 0 :(得分:1)
将它存储在会话中应该没问题。如果您已配置为使用CookieStore进行会话,请尝试尽可能减少数据(理想情况下只是产品ID)。如果您有多步结帐流程,您可能还想查看wicked之类的内容。
我鼓励您考虑直接在数据库中存储订单。这可以让你做一些很酷的事情,比如当他们回到你的网站时向用户展示他们的废弃购物车,或者向在流程中间离开的人发送提醒电子邮件/特别优惠。
您还需要一个预定的清理流程来清除早于几周/几个月的不完整订单。
答案 1 :(得分:1)
要在请求之间保留购物车,您可以在会话中存储必要的详细信息,也可以使用实际的数据库记录,并将订单标记为临时/未确认。 在使用数据库的简单场景中,可能会过度,但您肯定希望避免在会话中使用复杂数据。如果你将来改变一些东西,它可能会破坏旧的会话。
我正在开发一个简单的网上商店,所以我将展示我如何使用会话来存储和检索工作订单。我在[{1}}中存储一个哈希,其中键是产品ID,值是数量
添加到购物车操作
session[:cart]
def add_to_cart
product = Product.find(params[:product_id])
session[:cart][product.id] ||= 0
session[:cart][product.id] += 1
redirect_to :back
end
方法在请求之间恢复before_action
@order
订单型号
class ApplicationController < ActionController::Base
before_action :restore_order
private
def restore_order
session[:cart] ||= {}
@order = Order.build_from_session(session[:cart])
end
end