Skip to content

Instantly share code, notes, and snippets.

@oojikoo-gist
Created April 16, 2015 06:32
Show Gist options
  • Save oojikoo-gist/1dab61d3594ae21ae118 to your computer and use it in GitHub Desktop.
Save oojikoo-gist/1dab61d3594ae21ae118 to your computer and use it in GitHub Desktop.
rails: column_reader

reference: tomafro.net

Read ActiveRecord columns directly from the class

Sometimes you want to read just a single column from a collection of records, without the overhead of instantiating each and every one. You could just execute raw SQL, but it’s a shame to do away with the nice type conversion ActiveRecord provides. It’d also be a pity to get rid of find scoping, amongst other goodness.

module Tomafro::ColumnReader
  def column_reader(column_name, options = {})
    name = options.delete(:as) || column_name.to_s.pluralize
    column = columns_hash[column_name.to_s]
    
    self.module_eval %{
      def self.#{name}(options = {})
        merged = options.merge(:select => '#{column_name}')
        connection.select_all(construct_finder_sql(merged)).collect do |value| 
          v = value.values.first
          #{column.type_cast_code('v')}
        end
      end
    }
  end
end

Once you’ve extended ActiveRecord::Base with it, usage is simple. In your models, declare which columns you want access to:

ActiveRecord::Base.extend Tomafro::ColumnReader
 
class Animal < ActiveRecord::Base
  column_reader 'id'
  column_reader 'name'  
 
  named_scope :dangerous, :conditions => {:carnivorous => true} 
end
Animal.names 
#=> ['Lion', 'Tiger', 'Zebra', 'Gazelle']
 
Animal.names :limit => 1 
#=> ['Lion'] (Normal finder options supported)
 
Animal.dangerous.names 
#=> ['Lion', 'Tiger'] (Scoping respected)
 
Animal.ids
#=> [1, 2, 3] (Values cast correctly)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment