On the Differences of Months

July 28, 2011 § Leave a comment

Dealing with dates is hard.  Dealing date calculations is harder.  Luckily, in the Rails world we have ActiveSupport to help us with a lot of this.  It actually does so much, that I usually forget how much of a pain dealing with dates is suppose to be.  However, there are times now and then that I am reminded.  Little edge cases that haven’t yet been built into ActiveSupport.  One such edge case is determining the number of months between two dates. Why do months have to have different numbers of days?

This particular use case can be very useful when dealing with recurring payments.  Calculating the number of payment cycles a subscriber has gone through can tell you how much revenue they have generated.  I have put together two class methods for the Time object that will calculate just this.  One is a simple loop that takes time proportional to the time between the start and end times, and the other a more efficient direct calculation of the same number.

The simple loop looks like:

def months_between2(start_date, end_date)
  return -months_between2(end_date, start_date) if end_date < start_date

  count = 1

  while true
    return count - 1 if (start_date + count.months) > end_date
    count += 1
  end
end

It just starts at the start_date and keeps adding months until it passes the end_date. Not particularly difficult, but should get the job done for most cases.  All the complexity of the more efficient version comes from checks dealing with the various cases arising from different months having a different number of days. Anyways, the source code for that one looks much nicer over on GitHub.

On the Size of a String

July 21, 2011 § Leave a comment

In computer programs, number constants can be interesting and bewildering things.  Trying to figure out why one was chosen over another can be really confusing.  For a good while I was confused as to why ActiveRecord would set a string attribute to be a VARCHAR(255) in the database.  It limits the size of the string attributes to 255 characters long.  256 is a bit more natural when choosing constants in computer science.  255 is commonly used to denoted the last index in a 0-based array of 256 elements.  So why 255?  The short answer is “because of InnoDB and UTF-8 character sets.”

InnoDB has a limitation on the size of a key for a single column index of 767 bytes.  When the table is encoded with a UTF-8 character set, each characters has the possibility of using 3-bytes to represent its intended character.  That means in order to be able to fully index a UTF-8 encoded varchar column, the string must be able to be represented in 767 bytes.  767 / 3 = 255 2/3.  This means that the largest UTF-8 encoded varchar column can be 255 characters long, hence the ActiveRecord default string attribute size.

Problems on the Way

As bigger and bigger pushes are made for complete internationalization, we’ll see more things encoded with UTF-16 and UTF-32.  Characters using these encodings might require up to 4 bytes to represent their value.  When this happens, ActiveRecord will need to reduce the size of indexable string attributes to 191 characters.

For Fun

Here is a truly awesome magic number that seems to come out of no where, 0x5f3759d5.

On Translations

July 19, 2011 § Leave a comment

Languages have never really been a strong point of mine.  I took Spanish through high school and probably retain enough to order some beers and find the bath room in an emergency.  It comes down to the fact that I am not a huge fan of memorization.  Luckily there are amazing some tools out there to help.

Google Translate

The first one is probably one of the most used translation engines out there, Google Translate.  Sadly as many have probably already read a while ago, Google isn’t going to be offering it as a free service anymore citing extensive abuse. Luckily for those with real needs, there will be a paid version.  [link]

Since I spend a lot of my day on a command line I figured that it would be nice to have a little translate tool at my disposal.  One where I didn’t have to keep opening up a web page.  So I wrote a little bash function call the Google Translate’s API from the command line and print the results right there.

translate() {
  wget -qO- "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=$1&langpair=${3:-}|${2:-en}" | sed -E -n 's/[[:alnum:]": {}]+"translatedText":"([^"]+)".*/\1/p';
echo ''
  return 0;
}

You just drop this little guy in your .bashrc file and… Boom! Translations on the command line.

USAGE

translate  [] [<source language="" />]

The destination language is assumed to be English unless otherwise specified, and the source language is auto-detected if not specified.

$ translate hola
hello
$ translate hello es
hola
$ translate hello fr
bonjour
$ translate hola de es
Hallo
$ translate hola de
Hallo

