Rails에서 날짜를 어떻게 확인합니까?


92

Ruby on Rails에서 모델의 날짜를 확인하고 싶지만 일, 월, 연도 값이 모델에 도달 할 때 이미 잘못된 날짜로 변환되었습니다.

예를 들어, 내보기에 2009 년 2 월 31 일을 입력하면 Model.new(params[:model])컨트롤러에서 사용할 때 "2009 년 3 월 3 일"로 변환됩니다. 그러면 내 모델이 유효한 날짜로 간주되지만 정확하지 않습니다.

내 모델에서이 유효성 검사를 수행하고 싶습니다. 내가 할 수있는 방법이 있습니까? 아니면 완전히 잘못된 것입니까?

문제를 설명하는 " 날짜 유효성 검사 "를 찾았 지만 해결되지 않았습니다.


4
이 질문은 현재 Rails 날짜 유효성 검사에 대한 상위 Google 결과 중 하나입니다. 내가 한 것처럼 첫 번째 패스에서 놓칠 수 있습니다. 선택한 답변의 중요한 부분은 validates_timeliness gem입니다. 다른 곳에서 validates_timeliness에 대해 알게 되었기 때문에 나머지 답변도 읽지 않았고 그 gem은 사용자 지정 코드를 작성하지 않고도 필요한 모든 것을 수행합니다.
Jason Swett

답변:


61

date_select도우미를 사용 하여 날짜에 대한 태그를 생성하고 있다고 생각합니다 . 할 수있는 또 다른 방법은 일, 월, 연도 필드에 대한 선택 양식 도우미를 사용하는 것입니다. 다음과 같이 (내가 사용한 예는 created_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 %>

그리고 모델에서 날짜를 확인합니다.

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

플러그인 솔루션을 찾고 있다면 validates_timeliness 플러그인을 확인 하겠습니다 . 다음과 같이 작동합니다 (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 

사용 가능한 유효성 검사 방법 목록은 다음과 같습니다.

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.

제안 된 솔루션이 저에게 적합하지 않으며 Rails 2.3.5를 사용하고 있습니다
Roger

나는 그것을 깨끗하게 다시 작성하고 Rails 2.3.5에 대해 테스트했으며 이것은 나를 위해 작동합니다.
Jack Chu

안녕하세요 Jack, 솔루션을 시도해 보았습니다 .attr_accessible : day, : month, : year를 추가하면 작동합니다. 그건 말이 안 돼요 ... 어떤 생각이 있으면 감사합니다!
benoitr 2011 년

Rails 3에서는 github.com/adzap/validates_timeliness를 사용하고 있는데 정말 훌륭합니다.
Jason Swett

validates_timeliness의 플러그인 / 보석은 정말 사용하기 좋다. 매력적으로 작동하고 내 코드를 작게 유지합니다. 팁 고마워.
mjnissim

20

만성 보석 사용 :

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
이 특정 예제에서는 Chronic.parse(from_date_before_type_cast)문자열 값 입력을 얻기 위해 사용해야 했습니다. 그렇지 않으면 Rails는 to_date필드가 필드이기 때문에 문자열을 타입 캐스트 할 것 datetime입니다.
Calvin

18

Rails 3 또는 Ruby 1.9 호환성을 원한다면 date_validator gem을 사용 해보세요 .


나는 이것을 시도했다. 설치하고 유효성 검사를 추가하는 데 2 ​​분이 소요되었습니다!
jflores

11

Active Record는 _before_type_cast타입 캐스팅 전에 원시 속성 데이터를 포함하는 속성을 제공합니다 . 이는 사전 형변환 값이있는 오류 메시지를 반환하거나 형변환 후 불가능한 유효성 검사를 수행하는 데 유용 할 수 있습니다.

접근 자에서 유효성 검사를 수행하면 접근 자 계약이 약간 변경되기 때문에 Daniel Von Fange의 접근 자 재정의 제안을 피할 것입니다. Active Record에는 이러한 상황에 대한 명시적인 기능이 있습니다. 그걸 써.


4

모델에서 날짜로 변환되기 전에 날짜 문자열을 처리해야하므로 해당 필드에 대한 접근자를 재정의합니다.

날짜 필드가 published_date. 이것을 모델 객체에 추가하십시오.

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

이 목적을 위해 이것을 사용할지 모르겠지만 좋은 제안입니다.
Dan Rosenstark

3

조금 늦었지만 " 레일에서 날짜를 어떻게 확인합니까? " 덕분 에이 유효성 검사기를 작성할 수 있었으므로 희망이 누군가에게 유용합니다.

당신의 내부 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

1

다음은 비만 성적인 대답입니다 ..

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
이것은 항상 false를 반환합니다 "1/1/2013".is_a?(Date).-날짜는 사용자 입력에서 나오므로 문자열로 제공됩니다. 먼저 날짜로 구문 분석해야합니까?
Mohamad

옳은. Date.parse("1/1/2013").is_a?(Date), 그러나 전혀 구문 분석하지 않으면 날짜가 아닐 수도 있음을 알 수 있습니다.
여행

1
인수 오류를 구해야합니다 ... 아, 그냥 문자열을 자동으로 파싱했다면 멋 졌을 것입니다 ... 오 글쎄요.
Mohamad

0

날짜와 시간의 유효성을 검사 할 수 있습니다 (사용자 지정 선택을 사용하는 경우 매개 변수에 액세스 할 수있는 컨트롤러 어딘가의 메서드에서) ...

# 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

-3

validates_date_time플러그인 을 사용해 보셨습니까 ?


이 링크가 질문에 답할 수 있지만 여기에 답변의 필수 부분을 포함하고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 무효화 될 수 있습니다.
Pinal

나는 내 대답을 더 좋아한다. 두 사람이 동의합니다.
Ryan Duffield

4
@Pinal 링크는 실제로 죽었습니다.
Wayne Conrad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.