Association Cardinality in Rails

From time to time I’ve noticed people who struggle with cardinality and associations in Ruby on Rails. So, I thought I would attempt to create a cheat sheet here to help developers understand relationship cardinality and how it maps to associations.

ActiveRecord can be used to describe relations with one-to-one, one-to-many and many-to-many cardinality; where each model defines its relation to another. Let’s cover each of the three types of associations.

One-to-one

Use `has_one` in the base and `belongs_to` in the association:

class Family < ActiveRecord::Base
  has_one :home
end
class Home < ActiveRecord::Base
  belongs_to :family
end

A common question about a one-to-one association is ‘how to know which direction the has_one and belongs_to go?’  The correct way to know, is that whichever model has the foreign key, gets the `belongs_to`.  In this case, Home has the foreign key `family_id`.

One-to-one relationships are a bit odd, and as a general rule, if you find yourself using a lot of them, there is probably a better solution.

One-to-many

Use `has_many` in the base and `belongs_to` in the association:

class Family < ActiveRecord::Base
  has_many :parents
end
class Parent < ActiveRecord::Base
  belongs_to :family
end

This will be your most common relationship. As with one-to-one’s, the table with the foreign key gets the `belongs_to` (although this is a lot more obvious with a one-to-many). In this case the foreign key is `family_id`.

Many-to-many

These can be a lot more complicated and there is actually a couple of different ways to do it.

The first way involves a specific joining model. This results in 2 stages of has_many associations. It is referred to as `has_many :through` and is primarily used if you need to fully control the joining model/table:

class Family < ActiveRecord::Base
  belongs_to :parent
  belongs_to :kid
end
class Parent < ActiveRecord::Base
  has_many :kids, through: :families
end
class Kid < ActiveRecord::Base
  has_many :parents, through: :families
end

The second (and my preferred way) is to use the `has_and_belongs_to_many` method:

class Parent < ActiveRecord::Base
  has_and_belongs_to_many :kids 
end
class Kid < ActiveRecord::Base
  has_and_belongs_to_many :parents
end

The main difference (or disadvantage) with the `has_and_belongs_to_many`method is that the intermediary joining table and foreign keys need to be exactly named to match what Rails expects. Which many-to-many method you use ultimately depends on whether you need to work with the relationship model as its own entity directly.

MySQL utf8mb4 Encoding Breaks ActiveRecord’s Schema Setup

I recently wrote about the virtues of true UTF8 (utf8mb4) character sets in MySQL and how to change your database to use it. Today we will discuss a possible problem you may encounter when you do when programming on Ruby on Rails. The error looks something like this:

$ rake db:setup

Mysql::Error: Specified key was too long; max key length is 767 bytes:
CREATE UNIQUE INDEX unique_schema_migrations ON schema_migrations (version)

The problem exists because the utf8mb4 character set uses the full 4 bytes per character rather than the 1-3 of UTF8 (the character set most people mistakenly use thinking they’ll have full Unicode compliance). Because of this extra size, the schema_migration may no longer fit.

This small patch will set default mysql string column length to 191 instead of 255 which is the new index limit on utf8mb4 (aka real utf8).

# config/initializers/mysqlpls.rb
require 'active_record/connection_adapters/abstract_mysql_adapter'

module ActiveRecord
  module ConnectionAdapters
    class AbstractMysqlAdapter
      NATIVE_DATABASE_TYPES[:string] = { :name => "varchar", :limit => 191 }
    end
  end
end

 

Using Ruby’s Metaprogramming to Initialize an Object From a Hash

Consider the code:

class A
  attr_accessor :b, :c, :d, :e, :h, :i, :x
end

Now imagine that you want to initialize each instance variable to the one that has the same name in the hash.. Imagine all the repetitive and crappy code that would generate.

But this is Ruby and with Ruby there is *nearly* always a better way.  Instead, meta-program it, and mix-it-in.

module constructed_from_hash
 def initialize(h)
  h.each { |k, v| send("#{k}=", v) }
 end
end

