Rails Date Formats

First published on Fencore Ltd.’s Posterous page on December 3rd, 2010

(Note that the comment about working in Britain is no longer true, as I now reside in the USA.)

I don’t know about you but I get confused when working with dates as the built-in formats don’t work for me.
Ruby has a Date library that implements both the Date and DateTime classes and Rails extends these in its ActiveSupport library. There is also a Time class and, of course, these things cannot exist in isolation from each other.
As I work in Britain, I need to be able to produce dates in British format. I add custom formats to the Rails DATE_FORMATS hash by creating a file in config/initializers with the following contents:

Date::DATE_FORMATS[:british] = "%d/%m/%Y"
Date::DATE_FORMATS[:british_long] = "%d %B, %Y"
Date::DATE_FORMATS[:british_long_ordinal] = lambda { |date|
date.strftime("#{ActiveSupport::Inflector.ordinalize(date.day)} %B, %Y") } # => "25th April, 2007"

According to the documentation (for Rails 3.0.3 look at the ActiveSupport RDocs and then for to_formatted_s(format = :default) in DateTime), the file should be called config/initializers/time_formats.rb but it turns out that is is more of a suggestion than a ‘must do’. I found this out when I called I called it date_formats.rb by mistake; in fact I tried calling it splat.rb and it still worked, so perhaps something a little more generic like date_time_formats.rb would be better.
With that in place, and noting that to_formatted_s is aliased to to_s, you can do things like:

> date = Date.today => Fri, 03 Dec 2010
> date.to_s # this is the default output
=> "2010-12-03"
> date.to_s(:long) # this is pre-defined
=> "December 3, 2010"
> date.to_s(:british)
=> "03/12/2010"
> date.to_s(:british_long)
=> "03 December, 2010"
> date.to_s(:british_long_ordinal)
=> "3rd December, 2010"

You can do a similar thing with times (although I find no need to) and of course, you can define your own formats to satisfy your own local needs.
What about converting from a string to a Date or DateTime object?
Well, the strptime method is part of the Ruby language, so the following works:

> Date.strptime("31/01/2010", "%d/%m/%Y")
=> Sun, 31 Jan 2010 DateTime.strptime("31/01/2010", "%d/%m/%Y")
=> Sun, 31 Jan 2010 00:00:00 +0000

Note that I am using Ruby 1.9.2, although I believe nothing has changed from 1.8.x

Advertisements

Ruby Snippet – next day of week given date

First published on Fencore Ltd.’s Posterous page on October 13th, 2010

I needed the ability to work out the date of the next weekday after a given date, e.g. what is the date of the Saturday after the 1st December? The following will do it:

#date_convert.rb
require 'date'
require 'active_support/core_ext'
Date::DATE_FORMATS.merge!({british: "%d/%m/%Y"})
class DateConvert
  # usage:
  # date_of_next( day_name, date) where day_name is a string or symbol representation of a full weekday name, e.g. :saturday
  # and date is either a valid Date object or a string representation of a date
  def date_of_next( day_name, date = Date.today.to_s(:british))
    # Note that config/initializers/date_formats.rb has been created with the following lines:
    # Date::DATE_FORMATS[:british] = "%d/%m/%Y" # => 25/4/2007
    # Date::DATE_FORMATS[:british_long] = "%d %B, %Y" # 25 April 2007
    # Date::DATE_FORMATS[:british_long_ordinal] = lambda { |date| date.strftime("#{ActiveSupport::Inflector.ordinalize(date.day)} %B, #
    # day_name must be a string value representing the full day name (or a token equivalent)
    # date must be a valid Date
    #
    # date_of_next( "saturday") is valid
    # date_of_next( "Saturday") is valid
    # date_of_next( :Saturday) is valid
    # date_of_next( "sat", Date.today) is invalid - invalid day_name
    # date_of_next( :saturday, "2010/11/31")) is invalid - ArgumentError: invalid date
    #
    date = date.to_s(:british) if date.kind_of?(Date)
    which_day = (day_name.downcase.to_s + "?").to_sym
    (1..7).each do |inc|
      begin
        date_object = Date.strptime(date, "%d/%m/%Y")
        return date_object + inc if (date_object + inc).send(which_day)
      rescue
        puts "Enter the day as a string or symbol representation of a full weekday name, e.g. :saturday"
        puts "Enter the date as a string value of the form dd/mm/yyyy"
        return
      end
    end
  end
