rails_to 重复记录

rails_to for a duplicate record

以下代码在控制台中运行良好,并且做我想做的(第一行就可以,其他只是模拟更改。实际上它是真实的,这些是唯一需要的更改):

irb(main):012:0> year = Year.find(678).dup
  Year Load (0.4ms)  SELECT "years".* FROM "years" WHERE "years"."id" =  ORDER BY "years"."year_date" ASC LIMIT   [["id", 678], ["LIMIT", 1]]
=> #<Year id: nil, year_date: "1905-09-01", created_at: nil, updated_at: nil, resto: false, resid: true, file_basename: nil, person_id: 86, location_id: 95, title: "Resident", notes: "", resto_name: "", aws_url: nil, from_where_url: nil, caption: nil, croatian: true, from_where: nil, doc_id: 66>
irb(main):013:0> year.location_id = 211
=> 211
irb(main):014:0> year.resto = true
=> true
irb(main):015:0> year.resid = false
=> false
irb(main):016:0> year.title = "Co-proprietor"
=> "Co-proprietor"
irb(main):017:0> year.save
   (0.3ms)  BEGIN
  Location Load (0.5ms)  SELECT "locations".* FROM "locations" WHERE "locations"."id" =  LIMIT   [["id", 211], ["LIMIT", 1]]
  Person Load (0.3ms)  SELECT "people".* FROM "people" WHERE "people"."id" =  LIMIT   [["id", 86], ["LIMIT", 1]]
  Doc Load (0.2ms)  SELECT "docs".* FROM "docs" WHERE "docs"."id" =  LIMIT   [["id", 66], ["LIMIT", 1]]
  Year Create (5.3ms)  INSERT INTO "years" ("year_date", "created_at", "updated_at", "resto", "resid", "person_id", "location_id", "title", "notes", "resto_name", "croatian", "doc_id") VALUES (, , , , , , , , , , , ) RETURNING "id"  [["year_date", "1905-09-01"], ["created_at", "2020-05-10 15:12:37.102224"], ["updated_at", "2020-05-10 15:12:37.102224"], ["resto", true], ["resid", false], ["person_id", 86], ["location_id", 211], ["title", "Co-proprietor"], ["notes", ""], ["resto_name", ""], ["croatian", true], ["doc_id", 66]]
   (40.9ms)  COMMIT
=> true

当然,我会在 editnew 页面中进行更改。我只希望使用我所在的 show 页面中信息的副本创建该页面。用例是创建一堆记录,许多记录几乎是重复的,但确实需要手动完成,因为没有更改信息的模式。

我创建了各种按钮,但没有任何效果

<%= link_to 'Duplicate this connection (FIXME)', new_year_path(@year.dup), action: dup %>

与:

def dup
  @year = Year.find(params[:id]).dup
end

另一个迭代:<%= link_to 'Duplicate this connection (FIXME)', edit_year_path(@year.dup) %> No route matches {:action=>"edit", :controller=>"years", :id=>nil}, missing required keys: [:id]

我对此迷路了,但可能没那么难。

当您在此处对 ActiveRecord 模型对象调用 #.dup 时,它会复制除 id 和基本时间戳之外的所有属性。这意味着您有一个未持久化的对象。这就是您收到异常消息的原因。

假设您要复制记录 678,比方说,我期望这样的路径:

/years/new?base_id=678

在上面,base_id=678是查询字符串参数。

你会像这样生成它:

<%= link_to "Duplicate", new_year_path(base_id: @year&.id) %>

(当然假设@year已经初始化)

然后,在您的控制器操作中:

def new
  @year = Year.find_by(id: params[:base_id])&.dup || Year.new
end

假设我们找到有问题的 Year 记录,我们复制它。否则,我们回退到一个新的 Year 对象,一切都很好。

这应该可以解决您的问题。

搜索要复制的记录,调用attributes获取所有属性键值,丢弃时间戳列并将其传递给create方法以创建记录。

def dup
  year = Year.find(params[:id])

  @year = Year.create!(year.attributes.except("created_at", "updated_at"))
end
resources :years do
  get :duplicate
end
class Year < ApplicationRecord
  # creates a new instance of year with a a subset of the attributes
  # @return [Year] 
  def duplicate
    # attributes returns a hash with string keys 
    whitelist = %w( foo bar baz )
    self.class.new(attributes.slice(*whitelist))
  end
end
class YearsController < ApplicationController

  # ...

  # GET /years/:id/duplicate 
  def duplicate
    @year = Year.find(:id).duplicate 
    render :new
  end

  # ...
end

将要复制的属性列入白名单而不是列入黑名单可能是个好主意。