class A
 include constructed_from_hash
 attr_accessor :b, :c, :d, :e, :h, :i, :x
end

Nice, elegant and clean. Just the way Ruby code is supposed to be. AND this code will now scale, as more accessors are added to the object over time, the constructor too, wont need reprogramming. If you don’t need to do this often, you can pull just the constructor out of the module and put it directly into the class, but this way provides the most flexibility.

Header image taken from Examining Dwemthy’s Array composite pattern. An interesting read in it’s own right. check it out.

‘belongs_to’ and ‘has_one’ Differentiated

One of the more common confusions with ActiveRecord associations is the difference between the `has_one` and `belongs_to` relationships.

However, they are not interchangeable, and there are some serious differences. A `belongs_to` can only go in the class that holds the foreign key whereas `has_one` means that there is a foreign key in another table that references this class. So `has_one` can only go in a class that is referenced by a column in another table.

So this is wrong:

class Transaction < ActiveRecord::Base
  # The transactions table has a order_id  
  has_one :order                
end

class Order < ActiveRecord::Base
  # The orders table has a transaction_id
  has_one :transaction          
end

So is this:

class Transaction < ActiveRecord::Base
  # The transactions table has a order_id
  belongs_to :order             
end

class Order < ActiveRecord::Base
  # The orders table has a transaction_id
  belongs_to :transaction     
end

For a two-way association, you need one of each, and they have to go in the right class. Even for a one-way association, it matters which one you use, and which direction you use it:

class Transaction < ActiveRecord::Base
  # This table has no foreign keys
  has_one :order             
end

class Order < ActiveRecord::Base
  # The orders table has a transaction_id
  belongs_to :transaction     
end

Ruby Script to Import Google Contact Photos From Gravatar

Google Contact photos are a much neglected feature of the Google Stack. It really adds to the user experience when you see each of your contact photos when you make or receive a call. However, it can be a real pain (especially if you have hundreds of contacts).

But I had an idea recently, to try and match my Google Contact emails with Gravatar and try to auto-populate some of the dozens of contacts that didn’t already have a photo (after all a Gravatar is better than nothing).

So I wrote a Ruby script to find my contacts missing a photo and try to update it with a Gravatar (wherever possible). NB: You may need to first install the GData (Google Data) gem by opening a Terminal window and issuing: sudo gem install gdata.

#!/usr/bin/env ruby

# Google Contact Photos - Gravatar Importer
# Written by Ashley Angell
# http://ashleyangell.com
# Licenced under Creative Commons with Attribution

require "rubygems"
require "gdata"
require "rexml/document"
require "digest/md5"
require "net/http"
include REXML

none = 'd5fe5cbcc31cff5f8ac010db72eb000c'
user = ARGV[0]
pass = ARGV[1]

client = GData::Client::Contacts.new
client.clientlogin(user, pass)
data = client.get("https://www.google.com/m8/feeds/contacts/#{user}/full?max-results=10000")
myxml = Document.new data.body
p "contacts"
puts "-"*70
i = 0
myxml.each_element("feed/entry") do |e|
  begin
    gd = e.elements['gd:email']
    if !gd.nil?
      email = gd.attributes['address'].downcase
      hash = Digest::MD5.hexdigest(email)
      image_src = "http://www.gravatar.com/avatar/#{hash}"
      nil_image = false
      image_element = e.get_elements("link[@rel='http://schemas.google.com/contacts/2008/rel#photo']")[0]
      if !image_element.nil? and image_element.attributes['gd:etag'].nil?
        data = nil
        md5 = nil
        Net::HTTP.start(URI.parse(image_src).host) do |http|
          resp = http.get(URI.parse(image_src).path)
          data = resp.body
          md5 = Digest::MD5.hexdigest(data)
          File.open("#{email}.png", 'w') do |f|
            f.puts data if md5 != none
          end
        end
        md5 = Digest::MD5.hexdigest(data)
        if md5 != none
          puts "#{email} > #{image_src}"
          client.put_file(image_element.attributes['href'], "#{email}.png", 'image/png')
          i = i + 1
        else
          puts "#{email} > no match"
        end
      else
        puts "#{email} > skipped (already has photo)"
      end
      File.delete("#{email}.png") if File.exists?("#{email}.png")
    end
  rescue Exception => ex
    puts ex
  end
