【问题标题】:Duplicating record and it's children - but children get deleted from old record复制记录和它的孩子 - 但孩子会从旧记录中删除
【发布时间】:2015-12-29 16:57:02
【问题描述】:

我的问题类似于: My cloning method is stealing the children from the original model

但我似乎无法找到适用于我的解决方案。我正在尝试创建一个订单交换表单,其中涉及使用旧记录详细信息填充表单。因此,当我保存表单时,它会创建一个新的订单记录,但孩子们似乎已从旧的订单记录中删除并被吸入新的订单记录。

代码如下:

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

【问题讨论】:

  • 您能否将架构的相关部分添加到您的问题中。
  • 我复制了我认为相关的内容。有点长见谅

标签: ruby-on-rails postgresql ruby-on-rails-4 clone duplication


【解决方案1】:

我的方法是覆盖 Order 模型中的 ActiveRecord::Base#dup 方法,使其具有递归性,这意味着它也复制了 LineItem 集合:

class Order < ActiveRecord::Base
  def dup
    duped_order = super
    duped_order.line_items = line_items.map(&:dup)
    duped_order
  end
end

这样做可以很容易地进行测试。现在控制器变成了:

class OrderController < ApplicationController
  def new
    @order = Order.find(params[:id]).dup
  end

  def create
    # not sure how your form populates the params hash
    # here you need to new-up and then save the order and the line items
    # with the attributes from the form
  end
end

请编写测试以确认这是否符合您的预期。这是应该应用旧的“胖模型瘦控制器”范例的完美示例。

【讨论】:

  • 我已经尝试过了,但是当我在“创建”时出现了问题。从代码中,我传递了“exchange_order_params”(我已添加到我的 sn-p),但产品 ID 正在寻找 LineItem id(错误:对于 ID= 的 LineItem,找不到 ID=2 的产品)。我注意到 LineItem id 和 Order id 现在由于某种奇怪的原因为零(可能来自 dup)。我需要旧的 LineItem 和 Order id 才能将旧记录传递给新记录(当然具有不同的 ID)。抱歉,如果这有点难以理解,但我正在尽力解释我的问题。
  • 另外提一下,我需要保留 ID。我不能把它们拿出来。我知道,如果我删除了 id,它会起作用,但是它会引发另一个问题,该问题已通过保留 id 得到解决。那么有没有办法在复制旧 LineItem Id 时传递它?
  • 如果您需要保留 id,那么您不是在“克隆”对象,而是在使用实际的原始对象,所以我不明白您要做什么。是的,“dup”删除了 id,这通常是所需的行为。您提到的“其他问题”可能可以在不保留 ID 的情况下解决。根据我对您问题的理解,您不应该复制 ID,但也许我不完全理解您的问题。如果您想详细说明“其他问题”,也许我们可以解决那个问题。
  • 是的,很抱歉,很难解释,但基本上我有一个列出所有产品和库存水平的产品表。因此,ID 的来源是我创建新订单记录的地方,但它需要更新产品表中的库存水平。我知道克隆记录但保留 ID 听起来很奇怪,但我基本上是在制作一个交换订单表格,它采用旧订单的属性并填充一个订单新表格(因为我想从旧的的)。
  • 因此,将 ids 保留在强参数中意味着我更新 products 表,而不是创建新记录。我在这里找到了这个解决方案:stackoverflow.com/questions/18946479/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多