Raylarda bir tarihi nasıl doğrularım?


92

Ruby on Rails'deki modelimdeki bir tarihi doğrulamak istiyorum, ancak gün, ay ve yıl değerleri modelime ulaştıklarında zaten yanlış bir tarihe dönüştürülmüş.

Örneğin, benim görüşüme göre 31 Şubat 2009'a girersem, Model.new(params[:model])kontrolörümde kullandığımda, bunu modelim geçerli bir tarih olarak gördüğü "3 Mart 2009" a dönüştürüyor, ki bu doğru ama yanlış.

Modelimde bu doğrulamayı yapabilmek istiyorum. Yapabileceğim herhangi bir yol var mı yoksa bu konuda tamamen yanlış mı yapıyorum?

Sorunu tartışan bu " Tarih doğrulamasını " buldum ama çözülemedi.


4
Bu soru şu anda Rails tarih doğrulaması için en iyi Google sonuçlarından biridir. Benim yaptığım gibi ilk geçişte kaçırabilirsiniz: seçilen cevabın önemli kısmı validates_timeliness cevheridir. Cevabın geri kalanını bile okumadım çünkü validates_timeliness'i başka bir yerde öğrendim ve bu mücevher, herhangi bir özel kod yazmak zorunda kalmadan ihtiyacım olan her şeyi yapıyor.
Jason Swett

Yanıtlar:


61

date_selectTarih için etiketleri oluşturmak için yardımcıyı kullandığınızı tahmin ediyorum . Bunu yapmanın başka bir yolu da gün, ay, yıl alanları için seçme formu yardımcısı kullanmaktır. Bunun gibi (kullandığım örnek, created_at tarih alanıdır):

<%= 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 %>

Ve modelde tarihi doğrularsınız:

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

Bir eklenti çözümü arıyorsanız, validates_timeliness eklentisine bakarım. Şöyle çalışır (github sayfasından):

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 

Mevcut doğrulama yöntemlerinin listesi aşağıdaki gibidir:

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.

Önerilen çözüm benim için çalışmıyor ve Rails 2.3.5 kullanıyorum
Roger

Daha temiz olması için yeniden yazdım ve Rails 2.3.5'e karşı test ettim ve bu benim için çalışıyor.
Jack Chu

Merhaba Jack, çözümünüzü denedim, benim için işe yarıyor attr_accessible: day,: month,: year. Bu benim için mantıklı değil ... Herhangi bir fikrin varsa teşekkürler!
benoitr

Rails 3'te github.com/adzap/validates_timeliness kullanıyorum ve bu harika.
Jason Swett

Validates_timeliness eklenti / mücevher kullanmak gerçekten güzel. Büyüleyici çalışır ve kodumu daha küçük tutar. Bahşiş için teşekkürler.
mjnissim

20

Kronik mücevherin kullanılması:

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

3
Bu özel örnekte, Chronic.parse(from_date_before_type_cast)dize değeri girdisini almak için kullanmak zorunda kaldım . Aksi takdirde Rails to_date, alan bir datetimealan olduğu için dizeyi yazardı .
Calvin

18

Rails 3 veya Ruby 1.9 uyumluluğunu istiyorsanız date_validator gemini deneyin .


Bunu daha yeni denedim. Doğrulamayı yüklemek ve eklemek 2 dakikanın tamamını aldı!
jflores

11

Aktif Kayıt, _before_type_casttip yayınlamadan önce ham nitelik verilerini içeren öznitelikleri verir . Bu, önceden yazma değerleri olan hata mesajlarını döndürmek veya sadece typecast'ten sonra mümkün olmayan doğrulamaları yapmak için yararlı olabilir.

Daniel Von Fange'nin erişimciyi geçersiz kılma önerisinden çekinirim, çünkü bir erişimcide doğrulama yapmak erişimci sözleşmesini biraz değiştirir. Active Record, bu durum için açıkça bir özelliğe sahiptir. Kullan onu.


4

Burada biraz geç, ama " Raylarda bir tarihi nasıl doğrularım? " Sayesinde bu doğrulayıcıyı yazmayı başardım, umut birileri için yararlıdır:

İçinde 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

4

Modelinizde bir tarihe dönüştürülmeden önce tarih dizesini işlemeniz gerektiğinden, bu alan için erişimciyi geçersiz kılardım

Diyelim ki tarih alanınız published_date. Bunu model nesnenize ekleyin:

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

Bunu bu amaçla kullanıp kullanmayacağımı bilmiyorum ama bu harika bir öneri.
Dan Rosenstark

1

İşte kronik olmayan bir cevap ..

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

1
Bu her zaman yanlış döndürür: "1/1/2013".is_a?(Date)- Tarih, kullanıcı girdisinden gelir, bu nedenle dize olarak beslenir. Önce bir tarih olarak ayrıştırmalı mıyım?
Mohamad

Doğru. Date.parse("1/1/2013").is_a?(Date), ama eğer hiç ayrıştırmazsa, muhtemelen bir tarih olmadığını da görebilirsiniz.
Yolculuk

1
Argüman hatasını kurtarmanız gerekiyor ... ahh, dizeyi otomatik olarak ayrıştırsa harika olurdu ... oh pekala, bunun için değerli taşlar var.
Mohamad

0

Tarih ve saati bu şekilde doğrulayabilirsiniz (kontrol cihazınızda herhangi bir yerde, özel seçimler kullanıyorsanız, parametrelerinize erişim sağlayan bir yöntemde) ...

# 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

-2

validates_date_timeEklentiyi denediniz mi?


Bu bağlantı soruyu cevaplayabilirken, cevabın temel kısımlarını buraya eklemek ve referans için bağlantıyı sağlamak daha iyidir. Bağlantılı sayfa değişirse yalnızca bağlantı yanıtları geçersiz hale gelebilir.
Pinal

Cevabımı daha çok beğendim. İki kişi aynı fikirde.
Ryan Duffield

4
@Pinal Bağlantı gerçekten artık öldü.
Wayne Conrad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.