end
puts "Updated #{i} contact photos"

To execute it, simply copy and paste this into a text editor (or download it and unzip) and from Terminal (command) window and execute the following commands:

sudo chmod +x googlegravatarimporter.rb [Enter]
./googlegravatarer.rb your.address@gmail.com your_password [Enter]

It will cycle through your Google Contacts and indicate what action was taken. For me, surprisingly updated a few dozen contacts (even more than I expected).

I’ve posted this here for others that might want to do the same thing but cannot be bothered writing the script for it. Consider it posted here under Creative Commons with Attribution.

‘File not found: lib’ Error installing Rails Gem

I recently had a problem trying to install Rails 3 on my MacBook with a fresh OSX Snow Leopard:

sudo gem install rails
Password: {entered}
Successfully installed rails-3.0.7
1 gem installed
Installing ri documentation for rails-3.0.7...
File not found: lib

Turns out this is a somewhat common problem.  But it seems that the solution is easy, just manually reinstall RDoc. To do this run these 3 commands:

sudo gem install rdoc-data
sudo rdoc-data --install
sudo gem rdoc --all --overwrite

The last line in particular will re-generate all the documentation for your installed gems (including Rails) and can take a while, but you should be able to confirm the fix by reissuing the Rails gem install command:

sudo gem install rails

shows that rails now installs properly and says that it has installed both ri and RDoc documentation without issue.

Using Rails’ Flash Messages with AJAX Requests

Have you ever wondered how to get access to the Ruby on Rails‘ flash message when performing a AJAX or restful web request?  You might hit yourself on the head when you discover how easy it is.  Simply append the flash message to the Response headers.  You could even wrap this in a helper, and using an after_filter to automatically add the header for you on every AJAX response.

class ApplicationController < ActionController::Base
after_filter :flash_headers

def flash_headers
  # This will discontinue execution if Rails detects that the request is not
  # from an AJAX request, i.e. the header wont be added for normal requests
  return unless request.xhr?

  # Add the appropriate flash messages to the header, add or remove as
  # needed, but I think you'll get the point
  response.headers['x-flash'] = flash[:error]  unless flash[:error].blank?
  response.headers['x-flash'] = flash[:notice]  unless flash[:notice].blank?
  response.headers['x-flash'] = flash[:warning]  unless flash[:warning].blank?

  # Stops the flash appearing when you next refresh the page
  flash.discard
end

