Rails

Dynamic date exclusions w/ JQuery Datepicker, Rails & Gon

A question came up the other day when I was showing a colleague the reservation page for the restaurant app I’ve recently written (http://alianosbatavia.com): If the restaurant is closed, can you dynamically exclude dates from the JQuery date picker? The answer was yes – but I hadn’t found a nice way to do it. The way it previously was configured looked something like this (coffee script):

  $("#reservation_date").datepicker(
    minDate: "-0d",
    maxDate: "+1Y",
    showOtherMonths: true,
    selectOtherMonths: true,
    beforeShowDay: (date)->
      closedDates = [[12,25],[1,1],[8,22]]
      for closedDate in closedDates
        if(closedDate[1] == date.getDate() && (closedDate[0]-1) == (date.getMonth()))
          return [false]
      return [true]
  )

Fast forward to yesterday – I was watching Railscast episode #324 during my morning commute. It’s about passing data to javascript from Rails apps. There are a few ways to do that using HTML data tags, etc, (I’ll let you watch the episode) but the last suggestion involved using a gem called Gon. Gon essentially creates store of values at the window level in javascript and pumps it full of data from variables in your controllers in your Rails app (again, more details in the episode).

Using Gon to exclude dates from the JQuery date picker? Super easy.

You need to include gon in the head tag of the page on which it will be used. I added mine to my applications layout:

In application.html.erb:

<head>
  <title><%=h yield(:title) %></title>
  <%= include_gon %>
  <%= stylesheet_link_tag "application" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>

That will add the gon storage to every page. Next, add some data to the gon storage:

In my controller methods (or in a filter):

gon.exceptions = closed_dates

And now, from my JQuery date picker config:

In my assets/reservation.js.coffee:

  $("#reservation_date").datepicker(
    minDate: "-0d",
    maxDate: "+1Y",
    showOtherMonths: true,
    selectOtherMonths: true,
    beforeShowDay: (date)->
      closedDates = gon.exceptions
      for closedDate in closedDates
        if(closedDate[1] == date.getDate() && (closedDate[0]-1) == (date.getMonth()))
          return [false]
      return [true]
  )

That’s it! Be sure to check out the Railscast and the Gon github page for more details.

Advertisements

Simple caching in Rails 3.1

Parting ways with http://alianosbatavia.com has been a lot harder than I thought. Every time I think I’m going to hang it up, I think of something new to add to it.  Recently, I wanted to use simple caching to load blocks of reservations at start up, then refresh those blocks after each successful update of blocks from the admin UI.  Here we’ll talk about reading to and writing from the cache in Rails 3.1.

Writing to the cache

In config/initializers/load_reservations.rb:

require File.dirname(__FILE__) + '/../../lib/reservations_loader.rb'
Rails.cache.write(:reservation_blocks, ReservationsLoader.build_reservations_map)

Reading from the cache
In app/models/reservation.rb:

blocks = Rails.cache.read(:reservation_blocks)

Pretty easy.  I have an observer on ReservationBlocks that refreshes the cache the same way it initially loads it on startup.  This gives me a fast and easy way to display only reservations that are available for the currently selected date on the reservations screen without having to query the database every time a reservation time is requested.

I resolve, version 2.0

2011 is gone and with new year comes new resolutions. Some of last year’s resolutions got resolved, others fell to the wayside, and now I’ve come to write down a few more.

I never got back into grails – although I still feel like I want to. That one stays on the list!

Revisited some old text books, but I still have more to revisit. I forgot a lot about design patterns. Some of that is interview fodder, but still among the things I like to know.

The tracker app never went out, but an equally cool side project did – http://alianosbatavia.com – an implementation of a turn-key restaurant web app. Fairly successful so far, gave me a reason to write a production rails app, learn more about SEO, etc. Still not sure what my next idea is, but I want to get another app out this year…

Is Java still relevant? I go back and forth on this. I am thinking of either learning Play! or Scala/Akka. Not sure I care about either one. I think this is at the bottom of the list.

Lastly, I need to write the posts I talked about writing last year, including my favorite anonymous inner class mock madness.

Hopefully, I’ll be back soon.

Size doesn’t matter (or work, apparently)

Here’s a quick one.

Recently when doing some Rails work, I was using FormHelper to add a text area to an erb and couldn’t seem to get the size param to work. The Rails API docs clearly mention the use of the ‘:size’ param or the ‘:rows’ and ‘:columns’ params being acceptable.

For what it’s worth, neither seem to render in Firefox 3/4 or Safari. If you’re having the same problem, add a style to your text area to control the size, and you should be in business…

     <%=form_builder.text_area(:attribute, {:class=>"aSizedTextArea"})%>

In your css file:

.aSizedTextArea {
    overflow-y: scroll;
    height: 100px;
}

Getting my spec on

Although I still consider myself a rookie in the RoR world, I recently made my way through the Rspec book, and came out of the experience with some new skills to sharpen. On an internal project at Redpoint, we’re again using CanCan for authorization and Authlogic for authentication. My first task after getting involved a second time around (I was involved before I learned Rspec/Cucumber/BDD, stopped, read the book, and now am back) was to back fill some test coverage.

Immediately, I ran into issues figuring out how much to test, when to test what, factories vs mocks, etc – all much discussed topics with typical purist and cool kid groups. After poring over a zillion resources via the normal sources (mostly google and stackoverflow), I decided the best way to sharpen those newly forged rspec skills was to dive in the purist way.

First, I made a quick decision to treat features tested via Cucumber as integration tests, and used models created with FactoryGirl to test them. Easy enough, I thought – the rest would be just as easy…

Well, not exactly.

After piecing together a solution from the blog and forum post’s of others (see links above). Here’s what I ended up with:

Authlogic – essentially, the strategy here is to override the methods normally put in ApplicationController.rb to create stub/mocks of UserSession and User models.

in spec_helper.rb:

require 'authlogic/test_case'

def current_user(stubs = {})
  @current_user = stub_model(User, {:login=&gt;"a user name"}.merge(stubs))
end

def user_session(stubs = {}, user_stubs = {})
  @user_session ||= mock(UserSession, {:user =&gt; current_user(user_stubs), :record =&gt; true}.merge(stubs))
end

def login(session_stubs = {}, user_stubs = {})
  UserSession.stub!(:find).and_return(user_session(session_stubs, user_stubs))
end

def logout
  @user_session = nil
end

…resulting in tests that can call ‘login’ and ‘logout’ to simulate authenticated and unauthenticated users:

before { 
     login 
}

For CanCan, the solution came much quicker, and I think it was in a response to someone’s forum posting from Ryan Bates himself. In this case, we create an instance of ability, which is essential what is happening in the background during normal operation, and stack it with whatever :can’s we’d like. This new object just extends CanCan’s ability class, and we can alter it however we please. Now, my test contains something along these lines:

before { 
    login

    @ability = Object.new
    @ability.extend(CanCan::Ability)
    controller.stub(:current_ability).and_return(@ability) 
}

…and throughout my tests, when I want to set abilities, I add something like this where necessary:

     @ability.can :manage, :all

I hope this saves someone using the same Gems some time to see in one place. That is the only aspect of this post I can take credit for.

Like learning English from an auctioneer…

As we all know, skill retention has a lot to do with level of immersion and length of stay – the deeper you are into a particular technology and the length of time that you’re at that depth usually are directly related to how long you can remember a given technology, language, or practice.

My experience with Ruby and Rails reflects this. I’ve been in and out of two projects in my free time while working on other projects during the day. My approach to picking up Rails was similar to how I picked up Groovy and Grails – get a book and read it . In my case it was the classic Advanced Web Development With Rails. Coming from a java background, the learning curve for Groovy was easy. I only had to learn Grails. For Ruby and Rails, diving right into Rails was ok, but I glossed over a lot of the Ruby syntax and shortcuts, assuming I would pick them up later. With Ruby having a steeper learning curve for me, and not being deeply immersed in these projects for long periods of time, my personal velocity suffered. It was like learning English from an auctioneer – too often going back to find syntax examples of things I knew I wanted to do, but couldn’t remember exactly how…

A few weeks back a co-worker sent a link to our team about Ruby Koans (http://rubykoans.com/). While I’m not a huge fan of the ‘path to enlightenment’/’Zen b.s., they serve as a fast and hands-on way to learn the language (and it’s shortcuts), and serve as a quick reference point for use later. In short, I’m a big fan, and if you’re interested in learning Ruby and making it stick, I recommend working through them. The easiest way to get started is at github: (https://github.com/edgecase/ruby_koans).

ruby_koans = awesome (or is it ruby_koans == awesome?) Check the koans!

Makes life easier. Is good.

Some resources to get started using some handy tools for ruby/rails development

RVM is awesome. Manage the version of ruby you’re using and the gems for each version and/or project with ease. Super handy. All the pain of changing ruby versions on the mac is eliminated.

Get your BDD on with Rspec, and then automate with Autotest. No more autospec layer for Rspec 2 – Autotest is directly integrated these days. Let your machine run the tests for you as you write/update code. The growl plugin for development on the mac is slick as well. This is what development should be like.