Rel 6
Rails 6 menambahkan upsert
dan upsert_all
metode yang memberikan fungsionalitas ini.
Model.upsert(column_name: value)
[upsert] Ini tidak membuat contoh model apa pun juga tidak memicu callback atau validasi Rekaman Aktif.
Rel 5, 4, dan 3
Tidak jika Anda mencari jenis pernyataan "upsert" (di mana database menjalankan pembaruan atau pernyataan sisipkan dalam operasi yang sama). Di luar kotak, Rails dan ActiveRecord tidak memiliki fitur seperti itu. Namun, Anda dapat menggunakan permata upsert .
Jika tidak, Anda dapat menggunakan: find_or_initialize_by
atau find_or_create_by
, yang menawarkan fungsionalitas serupa, meskipun dengan biaya hit database tambahan, yang, dalam banyak kasus, hampir tidak menjadi masalah sama sekali. Jadi, kecuali Anda memiliki masalah kinerja yang serius, saya tidak akan menggunakan permata itu.
Misalnya, jika tidak ada pengguna yang ditemukan dengan nama "Roger", instance pengguna baru akan dibuat dengan name
set ke "Roger".
user = User.where(name: "Roger").first_or_initialize
user.email = "[email protected]"
user.save
Atau, Anda bisa menggunakan find_or_initialize_by
.
user = User.find_or_initialize_by(name: "Roger")
Di Rails 3.
user = User.find_or_initialize_by_name("Roger")
user.email = "[email protected]"
user.save
Anda dapat menggunakan sebuah blok, tetapi blok tersebut hanya berjalan jika recordnya baru .
User.where(name: "Roger").first_or_initialize do |user|
user.save
end
User.find_or_initialize_by(name: "Roger") do |user|
user.save
end
Jika Anda ingin menggunakan blok terlepas dari persistensi record, gunakan tap
hasil:
User.where(name: "Roger").first_or_initialize.tap do |user|
user.email = "[email protected]"
user.save
end
find_or_initialize_by
danfind_or_create_by
menerima satu blok. Saya pikir yang Anda maksud adalah apakah record ada atau tidak, sebuah blok akan diturunkan dengan objek record sebagai argumen, untuk melakukan pembaruan.Di Rails 4 Anda dapat menambahkan model tertentu:
def self.update_or_create(attributes) assign_or_new(attributes).save end def self.assign_or_new(attributes) obj = first || new obj.assign_attributes(attributes) obj end
dan menggunakannya seperti
User.where(email: "[email protected]").update_or_create(name: "Mr A Bbb")
Atau jika Anda lebih suka menambahkan metode ini ke semua model, masukkan penginisialisasi:
module ActiveRecordExtras module Relation extend ActiveSupport::Concern module ClassMethods def update_or_create(attributes) assign_or_new(attributes).save end def update_or_create!(attributes) assign_or_new(attributes).save! end def assign_or_new(attributes) obj = first || new obj.assign_attributes(attributes) obj end end end end ActiveRecord::Base.send :include, ActiveRecordExtras::Relation
sumber
assign_or_new
mengembalikan baris pertama dalam tabel jika ada dan kemudian baris itu akan diperbarui? Sepertinya melakukan itu untuk saya.User.where(email: "[email protected]").first
akan mengembalikan nihil jika tidak ditemukan. Pastikan Anda memiliki ruangwhere
lingkupupdated_at
tidak akan disentuh karenaassign_attributes
digunakanTambahkan ini ke model Anda:
def self.update_or_create_by(args, attributes) obj = self.find_or_create_by(args) obj.update(attributes) return obj end
Dengan itu, Anda dapat:
User.update_or_create_by({name: 'Joe'}, attributes)
sumber
Keajaiban yang Anda cari telah ditambahkan di
Rails 6
Sekarang Anda dapat melakukan upsert (perbarui atau sisipkan). Untuk penggunaan rekaman tunggal:Model.upsert(column_name: value)
Untuk beberapa catatan, gunakan upsert_all :
Model.upsert_all(column_name: value, unique_by: :column_name)
Catatan :
sumber
Pertanyaan lama tapi melemparkan solusi saya ke ring untuk kelengkapan. Saya membutuhkan ini ketika saya membutuhkan penemuan khusus tetapi pembuatan yang berbeda jika tidak ada.
def self.find_by_or_create_with(args, attributes) # READ CAREFULLY! args for finding, attributes for creating! obj = self.find_or_initialize_by(args) return obj if obj.persisted? return obj if obj.update_attributes(attributes) end
sumber
Anda dapat melakukannya dalam satu pernyataan seperti ini:
CachedObject.where(key: "the given key").first_or_create! do |cached| cached.attribute1 = 'attribute value' cached.attribute2 = 'attribute value' end
sumber
The sekuel permata menambahkan update_or_create metode yang tampaknya melakukan apa yang Anda cari.
sumber