Selecting only a subset of columns.

Hi.

In many areas in the AR API you can specify a :select option to select
only a subset of columns.

Is there any way to change the default selected columns (which is "*")
to a subset of columns for a whole model.

such that when I write Model.find(1) it gives me an instance with
only, say 3 (out of 7), columns. and to fetch all columns I have to
write Model.find(1, :select => "*")

Thanks in advance.

Jarl

Can you do that in a default_scope for the model? I have not tried it.

Colin

You may try adding a "default_scope :select=>'id, name, etc' " to
your model. This would accomplish what you are looking for, but I
can't assure it won't give you problems later in your code. Maybe you
should add a regular named_scope with parameters and use it instead of
'find'.

Anyway, you should always add the 'id' attribute to that list, just in
case you want to reload a particular object you found; if you don't
have id, '.reload' won't work.

Thanks Xuan and Colin for your attention.

Xuan <xuanpa@gmail.com> writes:

You may try adding a "default_scope :select=>'id, name, etc' " to
your model. This would accomplish what you are looking for,

That was exactly what I was looking for.

My actual implentation looked like this in my AR class

  DEFAULT_SELECT = "#{column_names.reject{|c| c =~ /image/ }.map{|c| "\"orders\".\"#{c}\""}.join(', ')}".freeze
  default_scope :select => DEFAULT_SELECT

And the very few places that I need all columns, I have added :select
=> '*' to the find call

but I can't assure it won't give you problems later in your
code. Maybe you should add a regular named_scope with parameters and
use it instead of 'find'.

Fortunately I have thousands of tests to asure that :slight_smile:

Jarl

Jarl Friis <jarl@gavia.dk> writes:

Thanks Xuan and Colin for your attention.

Xuan <xuanpa@gmail.com> writes:

You may try adding a "default_scope :select=>'id, name, etc' " to
your model. This would accomplish what you are looking for,

That was exactly what I was looking for.

My actual implentation looked like this in my AR class

  DEFAULT_SELECT = "#{column_names.reject{|c| c =~ /image/ }.map{|c| "\"orders\".\"#{c}\""}.join(', ')}".freeze
  default_scope :select => DEFAULT_SELECT

Warning to others:

This is not a good solution, it gives problems upon deploying an
application at a clean environment. The problem arise when doing rake
db:migrate, since column_names tries to get column names from the
database at a time where the table does not exist!

I have not found a better way (yet)

Jarl

I think you can avoid the problem in the migration by defining the
model class inside the migration, so something like:

class YourMigration < ActiveRecord::Migration
  class TheProblematicClass < ActiveRecordBase;
  end

  def self.up
    ...

This stops your class definition being used by the migration so your
default scope is never used. In fact I believe it is good to do this
if you ever reference an AR class in the migration as the code for the
class may not match the current state of the db during migrations.

Colin

Colin