I’m keeping my fingers crossed that Google keeps some sort of free version of the service available.  Check out the source in a more readable format over on github.

Word Lens

One of the other tools that had my jaw on the floor the first time I saw it was the iPhone app Word Lens.  Go over to the site and watch the demo video.  I’ll wait.  I love this thing.  It is an Augmented Reality (AR) app that uses the camera to read text and automatically replace it in image… in realtime.  Absolutely ridiculous.  It was very interesting to read a lot of the comments about the app when it first came out.  People we complaining about the language packs be $5 then the price getting upped to $10.  They were whining that it was too slow.  The couldn’t believe that it only did word by word translation and didn’t work on phrases.

Seriously?  Your telling me that being able point the camera in your phone at any sign in a foreign country (well, any Spanish speaking foreign country at the anyways) and immediately have it become understandable isn’t worth $10?  That you’d rather spend more on a phrase book and have to thumb through it by hand?  It is a proof of concept and a very good one at that.  Even in it’s current form it has the ability to change travel forever.  At the moment any English speaker has the ability to at least get the main point of any printed sign in Spanish, instantaneously.

Game changer.  It’s like your iPhone becomes a universal translator from Star Trek, or your mind is tweaked by the TARDIS and suddenly everything is comprehendible.

The Future is Now.

On When Create Is Not Like Create

July 14, 2011 § Leave a comment

I recently ran into an interesting issue in ActiveRecord while trying to set default values on an object using the after_initialize callback.  One would think the following blocks of code would be equivalent:

# new, save
Product.new(:name => "Awesome Product").save

# new w/ block, save
product = Product.new do |p|
  p.title = "Awesome Product"
end
product.save

# create
Product.create(:title => "Awesome Product")

# create w/ block
Product.create do |p|
  p.title = "Awesome Product"
end

In 99.9% of cases this is going to be true.  The last one, create with a block, however, can potentially cause you some problems if you are using after_initialize. The problem arises when you use after_initialize to set default values for attributes are are dependent on other attributes. Let us consider our Awesome Product has two more attributes, msrp and wholesale_price, that are tied to each other. If we have one of them we can always determine what the other should be. In this case, there wouldn’t really be a reason set both of them when creating a new object. Just set one and let the other one get set automatically.

For our example we’ll say, msrp = 2 * wholesale_price. You might use an after_initialize that looks something like this:

def after_initialize
  # set wholesale_price based on msrp
  if !msrp.nil? && wholesale_price.nil?
    self.wholesale_price = msrp / 2
  # set msrp based on wholesale_price
  elsif msrp.nil? && !wholesale_price.nil?
    self.msrp = wholesale_price * 2
  end
end

We can instantiate an object like this:

product = Product.new(:name => "Awesome Product", :msrp => 20)
 => <Product ...>
product.save
 => true
product.msrp
 => 20
product.wholesale
 => 10

Everything is working as it should. Now let’s use create instead of new and save.

product = Product.create(:name => "Awesome Product", :msrp => 20)
 => true
product.msrp
 => 20
product.wholesale
 => 10

Still works just fine. Now create with a block:

product = Product.create do |p|
  p.name = "Awesome Product"
  p.msrp => 20
end
 => true
product.msrp
 => 20
product.wholesale
 => nil

Uh, oh… Why didn’t wholesale_price didn’t get set? Take a look at the implementation of create in ActiveRecord::Base.

def create(attributes = nil, &block)
  if attributes.is_a?(Array)
    attributes.collect { |attr| create(attr, &block) }
  else
    object = new(attributes)
    yield(object) if block_given?
    object.save
    object
  end
end

Notice in the else block that a new object is created and then the block is yielded. This means that the after_initialize callback is run on the instantiated object BEFORE the block code is run. msrp is not set yet when after_initialize is run, so wholesale_price can’t be set. create without a block work fine because it is literally the same as using new and save.

TL;DR – after_initialize runs before the block code when using create and a block. Be careful when using after_initialize to set default values for attributes that depend on other attributes.

