How to set date interpretation/format? - ruby

I am dynamically updating the underlying model by passing the parameters from the posted form to the model like this:
#model.assign_attributes(params[:model])
I have a date coming in along with the rest of the post data in the format mm/dd/yyyy. Ruby appears to be parsing this date as if it is in the format dd/mm/yyyy, as far as I can tell. So, when I enter a date of 4/15/2014, for instance, the model fails to save because the month 15 does not exist (I assume, in reality I am just told that the date field is required).
How can I configure Ruby to parse my dates as mm/dd/yyyy?

Use the strptime method for date and supply the format.
Date.strptime("4/15/2014","%m/%d/%Y")
#=> #<Date: 2014-04-15 ((2456763j,0s,0n),+0s,2299161j)>
You will probably have to specify a call back like before_update if you want the conversion to happen in the model.
e.g.
class YourModel < ActiveRecord::Base
before_update :format_date
def format_date
date_field = Date.strptime(date_field,'%m/%d/%Y')
end
end

Related

Rails 5: Insert/Update only if there's no filled specific field for that id

I have a Followups table with the fields: patient_id, death_date (and other fields..).
There could be multiple records for the same patient_id but there must be only one death_date for that patient_id.
A unique index won't work as the user could insert two different death_date.
Which is the best way to achieve this in Rails 5?
If possible, please make an example.
Thanks
You could do this with a callback on the Followup model:
Assuming a Patient has_many :followups
class Followup
belongs_to :patient
validate :check_for_existing_death_date
private
def check_for_existing_death_date
# This will grab the first one if any with a death date exist
# This also assumes that the patient_id and patient exist
followup = patient.followups.where("death_date IS NOT NULL").take
# if you want to raise an error...
if followup
errors.add(:death_date, 'There is already a death date for this patient')
return false
end
# If not, do something with the data
# if followup
# self.death_date = nil # or followup.death_date if you want it saved on followups as well
# end
end
end
I would think that the best way to do this would be to store the death_date on the Patient record, since death only happens once per patient.

How to check whether correct date format has been provided

I'm currently working through the Well-Grounded Rubyist and have a question about an exercise that is asking to check whether a date provided is in the format 'yyyy-mm-dd' as opposed to 'yy-mm-dd'.
We have a class Ticket and should create a date= method that checks whether the date provided is in the above mentioned format.
Is .strftime correct to use here?
In the end the method should return the date in the correct format and provide an error message for dates in the wrong format, like so:
ticket = Ticket.new
ticket.date = "2013-11-12"
=> "2013-11-12"
ticket.date = "13-11-12"
=> "Please submit the date in the format 'yyyy-mm-dd'."
Could someone indicate how I could perform these checks on dates?
Date::xmlschema is strict about this specific format (try this in IRB):
require 'date'
Date.xmlschema("2013-11-12") #<Date: 2013-11-12 ((2456609j,0s,0n),+0s,2299161j)>
#invalid month number:
Date.xmlschema("2013-13-12") #<ArgumentError: invalid date>
# 2 digit year:
Date.xmlschema("13-11-12") #<ArgumentError: invalid date>
# no leap year:
Date.xmlschema("2013-02-29") #<ArgumentError: invalid date>
You can throw the error to the user by using begin..rescue
require 'date'
begin
Date.parse("31-02-2010")
rescue => e
p "#{e}" #print your own custom messages and return accordingly
end
Also write
rescue ArgumentError
It will throw By default error
ArgumentError (invalid date)

Changing ID to something more friendly

