Saya mencoba menemukan cara terbaik untuk mengatur nilai default untuk objek di Rails.
Yang terbaik yang dapat saya pikirkan adalah mengatur nilai default dalam new
metode di pengontrol.
Apakah ada yang punya masukan jika ini dapat diterima atau jika ada cara yang lebih baik untuk melakukannya?
ruby-on-rails
ruby
biagidp
sumber
sumber
Jawaban:
"Benar" adalah kata yang berbahaya di Ruby. Biasanya ada lebih dari satu cara untuk melakukan sesuatu. Jika Anda tahu Anda akan selalu menginginkan nilai default untuk kolom itu di tabel itu, mengaturnya dalam file migrasi DB adalah cara termudah:
Karena ActiveRecord menemukan properti tabel dan kolom Anda secara otomatis, ini akan menyebabkan default yang sama disetel di model mana pun yang menggunakannya di aplikasi Rails standar.
Namun, jika Anda hanya ingin nilai default ditetapkan dalam kasus tertentu - katakanlah, itu adalah model yang diwariskan yang berbagi tabel dengan beberapa orang lain - maka cara elegan lainnya adalah melakukannya secara langsung di kode Rails Anda ketika objek model dibuat:
Kemudian, saat Anda melakukan a
GenericPerson.new()
, atribut "Doe" akan selalu menetes ke atasPerson.new()
kecuali Anda menimpanya dengan sesuatu yang lain.sumber
.new
metode kelas. Diskusi postingan blog tentang pemanggilan langsung ActiveRecord.allocate
adalah tentang objek model yang dimuat dengan data yang ada dari database. ( Dan itu ide yang buruk bagi ActiveRecord untuk bekerja seperti itu, IMO. Tapi bukan itu intinya.)change_column_default :people, :last_name, nil
stackoverflow.com/a/1746246/483520change_column :people, :last_name, :string, default: "Doe"
Berdasarkan jawaban SFEley, berikut ini adalah yang diperbarui / diperbaiki untuk versi Rails yang lebih baru:
sumber
change_column
bisa jadi sangat "penataan", operasi kebalikannya tidak dapat disimpulkan. Jika Anda tidak yakin, cukup uji dengan menjalankandb:migrate
dandb:rollback
setelahnya. Jawaban yang diterima sebagai hasil yang sama tetapi setidaknya itu diasumsikan!up
dandown
seperti yang dijelaskan di atas dari @GoBustoPertama-tama Anda tidak dapat membebani
initialize(*args)
karena tidak dipanggil dalam semua kasus.Pilihan terbaik Anda adalah menempatkan default Anda ke dalam migrasi Anda:
Terbaik kedua adalah menempatkan default ke dalam model Anda, tetapi ini hanya akan berfungsi dengan atribut yang awalnya nihil. Anda mungkin mengalami masalah seperti yang saya lakukan dengan
boolean
kolom:Anda memerlukan
new_record?
agar default tidak menimpa nilai yang dimuat dari database.Anda harus
||=
menghentikan Rails dari mengganti parameter yang diteruskan ke metode inisialisasi.sumber
after_initiation :your_method_name
.... 2 penggunaanself.max_users ||= 10
after_initialize do
alih-alihdef after_initialize
Anda juga dapat mencoba
change_column_default
migrasi Anda (diuji di Rails 3.2.8):change_column_default dokumen API Rails
sumber
Jika Anda merujuk ke objek ActiveRecord, Anda memiliki (lebih dari) dua cara untuk melakukan ini:
1. Gunakan: parameter default di DB
MISALNYA
Info lebih lanjut di sini: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
2. Gunakan panggilan balik
MISALNYA
before_validation_on_create
Info lebih lanjut di sini: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147
sumber
Di Ruby on Rails v3.2.8, dengan menggunakan
after_initialize
callback ActiveRecord, Anda bisa memanggil metode dalam model Anda yang akan menetapkan nilai default untuk objek baru.Jadi, IMO itu akan terlihat seperti:
Foo.bar = default_value
untuk contoh ini kecuali jika contoh tersebut berisiattribute_whose_presence_has_been_validated
penyimpanan / pembaruan sebelumnya. Thedefault_value
kemudian akan digunakan bersama dengan pandangan Anda untuk membuat bentuk menggunakandefault_value
untukbar
atribut.Paling banter ini hacky ...
EDIT - gunakan 'catatan_baru?' untuk memeriksa apakah membuat instance dari panggilan baru
Alih-alih memeriksa nilai atribut, gunakan
new_record?
metode bawaan dengan rel. Jadi, contoh di atas akan terlihat seperti:Ini jauh lebih bersih. Ah, keajaiban Rails - lebih pintar dariku.
sumber
after_initialize
panggilan balik di sini? Dokumentasi Rails tentang callback memiliki contoh pengaturan nilai defaultbefore_create
tanpa pemeriksaan kondisi tambahanSubscription
after_initialize
, alih-alihbefore_create
callback, adalah kita ingin menyetel nilai default untuk pengguna (untuk digunakan dalam tampilan) saat mereka membuat objek baru. Thebefore_create
callback disebut setelah para pengguna telah menjabat objek baru, memberikan masukan mereka, dan diserahkan objek untuk penciptaan ke controller. Pengontrol kemudian memeriksa setiapbefore_create
panggilan balik. Tampaknya kontra-intuitif, tetapi ini adalah nomenklatur -before_create
mengacu padacreate
tindakan. Membuat instance objek baru bukanlahcreate
objek.Untuk bidang boolean di Rails 3.2.6 setidaknya, ini akan berfungsi dalam migrasi Anda.
Menempatkan
1
atau0
untuk default tidak akan berfungsi di sini, karena ini adalah bidang boolean. Ini harus berupatrue
ataufalse
nilai.sumber
Jika Anda berurusan dengan Model, Anda dapat menggunakan Attriutes API di Rails 5+ http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute
cukup tambahkan migrasi dengan nama kolom yang tepat dan kemudian atur model dengan:
sumber
Hasilkan migrasi dan gunakan
change_column_default
, ringkas dan dapat dibalik:sumber
Jika Anda hanya menetapkan default untuk atribut tertentu dari model yang didukung database, saya akan mempertimbangkan untuk menggunakan nilai kolom default sql - dapatkah Anda menjelaskan jenis default yang Anda gunakan?
Ada sejumlah pendekatan untuk menanganinya, plugin ini sepertinya merupakan opsi yang menarik.
sumber
Saran untuk menimpa baru / menginisialisasi mungkin tidak lengkap. Rails akan (sering) memanggil alokasi untuk objek ActiveRecord, dan panggilan untuk mengalokasikan tidak akan menghasilkan panggilan untuk diinisialisasi.
Jika Anda berbicara tentang objek ActiveRecord, lihat overriding after_initialize.
Posting blog ini (bukan milik saya) berguna:
Nilai default Konstruktor default tidak dipanggil
[Sunting: SFEley menunjukkan bahwa Rails benar-benar melihat default dalam database ketika membuat instance objek baru dalam memori - saya tidak menyadarinya.]
sumber
Saya perlu mengatur default seperti jika itu ditentukan sebagai nilai kolom default di DB. Jadi berperilaku seperti ini
Karena callback after_initialize dipanggil setelah menyetel atribut dari argumen, tidak ada cara untuk mengetahui apakah atribut tersebut nihil karena tidak pernah disetel atau karena sengaja disetel sebagai nil. Jadi saya harus sedikit mencari tahu dan datang dengan solusi sederhana ini.
Bekerja dengan baik untuk saya. (Rel 3.2.x)
sumber
Cara yang berpotensi lebih baik / lebih bersih daripada jawaban yang diajukan adalah dengan menimpa pengakses, seperti ini:
Lihat "Menimpa pengakses default" dalam dokumentasi ActiveRecord :: Base dan lainnya dari StackOverflow tentang penggunaan self .
sumber
saya menjawab pertanyaan serupa di sini .. cara bersih untuk melakukan ini adalah menggunakan Rails attr_accessor_with_default
MEMPERBARUI
attr_accessor_with_default sudah tidak digunakan lagi di Rails 3.2 .. Anda bisa melakukan ini dengan Ruby murni
sumber
attr_accessor_with_default
dihentikan pada rel> 3.1.0Jika Anda berbicara tentang objek ActiveRecord, saya menggunakan permata 'atribut-default'.
Dokumentasi & unduh: https://github.com/bsm/attribute-defaults
sumber
Anda bisa menggunakan permata rails_default_value. misalnya:
https://github.com/keithrowell/rails_default_value
sumber
Anda dapat mengganti konstruktor untuk model ActiveRecord.
Seperti ini:
sumber