我的问题类似于: My cloning method is stealing the children from the original model
但我似乎无法为此解决这个问题。我正在尝试创建一个订单交换表单,其中包含使用旧记录详细信息填充表单。因此,当我保存表单时,它会创建一个新的Order记录,但是孩子们似乎从旧的Order记录中删除并被虹吸到新记录中。
以下是代码:
def new
@old_order = Order.includes(:line_items).find(params[:id])
@order = Order.new @old_order.attributes
@order.line_items = []
@old_order.line_items.each do |old|
new = old.dup # the line_item id is set before creation.
new.order_id = @order.id
new.save!
@order.line_items << new
@old_order.line_items << old # this was to see if the old line_items would reappend to the old order. Didn't help...
end
end
def create
@order = Order.new(exchange_order_params)
if @order.save
@order.update_attributes!(stage: 2, ordered_at: Date.today)
redirect_to admin_returns_url, notice: "Order moved to 'accepted' for processing"
else
flash.now[:alert] = "Please try again"
render :action => "new"
end
end
private
def exchange_order_params
params.require(:order).permit(:id, :user_id,
line_items_attributes: [:id, :order_id, :cart_id, :quantity, :_destroy,
product_attributes: [:id, :sku, :euro_price, :sterling_price, :product_group_id, :product_size_id, :product_waistband_id]])
end
Schema.rb
create_table "orders", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "returned", default: false
t.date "date_sent"
t.date "ordered_at"
t.integer "user_id"
t.boolean "return_requested", default: false
t.integer "stage", default: 0
t.decimal "order_total", default: 0.0
t.string "transaction_secret"
t.string "token"
t.string "uuid"
t.string "currency"
t.float "discounted_by", default: 0.0
end
add_index "line_items", ["cart_id"], name: "index_line_items_on_cart_id", using: :btree
add_index "line_items", ["order_id"], name: "index_line_items_on_order_id", using: :btree
add_index "line_items", ["product_id"], name: "index_line_items_on_product_id", using: :btree
create_table "line_items", force: :cascade do |t|
t.integer "quantity"
t.integer "order_id"
t.integer "cart_id"
t.integer "product_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.float "unit_price"
t.string "currency"
end
create_table "product_groups", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "product_sizes", force: :cascade do |t|
t.string "specification"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "product_waistbands", force: :cascade do |t|
t.string "specification"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.integer "sku"
t.integer "product_group_id"
t.integer "product_size_id"
t.integer "product_waistband_id"
t.decimal "euro_price"
t.decimal "sterling_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "stock_level", default: 0
end
add_index "products", ["product_group_id"], name: "index_products_on_product_group_id", using: :btree
add_index "products", ["product_size_id"], name: "index_products_on_product_size_id", using: :btree
add_index "products", ["product_waistband_id"], name: "index_products_on_product_waistband_id", using: :btree
同样在订单模型中,我随机化了id before_create,以便当用户提交表单时,它会创建一个具有不同订单ID的欺骗副本。 LineItems也是如此。
Order.rb(在LineItem.rb中相同)
before_create :randomize_id
private
def randomize_id
begin
self.id = SecureRandom.random_number(1_000_000)
end while Order.where(id: self.id).exists?
end
答案 0 :(得分:0)
我的方法是覆盖Order模型中的ActiveRecord :: Base#dup方法,使其具有递归性,这意味着它也会复制LineItem集合:
-e '2 k 1024 / 1024 / n [ MiB] p'
这样做可以很容易地测试它。现在控制器变为:
class Order < ActiveRecord::Base
def dup
duped_order = super
duped_order.line_items = line_items.map(&:dup)
duped_order
end
end
写测试以确认这是在做你想要的。这是应该应用旧的“胖模型瘦控制器”范例的完美示例。