end

require '/Users/martin/work/utils/date_convert.rb'
describe DateConvert, "#date_of_next" do
  before(:each) do
    @dc = DateConvert.new
  end
  it "returns a date object when given a valid day of the week as a string" do
    @dc.date_of_next("saturday").should be_an_instance_of(Date)
    @dc.date_of_next("Saturday").should be_an_instance_of(Date)
  end
  it "returns a date object when given a valid day of the week as a symbol" do
    @dc.date_of_next(:saturday).should be_an_instance_of(Date)
  end
  it "returns a date object when given a valid day of the week and a valid date as a string" do
    @dc.date_of_next("saturday", "9/11/2010").should be_an_instance_of(Date)
  end
  it "returns a date object when given a valid day of the week and a valid date as a Date object" do
    @dc.date_of_next("saturday", Date.today).should be_an_instance_of(Date)
  end
  it "raises an exception when given a valid day of the week and a invalid date as a string" do
    @dc.date_of_next("saturday", "2010/11/9").should raise_exception()
  end
  it "raises an exception when given a day of the week in invalid format" do
    @dc.date_of_next("sat", "9/11/2010").should raise_exception()
  end
  it "returns a date for next saturday that should be a Saturday" do
    @dc.date_of_next("saturday").should be_a_saturday
  end
  it "returns a date for next sunday that should be a Sunday" do
    @dc.date_of_next("sunday").should be_a_sunday
  end
  it "returns a date for next saturday after '9/11/2010' that should be '13/11/2010'" do
    @dc.date_of_next("saturday", '9/11/2010').to_s(:british).should == '13/11/2010'
  end
end

Hope it helps.

no such file to load — .bundle/environment (LoadError)

First published on Fencore Ltd.’s Posterous page on October 13th, 2010

