@home   @rss   @archive   @codeforpeople.com     @radio[:m3u|:pls|:ruby]   @family   @neighbors 


ActiveRecord#each?

Something that’s struck me as odd lately while working with ActiveRecord is the apparent lack of any iteration support. ActiveRecord results don’t come back flat - they are a tree - and so iterating them generically can be a biaatch. Here’s a little go at it:

##############################################################################
# SCHEMA
##############################################################################
#
# create table company (
#   name string,
#   company_id integer primary key
# );
#
# create table employee (
#   name string,
#   employee_id integer primary key
# );
#
# create table company_employee (
#   company_id integer,
#   employee_id integer
# );
#
# insert into employee values (“ara”, NULL);          — 1
# insert into employee values (“dan”, NULL);          — 2
#
# insert into company values (“codeforpeople”, NULL); — 1
# insert into company values (“eparklabs”, NULL);     — 2
#
# insert into company_employee values ( 1, 1 );       — ara works for codeforpeople
# insert into company_employee values ( 2, 1 );       — ara works for eparklabs
# insert into company_employee values ( 2, 2 );       — dan works for eparklabs
#


##############################################################################
# CONFIG
##############################################################################
#
# ActiveRecord::Base::primary_key_prefix_type = :table_name_with_underscore
# ActiveRecord::Base::pluralize_table_names = false
#


##############################################################################
# DEMO
##############################################################################

  require config/environment.rb
  require config/boot.rb

  records = Employee.find :all, :include => :company

  records.each do |record|
    crawl record do |key, value|
      printf %-42.42s => %-32.32s\n, key, value
    end
    puts
  end


##############################################################################
# OUTPUT
##############################################################################
#
# employee[1].company[1].name                => codeforpeople                  
# employee[1].company[1].company_id          => 1                              
# employee[1].company[2].name                => eparklabs                      
# employee[1].company[2].company_id          => 2                              
# employee[1].name                           => ara                            
# employee[1].employee_id                    => 1                              
#
# employee[2].company[2].name                => eparklabs                      
# employee[2].company[2].company_id          => 2                              
# employee[2].name                           => dan                            
# employee[2].employee_id                    => 2                              
#


##############################################################################
# THE CODE
##############################################################################
BEGIN{
  def crawl record, visited={}, prefix=, &b
    return record if visited[record]
    visited[record] = true

    tid = record.class.table_name
    oid = record.id

    ### yes this __is__ pure evil
    columns = {}.update record.instance_variable_get(@attributes)
    record.instance_variables.each do |ivar|
      next if ivar == @attributes
      k = ivar[1..-1]
      v = record.instance_variable_get ivar
      columns.update k => v
    end

    columns.each do |cid, value|
      if(value.is_a? Array and value.first.is_a? ActiveRecord::Base)
        value.each do |v|
          crawl v, visited, #{ tid }[#{ oid }]., &b
        end
      elsif value.is_a? ActiveRecord::Base
        crawl value, visited, #{ tid }[#{ oid }]., &b
      else
        yield [#{ prefix }#{ tid }[#{ oid }].#{ cid }, value]
      end
    end

    record
  end
}

Anyone else got a better idea? If so ping me offline @ [[the address that you can find via google]].

Comments (View)
blog comments powered by Disqus