And then you just read the header with whatever you happen to be reading it with. For completeness sake here is an example of how to read the header in JavaScript using Prototype:

 new Ajax.Request('/your/url', {
  onSuccess: function(response) {
    var flash = response.getHeader('x-flash);
    if (flash) alert(flash);
 }
});

Forget the UML Module for NetBeans!

A while ago, I wrote a blog post on how, with considerable effort, you can get a native UML NetBeans module up and running despite the NetBeans UML module being removed from the standard distribution.

I managed to get mine working, but there is a huge cost – Once you close the project (or the IDE) housing the diagram, you can never reopen it.  Out of pure determination desperation and perseverance I managed to get the diagram I needed, printed and done; but I can never open it and make adjustments.

Apparently, we’re all supposed to use SDE for NetBeans by Visual Paradigm now as the “official” replacement, but I tried it, and it was simply fail.  Proprietary and fail.

Fortunately, after taking a punt, I found a UML modelling tool which is not only more functional and better than the NetBean’s module was, but looks better too.  It even has the ability to create code from class diagrams (which you can obviously just cut and paste into your NetBeans IDE project of choice.  Its called ArgoUML.

ArgoUML is the leading open source UML modeling tool and includes support for all standard UML 1.4 diagrams. It runs on any Java platform and is available in ten languages.

I’ve used it a bit now, and I just love it.  I particularly like the way it can make recommendations on how to improve your diagram using its “critics” system.

It’s features boast:

  • All 9 UML 1.4 Diagrams supported
  • Platform Independent: Java 5+
  • Click and Go! with Java Web Start
  • Standard UML 1.4 Metamodel
  • UML Profile support with profiles provided
  • XMI Support
  • Export Diagrams as GIF, PNG, PS, EPS, PGML and SVG
  • Available in ten languages – EN, EN-GB, DE, ES, IT, RU, FR, NB, PT, ZH
  • Advanced diagram editing and Zoom
  • OCL Support
  • Forward Engineering
  • Reverse Engineering / Jar/class file Import
  • Cognitive Support
    • Reflection-in-action
      • Design Critics
      • Corrective Automations (partially implemented)
      • “To Do” List
      • User model (partially implemented)
    • Opportunistic Design
      • “To Do” List
      • Checklists
    • Comprehension and Problem Solving
      • Explorer Perspectives
      • Multiple, Overlapping Views

I haven’t yet worked out how to create object instances from my class diagrams yet, so I’m not sure if it just doesn’t support this or it’s user error, but in every other conceivable way, it seems to be an excellent UML modelling application for virtually every OS you can name.

Getting SSI to work in MAMP

It’s no secret that I adore my Mac, mostly because it just makes my life easier.  I enjoy the security of OSX, I love it’s responsiveness and I love that my operating system doesn’t punish me for installing applications and development stacks just to ‘play with them’.  A while ago, while looking for a stack that would let me quickly and effortlessly get Apache, MySQL and PHP5 working together without having to muss about with configs and the such, I discovered MAMP and frankly, I adored it instantly.  After a rather large download, it was effortless to install and running it was a cinch.  And better still, the server applications only run when you open the MAMP application and tell them to run, so that you dont loose vital system resources running services you dont need.

Additionally, my IDE of choice, NetBeans can integrate directly with MAMP, so that when you create (for sake of argument) a new PHP project and run it, it automatically puts the project files into the MAMP Apache directory (to be honest you do need to configure the path when you create the project, but its no big deal) making development painless and convenient.

But I did hit a snag recently when for a university assignment I was required to do a XHTML website using HTML Server Side Includes.  I was shocked when I ran my website and my SSI didnt work.

But there is a solution.

To make .shtml work, I deleted the comment-symbols ( # ) in the file http.conf (find it in /Applications/MAMP/conf/apache/ and at the time of writing was near lines 982:

# To parse .shtml files for server-side includes (SSI):
# (You will also need to add "Includes" to the "Options" directive.)
#
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml

Download Microsoft .NET Framework 3.5 SP1 Standalone Full Redistributable Setup Installer

Many applications uses Microsoft .NET Framework 3.5 as development platform, and thus requires .NET Framework to be installed beforehand, else the installation will request to download and install .NET Framework from Internet. On offline system without Internet access or online server with slow downloading speed, the requirement to download setup files through web may hit the wall – a no go.

kamagra shipping

Microsoft initially just provides a minimal size dotnetfx35setup.exe download which is a bootstrapper that will still need to download more files via Internet. For users who prefer to perform offline installation or install .NET Framework 3.5 SP1 without waiting for download to complete will have to download and save a copy of full complete standalone or redistributable Microsoft .NET Framework 3.5 SP1 setup installer, which is finally published by Microsoft.

Microsoft .NET Framework 3.5 SP1 (Service Pack 1) is a full cumulative update that contains many new features building incrementally upon .NET Framework 2.0, 3.0, 3.5, and includes cumulative servicing updates to the .NET Framework 2.0 and .NET Framework 3.0 subcomponents. See KB951847 for list of changes and fixed issues in the .NET Framework 3.5 Service Pack 1.

Download full package of Microsoft .NET Framework 3.5 SP1: dotnetfx35.exe (231 MB)

For known issues and release notes, refer to Microsoft .NET Framework 3.5 SP1 Readme.