Apakah ada cara untuk mengganti nilai id model saat membuat? Sesuatu seperti:
Post.create(:id => 10, :title => 'Test')
akan ideal, tetapi jelas tidak akan berhasil.
Apakah ada cara untuk mengganti nilai id model saat membuat? Sesuatu seperti:
Post.create(:id => 10, :title => 'Test')
akan ideal, tetapi jelas tidak akan berhasil.
Jawaban:
id hanya attr_protected, itulah sebabnya Anda tidak dapat menggunakan tugas massal untuk menyetelnya. Namun, saat mengaturnya secara manual, itu hanya berfungsi:
o = SomeObject.new
o.id = 8888
o.save!
o.reload.id # => 8888
Saya tidak yakin apa motivasi aslinya, tetapi saya melakukan ini saat mengonversi model ActiveHash ke ActiveRecord. ActiveHash memungkinkan Anda menggunakan semantik milik_to yang sama di ActiveRecord, tetapi alih-alih memiliki migrasi dan membuat tabel, dan menimbulkan overhead database pada setiap panggilan, Anda cukup menyimpan data Anda dalam file yml. Kunci asing dalam database mereferensikan id dalam memori di yml.
ActiveHash sangat bagus untuk daftar pilihan dan tabel kecil yang jarang berubah dan hanya diubah oleh pengembang. Jadi, saat beralih dari ActiveHash ke ActiveRecord, paling mudah adalah menyimpan semua referensi kunci asing yang sama.
ActiveRecord::VERSION::STRING == "3.2.11"
sini (dengan adaptor sqlite3) dan yang di atas berfungsi untuk saya.
Mencoba
a_post = Post.new do |p|
p.id = 10
p.title = 'Test'
p.save
end
yang akan memberikan apa yang Anda cari.
Anda juga bisa menggunakan sesuatu seperti ini:
Post.create({:id => 10, :title => 'Test'}, :without_protection => true)
Meskipun seperti yang dinyatakan dalam dokumen , ini akan melewati keamanan penugasan massal.
Untuk Rails 4:
Post.create(:title => 'Test').update_column(:id, 10)
Jawaban Rails 4 lainnya tidak berhasil untuk saya. Banyak dari mereka tampak berubah saat memeriksa menggunakan Rails Console, tetapi ketika saya memeriksa nilai di database MySQL, mereka tetap tidak berubah. Jawaban lain hanya kadang-kadang berhasil.
Untuk MySQL setidaknya, menetapkan di id
bawah nomor id penambahan otomatis tidak berfungsi kecuali Anda menggunakan update_column
. Sebagai contoh,
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
Jika Anda mengubah create
untuk menggunakan new
+, save
Anda masih akan mengalami masalah ini. Mengubah id
suka secara manual p.id = 10
juga menghasilkan masalah ini.
Secara umum, saya akan menggunakan update_column
untuk mengubah id
meskipun itu memerlukan biaya query database tambahan karena akan bekerja sepanjang waktu. Ini adalah kesalahan yang mungkin tidak muncul di lingkungan pengembangan Anda, tetapi diam-diam dapat merusak database produksi Anda sambil mengatakan bahwa itu berfungsi.
Post.new.update(id: 10, title: 'Test')
Sebenarnya, melakukan hal berikut ternyata berhasil:
p = Post.new(:id => 10, :title => 'Test')
p.save(false)
validate: false
, bukan hanya false
. Namun, Anda masih mengalami masalah atribut yang dilindungi - ada cara terpisah yang telah saya uraikan dalam jawaban saya.
Seperti yang Jeff tunjukkan, id berperilaku seolah-olah dilindungi_tarik. Untuk mencegahnya, Anda perlu mengganti daftar atribut default yang dilindungi. Berhati-hatilah saat melakukan ini di mana pun sehingga informasi atribut bisa berasal dari luar. Bidang id secara default dilindungi karena suatu alasan.
class Post < ActiveRecord::Base
private
def attributes_protected_by_default
[]
end
end
(Diuji dengan ActiveRecord 2.3.5)
kita dapat mengganti atribut_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 }
Ini tidak menurut saya sebagai hal yang biasanya ingin Anda lakukan, tetapi berfungsi dengan baik jika Anda perlu mengisi tabel dengan satu set id tetap (misalnya saat membuat default menggunakan tugas rake) dan Anda ingin mengganti penambahan otomatis (sehingga setiap kali Anda menjalankan tugas, tabel diisi dengan id yang sama):
post_types.each_with_index do |post_type|
PostType.create!(:name => post_type) { |t| t.id = i + 1 }
end
Letakkan fungsi create_with_id ini di bagian atas seed.rb Anda dan kemudian gunakan untuk melakukan pembuatan objek di mana id eksplisit diinginkan.
def create_with_id(clazz, params)
obj = clazz.send(:new, params)
obj.id = params[:id]
obj.save!
obj
end
dan gunakan seperti ini
create_with_id( Foo, {id:1,name:"My Foo",prop:"My other property"})
alih-alih menggunakan
Foo.create({id:1,name:"My Foo",prop:"My other property"})
Kasus ini adalah masalah serupa yang perlu ditimpa id
dengan jenis tanggal khusus:
# 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
Lalu :
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">
Callback berfungsi dengan baik.
Semoga berhasil!.
id
berdasarkan cap waktu Unix. Saya telah melakukan itu di dalam before_create
. Bekerja dengan baik.
Untuk Rails 3, cara paling sederhana untuk melakukan ini adalah dengan menggunakan new
dengan without_protection
perbaikan, dan kemudian save
:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save
Untuk data seed, mungkin masuk akal untuk melewati validasi yang dapat Anda lakukan seperti ini:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save(validate: false)
Kami sebenarnya telah menambahkan metode helper ke ActiveRecord :: Base yang dideklarasikan segera sebelum mengeksekusi file seed:
class ActiveRecord::Base
def self.seed_create(attributes)
new(attributes, without_protection: true).save(validate: false)
end
end
Dan sekarang:
Post.seed_create(:id => 10, :title => 'Test')
Untuk Rails 4, Anda harus menggunakan StrongParams alih-alih atribut yang dilindungi. Jika demikian, Anda dapat menetapkan dan menyimpan tanpa mengirimkan tanda apa pun ke new
:
Post.new(id: 10, title: 'Test').save # optionally pass `{validate: false}`
{}
seperti jawaban Samuel di atas (Rails3).
id
masih 10.
id
diteruskan sebagai 10 - jadi memang seharusnya begitu. Jika bukan itu yang Anda harapkan, dapatkah Anda menjelaskan dengan sebuah contoh?
Anda dapat memasukkan id dengan 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