Extremely Simple Calendar Integration for Rails

Posted on August 8th, 2007 in rails, ruby, technology by mendicant

Today we’ll go over an extremely simple way to add a javascript/css calendar to your Rails app. We will be using the Calendar Date Select Plugin. It is a small, easy to use calendar based on the prototype library.

This was written back in the day for Rails 1.2, so take all this information with a grain of salt.

Installation is simple, and uses the typical installation syntax:

script/plugin install http://calendardateselect.googlecode.com/svn/tags/calendar_date_select

Voila! Installed!

Now, we just need to integrate it.

First, in your layout you need to add the javascript tag:

<%= calendar_date_select_includes "silver" %>

You can also use “red”, “blue” or “nil” for other color schemes.

Also note that you need to have prototype included as well, so if you haven’t already, you should also add the following to your layout:

<%= javascript_include_tag :defaults %>

And now, we’re ready to use it! Usage is simple. I was using it to keep track of an expiry date for a property, so I used to the following tag:

<%= calendar_date_select_tag "property[expiry_date]", @property.expiry_date.to_s  %>

If you wish, you can also check out the demo section for more information on using it with Form Builder.

Finally, I didn’t like the default ‘natural’ syntax for the date “August 8th, 2007″, so I changed it to use my preference, hyphenated syntax. To do this, open your environment.rb file and add the following line:

CalendarDateSelect.format = :hyphen_ampm

There! That is all I needed to do. Of course, there are more options, simply adding a :time => true will allow you to have a time field as well. There are a few more configuration options available for the calendar. You can find out more and get some more screenshots by visiting the project’s homepage.

Update:
Sorry, I haven’t responded to basically anyone that has commented here. I wish I had more time, but at this point I don’t. I am planning on getting back into this, but it might take a while. :(

Cascading Selects in Rails

Posted on July 18th, 2007 in rails, ruby by mendicant

While I know there are resources out there for creating Cascading (dependant?) select boxes using Ruby on Rails, my decision to write about this came more from the myriad of solutions for all different versions of rails. Some of them worked and some of them didn’t. This is what ended up being my solution to the problem.

As a background, this was for a signup page which would require a state/province and a country. I wanted a user to select their country first, which would then populate the select box for the state/province so that they could choose from only relevant entries.

The model is Property and the controller is properties_controller.
The relevant part of the form looks like this:

<%= select "property", "country_id", Country.find(:all).collect {|c| [ c.name, c.id ] }, { :include_blank => true} %>
<div id="provinces">
  <%= select "property", "province_id", @provinces.collect {|p| [ p.name, p.id ] }, { :include_blank => true } %></td>
</div>
<script type="text/javascript">
  //<![CDATA[
  new Form.Element.Observer('property_country_id', 0, function(element, value) { new Ajax.Request('/properties/select_country?country_id='+value, {asynchronous:true, evalScripts:true}); });
  //]]>
</script>

Now, there is some clarification needed here. I would guess that people would argue that rather than write your own javascript in this instance, it would make more sense to use the observe_field helper. I could not for the life of me get the observe_field helper to create working javascript. If anyone has any suggestions, I’d be happy to hear them.Anyhow, the basics of the javascript is this:
Observe the field ‘property_country_id’.
When it is changed, perform the listed function.

The function creates an Ajax Request to my properties controller to it’s select_country action, and also passes in the country_id selected in the parameters.

Now let’s look at how the action works in app/controllers/properties_controller.rb.

def select_country
  @country_id=params[:country_id]

  if (@country_id.nil?)
    @provinces=Array.new
  else
    @provinces = Province.find(:all, :conditions => 'country_id='+@country_id, :order=>'name')
  end
end

What this does is checks the country_id and if it doesn’t exist returns a new empty array, and if it does exist, finds all the provinces (I’m Canadian so I named my model provinces) related to that country.So now we have the the list of provinces, and all thats left for us to do is repopulate the Province Select box. To do that, we use an RJS template. So we create a .rjs file in app/views/properties/select_country.rjs. We then populate it with:

page.replace_html(’provinces’, (select “property”, “province_id”, @provinces.collect {|p| [ p.name, p.id ] }, { :include_blank => true }) )

This will replace the html in the id ‘provinces’ with a select box populated with the provinces we found in the action.

That’s all there is to it!