Posts Tagged ‘activerecord’

Deep associations in rails activerecord

May 22nd, 2010 Comments off

Some time ago I wrote about complex associations, now time to add another method and corrections.

First the finder_by_sql, in that particular case It was necessary to add

:readonly => true

So the code looks now like this:

  has_many :roles, 
    :readonly => true, 
    :finder_sql => '
INNER JOIN responsibilities ON = responsibilities.role_id
INNER JOIN assigments ON responsibilities.group_id = assigments.group_id
WHERE assigments.user_id = #{id}

There is one realy big downside of using finder_sql – it does not work with find_by_… or named scopes, so this forced me to continue searching and this is the result:

  def roles
       :joins => { :responsibilities => { :group => { :assigments => :user } } },
       :conditions => {"" => id},
       :group => ""

and now I can write:


where by_name is an named scope

  named_scope :by_name, lambda { |type| {:conditions => [ " = ", type.to_s ] } }

complex associations in rails activerecord

January 30th, 2010 1 comment

During playing with CanCan from ryanb show in last railscasts I did planned some models and find me in quite strange situation – I knew the connection, but I could not easily get the result.

My models look something like:

class User < ActiveRecord::Base
  has_many :assigments
  has_many :groups, :through => :assigments
class Assigment < ActiveRecord::Base
  belongs_to :user
  belongs_to :group
class Group < ActiveRecord::Base
  has_many :assigments
  has_many :users, :through => :assigments
  has_many :responsibilities
  has_many :roles, :through => :responsibilities
class Responsibility < ActiveRecord::Base
  belongs_to :role
  belongs_to :group
class Role < ActiveRecord::Base
  has_many :responsibilities
  has_many :groups, :through => :responsibilities

So my first try was to get roles through groups manually:{|g| 

But this solution is waste of resources, for system with a lot of possible roles it might be very inefficient, it takes first all groups of user and then ittereting through them gets all it’s roles. it will generate a lot of database queries.
So after some searching I got following code:{|r|}.uniq

To make it working I used one quite nice feature of Active record – :finder_sql – so in user.rb I have added following line:

has_many :roles, :finder_sql => 'SELECT r.* FROM users u LEFT JOIN assigments a ON LEFT JOIN responsibilities res ON a.group_id=res.group_id LEFT JOIN roles r ON'

This makes it possible to get all the roles for a user just in one call, everything calculated on database side. Unfortunately there is one down side of this – the SQL code might be not portable to other databases, so use it only when You are sure You will stick to one database.
There is also other way around, it allows to get the same data in two sql calls, without using SQL queries, just on pure ActiveRecord usage:

).map{|r| }.uniq

There are many ways to archive the same goal, knowing them is only an part – knowing how they work, makes us aware how to chose the path.

on 2009-01-31 13:15 added:
Another way going out of the Group class:


Did You liked this post or maybe not, vote on it at dzone.