When creating a record the URL generated to view that record ends with its id
/record/21
I would like to be able to change that to something easier to read, such as my name and reference attributes from the model. I have looked at friendly_id but has trouble implementing a custom method to generate the URL
class Animal < ActiveRecord::Base
extend FriendlyId
friendly_id :name_and_ref
def name_and_ref
"#{name}-#{reference}"
end
end
I ended up getting an error
PG::UndefinedColumn: ERROR: column animals.name_and_ref does not exist LINE 1: SELECT "animals".* FROM "animals" WHERE "animals"."name_an... ^ : SELECT "animals".* FROM "animals" WHERE "animals"."name_and_ref" = 'Clawd-A123456' ORDER BY "animals"."id" ASC LIMIT 1
def show
#animal = Animal.friendly.find(params[:id])
end
I then come across the to_param method which Rails has available, in my model I have
def to_param
"#{self.id}-#{self.name}"
end
which will generate a URL for me of
/19-clawd
This works, but when I do the following it throws an error
def to_param
"#{self.name}-#{self.reference}"
end
My question though is how can I generate the URL to be name and reference without it throwing
Couldn't find Animal with 'id'=Clawd-A123456
If you would like to use your own "friendly id" then you'll need to adjust the find statement in your controller to something like
id = params[:id].split(/-/, 2).first
#animal = Animal.find(id)
Similarly, for the name/reference combination
name, reference = params[:id].split(/-/, 2)
#animal = Animal.find_by(name: name, reference: reference)
The second choice is a little more difficult because you'll have to do some work in the model to guarantee that the name/reference pair is unique.
The easiest way, is to go with friendly_id and simply add the missing database column. Keep in mind that you will need to ensure this new column is unique for every record. It basically acts as primary key.

Rails 3.2 - validate format of date

I have the model Teacher which has field :teacher_birthday. I get :teacher_birthday from the view (a single textbox). I want to make sure that an input date has a such format - dd.mm.yyyy (i mean i want to be sure, that an input date as 12.24.1991 will not be save in db because such date is wrong) and that this date exists. Also, i want to do this in the MODEL. Is this possible?
Try the chronic gem. It has very flexible date parsing, including what you're looking for:
[11] pry(main)> require 'chronic'
=> true
[12] pry(main)> Chronic.parse('24.12.1991'.gsub('.','-'))
=> 1991-12-24 12:00:00 -0700
Declare the validation method to be called in your model, and then define this method. The following should roughly do what you need:
validate :validate_teacher_birthday
private
def validate_teacher_birthday
errors.add("Teacher birthday", "is invalid.") unless (check_valid_date && valid_date_format)
end
def valid_date_format
self.teacher_birthday.match(/[0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9]/)
end
def check_valid_date
begin
parts = self.teacher_birthday.split(".") #contains array of the form [day,month,year]
Date.civil(parts[2].to_i,parts[1].to_i,parts[0].to_i)
rescue ArgumentError
#ArgumentError is thrown by the Date.civil method if the date is invalid
false
end
end

Datamapper DateTime to String behaviour

I write my first project wich using Datamapper as ORM, so please be patient. :)
I try to do get String from DateTime field:
Error.first.submitted_at.to_s
=> "2009-08-24T12:13:32+02:00"
Returned String is not good for me. In ActiveRecord I can do something like that:
Error.first.submitted_at.to_s(:only_date)
or any other date formatter. Is somethig similar available in DataMapper or I must to use strftime method?
That's a feature available using AcitveSupport. You can do require 'activesupport' to get it. That might be overkill, though. You could also use #stamp from Facets to do the same thing, but you have to set up the :only_date format:
require 'facets/date'
Date::FORMAT[:only_date] = '%d.%m.%y' # For Date objects
Time::FORMAT[:only_date] = '%d.%m.%y' # For DateTime objects
d = DateTime.now
d.stamp(:only_date) # => "24.08.09"
If you really want to use it with the to_s method, you can do that, too:
require 'facets/date'
Date::FORMAT[:only_date] = '%d.%m.%y' # For Date objects
Time::FORMAT[:only_date] = '%d.%m.%y' # For DateTime objects
class DateTime
alias :default_to_s :to_s
def to_s(format=nil)
if format.nil?
default_to_s
else
stamp format
end
end
end
d = DateTime.now
d.to_s(:only_date) # => "24.08.09"

Resources