ruby-on-rails - 复制记录及其子项 - 但子项会从旧记录中删除

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

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

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

代码如下:

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

架构.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

同样在 Order 模型中,我将 id before_create 随机化,这样当用户提交表单时,它会创建一个具有不同 Order 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

最佳答案

我的方法是重写 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

这样做可以使其易于测试。现在 Controller 变为:

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

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

关于ruby-on-rails - 复制记录及其子项 - 但子项会从旧记录中删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32890944/

相关文章:

postgresql - 使用 SQLAlchemy 通过 unix 套接字连接到数据库

ruby-on-rails - finder_sql 不使用 Rails 解析字符串

c# - x32 应用程序可以使用 x64 数据库吗?

ruby-on-rails - rails 与 has_many 的错误关联

ruby-on-rails - 为 nil :NilClass 设计 Rspec 未定义方法 `env'

ruby-on-rails - Rails URL 生成器切换 http/https

ruby-on-rails - Heroku 中的 unicorn ?为什么不在开发中?

ruby-on-rails - 如何使用 Koala gem 取消用户 Facebook 权限

ruby - rails ransack gem 搜索 json 列

ruby-on-rails-4 - PG::ConnectionBad:将 rails 从 4.2 升级到 5.2 后连接关闭