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.
精彩评论