Saya memiliki array objek, sebut saja itu Indicator
. Saya ingin menjalankan metode kelas Indikator (yang dari def self.subjects
varietas, cakupan, dll) pada larik ini. Satu-satunya cara yang saya tahu untuk menjalankan metode kelas pada sekelompok objek adalah membuatnya menjadi ActiveRecord :: Relation. Jadi saya akhirnya beralih ke to_indicators
metode Array
.
def to_indicators
# TODO: Make this less terrible.
Indicator.where id: self.pluck(:id)
end
Kadang-kadang saya merangkai beberapa cakupan ini untuk menyaring hasil, dalam metode kelas. Jadi, meskipun saya memanggil metode pada ActiveRecord :: Relation, saya tidak tahu cara mengakses objek itu. Saya hanya bisa mendapatkan isinya melalui all
. Tapi all
adalah Array. Jadi saya harus mengubah array itu menjadi ActiveRecord :: Relation. Misalnya, ini adalah bagian dari salah satu metode:
all.to_indicators.applicable_for_bank(id).each do |indicator|
total += indicator.residual_risk_for(id)
indicator_count += 1 if indicator.completed_by?(id)
end
Saya kira ini diringkas menjadi dua pertanyaan.
- Bagaimana cara mengubah Array objek menjadi ActiveRecord :: Relation? Lebih disukai tanpa melakukan
where
setiap waktu. - Saat menjalankan
def self.subjects
metode tipe pada ActiveRecord :: Relation, bagaimana cara mengakses objek ActiveRecord :: Relation itu sendiri?
Terima kasih. Jika saya perlu mengklarifikasi sesuatu, beri tahu saya.
sumber
.all
, gunakan saja.scoped
seperti yang ditunjukkan oleh jawaban Andrew Marshall (Meskipun di rel 4 itu akan berhasil.all
). Jika Anda merasa perlu mengubah array menjadi relasi yang salah di suatu tempat ...Jawaban:
Anda tidak dapat mengonversi Array menjadi ActiveRecord :: Relation karena Relation hanyalah pembuat kueri SQL dan metodenya tidak beroperasi pada data aktual.
Namun, jika yang Anda inginkan adalah relasi, maka:
untuk ActiveRecord 3.x, jangan panggil
all
dan sebaliknya panggilscoped
, yang akan mengembalikan Relasi yang mewakili rekaman yang sama yangall
akan diberikan kepada Anda dalam Array.untuk ActiveRecord 4.x, cukup panggil
all
, yang mengembalikan Relasi.Ketika metode dipanggil pada objek Relasi,
self
adalah relasinya (sebagai lawan dari kelas model yang didefinisikannya).sumber
class User; def self.somewhere; where(location: "somewhere"); end; end
, makaUser.limit(5).somewhere
Anda dapat mengonversi larik objek
arr
menjadi ActiveRecord :: Relation seperti ini (dengan asumsi Anda mengetahui kelas objek tersebut, yang mungkin Anda lakukan)Anda harus menggunakannya
where
, itu adalah alat yang berguna yang tidak boleh enggan Anda gunakan. Dan sekarang Anda memiliki satu baris yang mengonversi array menjadi relasi.map(&:id)
akan mengubah array objek Anda menjadi array yang hanya berisi id mereka. Dan meneruskan array ke klausa where akan menghasilkan pernyataan SQLIN
yang terlihat seperti:Perlu diingat bahwa pengurutan array akan hilang - Tetapi karena tujuan Anda hanya menjalankan metode kelas pada koleksi objek-objek ini, saya berasumsi itu tidak akan menjadi masalah.
sumber
where(id: arr.map(&:id))
? Dan secara tegas, ini tidak mengubah array menjadi relasi, tetapi mendapatkan instance baru dari objek (setelah relasinya terwujud) dengan ID yang mungkin memiliki nilai atribut berbeda dari instance yang sudah ada di memori dalam array.Nah, dalam kasus saya, saya perlu mengubah array objek ke ActiveRecord :: Relation serta mengurutkannya dengan kolom tertentu (id misalnya). Karena saya menggunakan MySQL, fungsi bidang dapat membantu.
SQL terlihat seperti:
Fungsi bidang MySQL
sumber
ActiveRecord::Relation
mengikat query database yang mengambil data dari database.Anggaplah masuk akal, Kami memiliki array dengan objek dari kelas yang sama, lalu dengan kueri mana kami seharusnya mengikatnya?
Saat aku lari,
Di sini, di atas,
users
kembalikanRelation
objek tetapi mengikat kueri database di belakangnya dan Anda dapat melihatnya,Jadi tidak mungkin untuk kembali
ActiveRecord::Relation
dari larik objek yang tidak bergantung pada kueri sql.sumber
Pertama-tama, ini BUKAN peluru perak. Dari pengalaman saya, saya menemukan bahwa mengubah menjadi relasi terkadang lebih mudah daripada alternatif. Saya mencoba menggunakan pendekatan ini dengan sangat hemat dan hanya dalam kasus di mana alternatifnya akan lebih kompleks.
Yang dikatakan di sini adalah solusi saya, saya telah memperpanjang
Array
kelasContoh penggunaannya adalah
array.to_activerecord_relation.update_all(status: 'finished')
. Sekarang di mana saya menggunakannya?Terkadang Anda perlu memfilter
ActiveRecord::Relation
misalnya mengambil elemen yang belum selesai. Dalam kasus tersebut yang terbaik adalah menggunakan ruang lingkupelements.not_finished
dan Anda akan tetap menyimpannyaActiveRecord::Relation
.Namun terkadang kondisi tersebut lebih kompleks. Keluarkan semua elemen yang belum selesai, dan yang telah diproduksi dalam 4 minggu terakhir dan telah diperiksa. Untuk menghindari membuat cakupan baru, Anda bisa memfilter ke array lalu mengonversinya kembali. Ingatlah bahwa Anda masih melakukan kueri ke DB, cepat karena DB mencari berdasarkan
id
tetapi masih kueri.sumber