开发者

Date Validation In Rails 3

I've got a Rails 3 app (using Mongodb and Mongoid if that makes a difference), and in one of my models I have a field defined as a Date type.

class Participant
  include Mongoid::Document

  field :birth_date, :type => Date
end

My controller is using the find_or_initialize_by feature of mongo:

class ParticipantController

  def create
    @participant = Participant.find_or_initialize_by(params[:participant])
    if @participant.save
      redirect_to participants_path
    else
      render :new
    end
  end
end

All this boils down to: how do I do date validation in ActiveModel with Mongoid and Rails 3?

I want to make sure an input of "blah" as in a textbox does not throw an exception when assigned to the .birth_date field of my model. It should provides a nice validation error message without using the controller to do the validation.

Here's the basic requirements:

  • The view must be a single textbox. Nothing else. This is a user requirement that we cannot change

  • The validation should be done in the model, not in the controller or the

    view (javascript or whatever)

  • No regex format validations (they don't work right / support locale's etc)

The pro开发者_JAVA百科blem is that the value from the textbox is assigned to the .birth_date before validates_format_of and validates_presence_of are run. so...

how do I intercept the assignment of the value, so that I can validate it before it gets assigned? is it possible to do that in the model, using ActiveModel? or does this require me putting code in the controller to do this?


This small block of code may do the trick

retVal = "it is a date"
begin
  y = Date.parse("rodman was here")
rescue
  retVal = "nope not a date"
end

puts retVal


The validates_timeliness gem is pretty sweet. You can just do something like this:

class Participant < ActiveRecord::Base
  validates_date :birth_date
end


I've just found this, though I haven't yet played with it:

http://blog.codegram.com/2011/2/date-validation-with-rails-3

Github repository is at https://github.com/codegram/date_validator

Quoting from the blog posting:

"You can use it either in Rails 3 models or in any custom class (after requiring ActiveModel), in a really easy manner

They also give an example that makes it seem like it should work for you - it's done in the model, rather than in the controller.

validates expiration_date,
    :date => { :after => Time.now, :before => Time.now + 1.year }


You need to use before_validation filter for e.g. in your model

class Participant
  include Mongoid::Document
  before_validation :make_a_date
  field :birth_date, :type => Date

  private
  def make_a_date
    #do all sorts of manipulation of the date here
  end
end

another alternative would be to create your own validation method? But I don't think thats what you want...


An alternative is to create a validation class that extends ActiveModel::EachValidator, e.g.:

class TimeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value && !value.kind_of?(Time)
      record.errors[attribute] << (options[:message] || "don't recognise time")
    end
  end
end

In the above example I'm coupling this with a setter method on the model that handles the parsing if a string is passed in. I wanted to support fuzzy date time matching so I'm using Chronic.

require 'chronic'

def starts_at=(value)
  if value.kind_of?(String) && parsed_time = Chronic.parse(value)
    @starts_at = parsed_time.utc
  else
    @starts_at = value
  end
end

and this to set up the validator on the model

validates :starts_at, :time => true

Which is nice and conventional.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