มีวิธีใดในการลบล้างค่า id ของโมเดลในการสร้างหรือไม่ สิ่งที่ต้องการ:
Post.create(:id => 10, :title => 'Test')
จะเหมาะ แต่เห็นได้ชัดว่าใช้ไม่ได้
มีวิธีใดในการลบล้างค่า id ของโมเดลในการสร้างหรือไม่ สิ่งที่ต้องการ:
Post.create(:id => 10, :title => 'Test')
จะเหมาะ แต่เห็นได้ชัดว่าใช้ไม่ได้
คำตอบ:
id เป็นเพียง attr_protected ซึ่งเป็นสาเหตุที่คุณไม่สามารถใช้การกำหนดจำนวนมากเพื่อตั้งค่าได้ อย่างไรก็ตามเมื่อตั้งค่าด้วยตนเองจะใช้งานได้:
o = SomeObject.new
o.id = 8888
o.save!
o.reload.id # => 8888
ฉันไม่แน่ใจว่าแรงจูงใจดั้งเดิมคืออะไร แต่ฉันทำเช่นนี้เมื่อแปลงโมเดล ActiveHash เป็น ActiveRecord ActiveHash ช่วยให้คุณสามารถใช้ความหมายเป็นของเดียวกับใน ActiveRecord แต่แทนที่จะมีการโยกย้ายและสร้างตารางและทำให้เกิดค่าใช้จ่ายของฐานข้อมูลในทุกการโทรคุณเพียงแค่จัดเก็บข้อมูลของคุณในไฟล์ yml คีย์นอกในฐานข้อมูลอ้างอิงรหัสในหน่วยความจำใน yml
ActiveHash เหมาะสำหรับรายการเลือกและตารางขนาดเล็กที่มีการเปลี่ยนแปลงไม่บ่อยนักและมีการเปลี่ยนแปลงโดยนักพัฒนาเท่านั้น ดังนั้นเมื่อเปลี่ยนจาก ActiveHash เป็น ActiveRecord วิธีที่ง่ายที่สุดก็คือให้การอ้างอิงคีย์ต่างประเทศทั้งหมดเหมือนกัน
ActiveRecord::VERSION::STRING == "3.2.11"
ที่นี่แล้ว (ด้วยอะแดปเตอร์ sqlite3) และข้างต้นใช้ได้กับฉัน
ลอง
a_post = Post.new do |p|
p.id = 10
p.title = 'Test'
p.save
end
ที่ควรให้สิ่งที่คุณกำลังมองหา
คุณยังสามารถใช้สิ่งนี้:
Post.create({:id => 10, :title => 'Test'}, :without_protection => true)
แม้ว่าตามที่ระบุไว้ในเอกสารนี้จะข้ามการรักษาความปลอดภัยการมอบหมายงานจำนวนมาก
สำหรับ Rails 4:
Post.create(:title => 'Test').update_column(:id, 10)
คำตอบอื่น ๆ Rails 4 ไม่ได้ผลสำหรับฉัน หลายคนดูเหมือนจะเปลี่ยนไปเมื่อตรวจสอบโดยใช้ Rails Console แต่เมื่อฉันตรวจสอบค่าในฐานข้อมูล MySQL ค่านั้นก็ยังไม่เปลี่ยนแปลง คำตอบอื่น ๆ ใช้ได้ผลในบางครั้งเท่านั้น
สำหรับ MySQL อย่างน้อยการกำหนดid
ดังต่อไปนี้หมายเลขรหัสที่เพิ่มขึ้นรถยนต์ไม่ไม่update_column
ทำงานเว้นแต่คุณจะใช้ ตัวอย่างเช่น,
p = Post.create(:title => 'Test')
p.id
=> 20 # 20 was the id the auto increment gave it
p2 = Post.create(:id => 40, :title => 'Test')
p2.id
=> 40 # 40 > the next auto increment id (21) so allow it
p3 = Post.create(:id => 10, :title => 'Test')
p3.id
=> 10 # Go check your database, it may say 41.
# Assigning an id to a number below the next auto generated id will not update the db
ถ้าคุณเปลี่ยนcreate
ไปใช้new
+ save
คุณจะยังคงมีปัญหานี้ การเปลี่ยนสิ่งที่id
ชอบด้วยตนเองp.id = 10
ก็ทำให้เกิดปัญหานี้
โดยทั่วไปฉันจะใช้update_column
เพื่อเปลี่ยนid
แม้ว่าจะมีค่าใช้จ่ายในการสืบค้นฐานข้อมูลเพิ่มเติมเนื่องจากจะทำงานตลอดเวลา นี่เป็นข้อผิดพลาดที่อาจไม่ปรากฏในสภาพแวดล้อมการพัฒนาของคุณ แต่สามารถทำให้ฐานข้อมูลการผลิตของคุณเสียหายอย่างเงียบ ๆ ในขณะที่บอกว่ากำลังทำงานอยู่
Post.new.update(id: 10, title: 'Test')
อันที่จริงปรากฎว่าการทำงานต่อไปนี้:
p = Post.new(:id => 10, :title => 'Test')
p.save(false)
validate: false
false
อย่างไรก็ตามคุณยังคงพบปัญหาแอตทริบิวต์ที่มีการป้องกัน - มีวิธีแยกต่างหากซึ่งฉันได้ระบุไว้ในคำตอบของฉัน
ดังที่เจฟฟ์ชี้ให้เห็น id จะทำงานราวกับว่ามีการป้องกัน Attr_protected เพื่อป้องกันไม่ให้คุณต้องลบล้างรายการของแอตทริบิวต์ที่มีการป้องกันเริ่มต้น ระวังการทำเช่นนี้ทุกที่ที่ข้อมูลแอตทริบิวต์สามารถมาจากภายนอกได้ ฟิลด์ id ได้รับการป้องกันโดยค่าเริ่มต้นด้วยเหตุผล
class Post < ActiveRecord::Base
private
def attributes_protected_by_default
[]
end
end
(ทดสอบด้วย ActiveRecord 2.3.5)
เราสามารถแทนที่ attributes_protected_by_default
class Example < ActiveRecord::Base
def self.attributes_protected_by_default
# default is ["id", "type"]
["type"]
end
end
e = Example.new(:id => 10000)
Post.create!(:title => "Test") { |t| t.id = 10 }
สิ่งนี้ไม่ได้ตีฉันว่าเป็นสิ่งที่คุณต้องการทำตามปกติ แต่จะทำงานได้ดีถ้าคุณต้องการเติมข้อมูลในตารางด้วยชุดรหัสคงที่ (เช่นเมื่อสร้างค่าเริ่มต้นโดยใช้งานคราด) และคุณ ต้องการลบล้างการเพิ่มขึ้นอัตโนมัติ (เพื่อให้ทุกครั้งที่คุณรันงานตารางจะถูกเติมด้วยรหัสเดียวกัน):
post_types.each_with_index do |post_type|
PostType.create!(:name => post_type) { |t| t.id = i + 1 }
end
วางฟังก์ชันcreate_with_idนี้ไว้ที่ด้านบนสุดของ seed.rb ของคุณจากนั้นใช้เพื่อสร้างอ็อบเจกต์ของคุณในที่ที่ต้องการรหัสที่ชัดเจน
def create_with_id(clazz, params)
obj = clazz.send(:new, params)
obj.id = params[:id]
obj.save!
obj
end
และใช้แบบนี้
create_with_id( Foo, {id:1,name:"My Foo",prop:"My other property"})
แทนที่จะใช้
Foo.create({id:1,name:"My Foo",prop:"My other property"})
กรณีนี้เป็นปัญหาที่คล้ายกันซึ่งจำเป็นต้องเขียนทับid
ด้วยวันที่ที่กำหนดเอง:
# in app/models/calendar_block_group.rb
class CalendarBlockGroup < ActiveRecord::Base
...
before_validation :parse_id
def parse_id
self.id = self.date.strftime('%d%m%Y')
end
...
end
แล้ว:
CalendarBlockGroup.create!(:date => Date.today)
# => #<CalendarBlockGroup id: 27072014, date: "2014-07-27", created_at: "2014-07-27 20:41:49", updated_at: "2014-07-27 20:41:49">
การโทรกลับทำงานได้ดี
โชคดี!.
id
ประทับเวลาตาม Unix ฉันได้ทำภายในbefore_create
แล้ว ใช้งานได้ดี
สำหรับ Rails 3 วิธีที่ง่ายที่สุดคือใช้new
กับการwithout_protection
ปรับแต่งจากนั้นsave
:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save
สำหรับข้อมูลเมล็ดพันธุ์คุณควรหลีกเลี่ยงการตรวจสอบความถูกต้องซึ่งคุณสามารถทำได้ดังนี้:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save(validate: false)
เราได้เพิ่มวิธีการช่วยเหลือลงใน ActiveRecord :: Base ที่ประกาศทันทีก่อนที่จะเรียกใช้ไฟล์ seed:
class ActiveRecord::Base
def self.seed_create(attributes)
new(attributes, without_protection: true).save(validate: false)
end
end
และตอนนี้:
Post.seed_create(:id => 10, :title => 'Test')
สำหรับ Rails 4 คุณควรใช้ StrongParams แทนแอตทริบิวต์ที่มีการป้องกัน หากเป็นกรณีนี้คุณจะสามารถกำหนดและบันทึกได้โดยไม่ต้องส่งแฟล็กใด ๆ ไปที่new
:
Post.new(id: 10, title: 'Test').save # optionally pass `{validate: false}`
{}
ตามคำตอบของซามูเอลด้านบน (Rails3)
id
ยังคงเป็น 10
id
ถูกส่งผ่านเป็น 10 - นั่นคือสิ่งที่ควรจะเป็น หากนั่นไม่ใช่สิ่งที่คุณคาดหวังคุณสามารถอธิบายด้วยตัวอย่างได้หรือไม่?
ใน Rails 4.2.1 พร้อม Postgresql 9.5.3 Post.create(:id => 10, :title => 'Test')
ทำงานได้ตราบเท่าที่ยังไม่มีแถวที่มี id = 10 อยู่แล้ว
คุณสามารถแทรก id โดย sql:
arr = record_line.strip.split(",")
sql = "insert into records(id, created_at, updated_at, count, type_id, cycle, date) values(#{arr[0]},#{arr[1]},#{arr[2]},#{arr[3]},#{arr[4]},#{arr[5]},#{arr[6]})"
ActiveRecord::Base.connection.execute sql