Saya ingin memvalidasi tanggal dalam model saya di Ruby on Rails, namun, nilai hari, bulan dan tahun sudah diubah menjadi tanggal yang salah pada saat mereka mencapai model saya.
Misalnya, jika saya memasukkan 31 Februari 2009 dalam pandangan saya, ketika saya menggunakan Model.new(params[:model])
di controller saya, itu mengubahnya menjadi "3 Maret 2009", yang kemudian dilihat model saya sebagai tanggal yang valid, yang sebenarnya, tetapi itu salah.
Saya ingin dapat melakukan validasi ini dalam model saya. Adakah cara yang saya bisa, atau apakah saya melakukan ini sepenuhnya salah?
Saya menemukan " Validasi tanggal " yang membahas masalah tetapi tidak pernah terselesaikan.
ruby-on-rails
ruby
validation
date
Megamug
sumber
sumber
Jawaban:
Saya menduga Anda menggunakan
date_select
helper untuk menghasilkan tag untuk tanggal tersebut. Cara lain yang bisa Anda lakukan adalah dengan menggunakan pilih formulir pembantu untuk bidang hari, bulan, tahun. Seperti ini (contoh yang saya gunakan adalah bidang tanggal create_at):<%= f.select :month, (1..12).to_a, selected: @user.created_at.month %> <%= f.select :day, (1..31).to_a, selected: @user.created_at.day %> <%= f.select :year, ((Time.now.year - 20)..Time.now.year).to_a, selected: @user.created_at.year %>
Dan dalam model, Anda memvalidasi tanggal:
attr_accessor :month, :day, :year validate :validate_created_at private def convert_created_at begin self.created_at = Date.civil(self.year.to_i, self.month.to_i, self.day.to_i) rescue ArgumentError false end end def validate_created_at errors.add("Created at date", "is invalid.") unless convert_created_at end
Jika Anda mencari solusi plugin, saya akan memeriksa plugin validates_timeliness . Ini berfungsi seperti ini (dari halaman github):
class Person < ActiveRecord::Base validates_date :date_of_birth, on_or_before: lambda { Date.current } # or validates :date_of_birth, timeliness: { on_or_before: lambda { Date.current }, type: :date } end
Daftar metode validasi yang tersedia adalah sebagai berikut:
validates_date - validate value as date validates_time - validate value as time only i.e. '12:20pm' validates_datetime - validate value as a full date and time validates - use the :timeliness key and set the type in the hash.
sumber
Menggunakan permata kronis:
class MyModel < ActiveRecord::Base validate :valid_date? def valid_date? unless Chronic.parse(from_date) errors.add(:from_date, "is missing or invalid") end end end
sumber
Chronic.parse(from_date_before_type_cast)
untuk mendapatkan input nilai string. Jika tidak, Rails akan memasukkan stringto_date
karena bidang itu adalahdatetime
bidang.Jika Anda menginginkan kompatibilitas Rails 3 atau Ruby 1.9, coba gem date_validator .
sumber
Rekaman Aktif memberi Anda
_before_type_cast
atribut yang berisi data atribut mentah sebelum typecasting. Ini dapat berguna untuk mengembalikan pesan kesalahan dengan nilai pra-typecast atau hanya melakukan validasi yang tidak mungkin dilakukan setelah typecast.Saya akan menghindari saran Daniel Von Fange untuk menimpa pengakses, karena melakukan validasi di pengakses mengubah sedikit kontrak pengakses. Rekaman Aktif memiliki fitur secara eksplisit untuk situasi ini. Gunakan.
sumber
Agak terlambat di sini, tetapi berkat " Bagaimana cara memvalidasi tanggal di rel? " Saya berhasil menulis validator ini, harapan berguna bagi seseorang:
Di dalam Anda
model.rb
validate :date_field_must_be_a_date_or_blank # If your field is called :date_field, use :date_field_before_type_cast def date_field_must_be_a_date_or_blank date_field_before_type_cast.to_date rescue ArgumentError errors.add(:birthday, :invalid) end
sumber
Karena Anda perlu menangani string tanggal sebelum diubah menjadi tanggal dalam model Anda, saya akan mengganti pengakses untuk bidang itu
Misalkan bidang tanggal Anda adalah
published_date
. Tambahkan ini ke objek model Anda:def published_date=(value) # do sanity checking here # then hand it back to rails to convert and store self.write_attribute(:published_date, value) end
sumber
Inilah jawaban non-kronis ..
class Pimping < ActiveRecord::Base validate :valid_date? def valid_date? if scheduled_on.present? unless scheduled_on.is_a?(Time) errors.add(:scheduled_on, "Is an invalid date.") end end end
sumber
"1/1/2013".is_a?(Date)
- Tanggal berasal dari input pengguna, jadi diberi makan sebagai string. Saya harus menguraikannya sebagai kencan dulu?Date.parse("1/1/2013").is_a?(Date)
, tetapi Anda dapat melihat bahwa jika tidak diurai sama sekali, mungkin juga bukan tanggal.Anda dapat memvalidasi tanggal dan waktu seperti itu (dalam metode di suatu tempat di pengontrol Anda dengan akses ke parameter Anda jika Anda menggunakan pilihan kustom) ...
# Set parameters year = params[:date][:year].to_i month = params[:date][:month].to_i mday = params[:date][:mday].to_i hour = params[:date][:hour].to_i minute = params[:date][:minute].to_i # Validate date, time and hour valid_date = Date.valid_date? year, month, mday valid_hour = (0..23).to_a.include? hour valid_minute = (0..59).to_a.include? minute valid_time = valid_hour && valid_minute # Check if parameters are valid and generate appropriate date if valid_date && valid_time second = 0 offset = '0' DateTime.civil(year, month, mday, hour, minute, second, offset) else # Some fallback if you want like ... DateTime.current.utc end
sumber
Sudahkah Anda mencoba
validates_date_time
pengaya?sumber