As part of the confusion I caused for myself last week (see https://martinjhawkins.wordpress.com/2013/10/08/installing-ri-documentation-for-rails-3-0-0-file-not-found-lib-and-rvm), I managed to include a fight with Textmate.
I use Cucumber and I run the features from within Textmate; for me the information is presented far better than it is on the command line.
After I’d installed rvm and re-installed the gems, using Bundler, I proceeded to check that testing was working as it had been. So, I loaded everything into Textmate, opened a feature window and hit Command-r. Instead of the results window I got an error trace, in which was the following: ‘no such file to load -- .bundle/environment (LoadError)‘.
So – off to look at the .bundle folder – no sign of an environment.rb file. Look at the Bundler web site – nothing there. Google the error – yes, some other people have seen it but there don’t seem to be any magic fixes.
Off to the rvm site again; check that rvm is installed properly – yes; check that all the actions mentioned under Integration/Textmate have been completed yes. I’m beginning to get that horrible sinking feeling that I’ve broken something serious.
On a whim, I created an empty .bundle/environment.rb file and tried to run the feature again – and lo – it worked! I have no idea what this file actually does in the grand scheme of things but the unfortunate thing was that it got deleted every time I ran a feature test. I was not going to recreate it every time.
Time for a re-install.
Cucumber.tmbundle‘ lives in the ~/Library/ApplicationSupport/TextMate/Bundles/ folder, so I deleted it and re-installed it using the instructions on the ‘http://github.com/drnic/cucumber-tmbundle‘ page. Re-loaded Bundles in Textmate and now nothing worked. The only thing that showed up in the Cucumber bundle now was ‘Switch to new Canonical Fork’. Eh? That wasn’t there before and was certainly not what I wanted.
Cue an even deeper sinking feeling.
I took a careful look at what I’d done. I’d copied the instructions from http://github.com/drnic/cucumber-tmbundle without paying too much close attention and realised that was the error.
Drnic has taken over the development of the Cucumber.tmbundle from Ben Mabey, who created it but who no longer used it. Rather than let it whither and die he passed it across to Drnic. In cloning the site, a basic error was made – the important line in the instructions refer to the old site. In order to make the install work properly, you need to replace the line that says

git clone git://github.com/bmabey/cucumber-tmbundle.git Cucumber.tmbundle

with

git clone http://github.com/drnic/cucumber-tmbundle.git Cucumber.tmbundle

Once I’d realised that mistake, I re-installed and everything worked fine.

Installing ri documentation for rails-3.0.0… File not found: lib and rvm

First published on Fencore Ltd.’s Posterous page on October 13th, 2010

I’ll put the bottom line first: if you’ve tried installing Rails 3 and received an ‘Installing ri documentation for rails-3.0.0… File not found: lib’ error and ended up with no Rdocs, you need to install the rdoc gem first. If you do that, the problem goes way and the install will work perfectly.
I’d been working on a Rails application for some time and had been using it as a learning experience – trying all sorts of new ideas but the wheels fell off last week.
Rails 2.3.8 had been producing lots of deprecation warnings and seeing that 2.3.9 addressed some of those, I thought I’d upgrade. Easy enough – download the new gems (and incidentally clog up my gem repository even more) make a couple of trivial changes to the environment.rb file and try it out. No issues so far.
I needed to move the application to a Windows box and tried freezing the gems into the vendor directory and then copying it across, having installed MySQL and used the Windows Ruby Installer. No luck this time; it’s been a long while since I’ve run Rails on a Windows box but it seems an even less friendly environment than it used to. Apparently the Ruby installer is compiled using a different compiler nowadays and some gems haven’t changed along with it. I needed to install different versions of some gems.
Recognising the existence of rvm, which allows different versions of Ruby to run on the same computer (although you need to use ‘pik’ on a Windows computer), and also of the Bundler gem, which is integral to Rails 3 and allows for better management of gems, I decided to try these out.
Too many changes at once? Darn right. Hindsight is a wonderful thing…
If you follow the instructions carefully, rvm installs easily enough. You can install different versions of Ruby and install different gems for each Ruby version. (rvm calls these gemsets).
In fact, rvm goes further than this – it enables the creation of many gemsets under each Ruby version, allowing you to create gemsets for specific applications. When using a specific gemset, you also have access to a global gemset under that Ruby version. Neat!
Using a file called .rvmrc, you can set things up so that a default Ruby and gemset are chosen when you ‘cd’ to a particular directory.
rvm is an excellent utility and full marks must go to Wayne Seguin and his helpers for developing it. My only carp is about the web documentation, which I really do not like but this is open source right? Live with it or offer to help out!
I did have one huge issue, however. After I had got everything installed to my satisfaction (or so I thought), I tried installing Rails 3.
Now, according to the Rails 3 web site, http://rubyonrails.org/download, you need Ruby, Rubygems and then you can install Rails. If you do and you do not have the rdoc gem installed (which will happen if you use rvm), you will get the error described. Rails will install and work, but you won’t have the documentation locally available. So make sure you have the rdoc gem installed first. (rdoc is also part of Ruby’s standard lib and Rubygems is supposed to install it too – so I guess someone’s not testing enough!)
I have set things up so that the following are available in the global gemset under Ruby-1.8.7; bundler, rake, rdoc, rdoc-data, and syntax. Rake is provided by the rvm setup; the rvm documentation had also stated that rdocs would be installed by default but this wasn’t the case and the rvm web site has had been amended to reflect that.
In my opinion, the Rails site should state that the rdoc gem needs to be installed before Rails (or better yet, make it transparent by including it in the Rails install itself). I’ve tried raisng the issue but so far the response has been that rdoc is not a Rails dependency…

Adding a line break to a Rails confirm message

First published on Fencore Ltd.’s Posterous page on July 13th, 2010

In Rails 2.3.8, the following is produced by the scaffold generator:

<td><%= link_to 'Destroy', common_contents, :confirm => 'Are you sure?', :method => :delete %></td>

If you want to break the ‘confirm’ message over multiple lines, it is important to note that the generator has enclosed the message in single quotes. To make the line break, use \n and change the single quotes to double quotes.

<td><%= link_to 'Destroy', common_contents, :confirm => "Danger/nAre you sure?", :method => :delete %></td>

You’ll then get

2010.7.13.fig1

Instead of

2010.7.13.fig2