On Cross Subdomain Cookies

July 12, 2011 § 1 Comment

The first Ruby gem I ever wrote was tld-cookies.  While it is very poorly named, probably should have been called root-domain-cookies or something like that, it adds a nice little bit of functionality to the Rails 3 cookie jars.

One of the things about Rails 3 that I thought was really cool, was the way cookies were accessed. It’s not a big and fancy piece of code, but to me it is just a slick way to do things. The chaining of the different cookie jars makes it trivial to create the cookies you want and need.

cookies.permanent.signed[:awesome_cookie] = "cookies awesomeness"
cookies.signed[:awesome_cookie]
 => "cookies awesomeness"

At the time I was working on a project at work that required the use of a lot of dynamic subdomains, and we wanted to be able to write cookies across all of the subdomains as well as for individual subdomains. In Rails 3 you could set the domain when you write to the cookie like:

cookies.signed[:awesome_cookie]     = { :value => "cookies awesomeness",           :domain => "example.com" }
cookies.signed[:awesome_cookie_sub] = { :value => "cookies awesomeness subdomain", :domain => "sub.example.com" }

Now that is a lot of extra work and looks pretty ugly. You could set the default domain for you cookies like this:

Rails.application.config.session_store :cookie_store, :key => '_app_name_session', :domain => :all

But I guess I’d rather explicitly say when a cookie is to be used across all subdomains. To this point I tld-cookies add a tld cookie jar to your Rails 3 app which sets the domain for the cookie to be the root domain, i.e. example.com.

cookies.tld.signed[:tld_cookie] = "ACROSS ALL SUBDOMAINS!!!"
cookies.signed[:tld_cookie]
 => "ACROSS ALL SUBDOMAINS!!!"

As you can see above, you use it similarly to how you would use the permanent cookie jar. The slight difference is when you want to delete the cookie you have to use the tld accessor.

So yeah, first Ruby gem. Poorly named, fun little learning project.

On Selecting A Single Column

July 9, 2011 § 1 Comment

Many times when we are selecting a rows out of the database we just want a single column and have no need for the entire object. There are a number of ways to accomplish this with ActiveRecord. One can get all the records from the database and then collect the attribute needed:

Posts.where(:status => 'published').collect(&:id)
=> [ 1, 5, 8, 10 ]

This has the benefit of being able to us any overwritten accessors, but has a lot of overhead associated with generating the objects. Another way to do it is to go directly to the database:

ActiveRecord::Base.connection.select_values("SELECT id FROM posts WHERE status = 'published'")
 => [ 1, 5, 8, 10 ]

This is much faster, but requires one to use the direct connection to the database and have the SQL literal prepared. Not particularly user friendly even if you can get the SQL literal using the to_sql:

ActiveRecord::Base.connection.select_values(Posts.where(:status => 'published').select(:id).to_sql)
 => [ 1, 5, 8, 10 ]

Wouldn’t it be nicer if you could just do the following:

Post.where(:status => 'published').select_column(:id)
 => [ 1, 5, 8, 10 ]

The select-column gem provides the above functionality above.  You can you it in your Rails 3 app or checkout the source code over on github.

Usage

select_column accepts a single optional argument. This is the column that you want to have returned in an array. The returned column can also be specified using the select query method.

If neither a select nor an argument is given, :id is assumed to be the column to be returned. If multiple select query methods are present, the first one defined will be the column returned.

Some examples:

# selects an array of ids
Post.select_column

# selects an array of titles
Post.select_column(:title)

# selects an array of ids
Post.where(:status => 'published').select_column

# selects an array of titles
Post.where(:status => 'published').select_column(:title)

# selects an array of titles
Post.select(:title).where(:status => 'published').select_column

Update (Jan 21, 2012): It’s like they keep looking at my gems and integrating them into Rails. As of Rails 3.2 this gem’s functionality has been replicated by ActiveRecord::Relation#pluck. Check it out in the release notes.

Where Am I?

You are currently viewing the archives for July, 2011 at The On Blog.