Class BaseRecord
In: base_record.rb
Parent: ActiveRecord::Base

Overrides ActiveRecord::Base to provide support for table_sql. This allows the table name in a query to be replaced with a subquery, essentially simulating a view within ActiveRecord.

Currently, this has only been tested on MySQL 4.1 and Ruby on Rails 0.13.1.

This defines two new class methods set_table_sql and set_table_sql_columns. Both must be used to make a BaseRecord subclass use table_sql. Usually, set_primary_key will have to be called as well (if the primary key of the view is not called id). For example, a ParentDetail class could be defined as:

  belongs_to :parent
  set_table_sql(<<-TABLE_SQL
    SELECT
      parents.id parent_id,
      SUM(children.attribute) attrib_sum
    FROM
      parents
      INNER JOIN children ON parents.id = children.parent_id
    GROUP BY parents.id
    TABLE_SQL
  )
  set_table_sql_columns([
    ActiveRecord::ConnectionAdapters::Column.new('parent_id', nil, 'bigint'),
    ActiveRecord::ConnectionAdapters::Column.new('attrib_sum', nil, 'bigint')])
  set_primary_key('parent_id')

Parent, which should also inherit from BaseRecord, could then be defined as:

  has_many :children
  has_one :parent_detail

You can then perform eager loading finds like the following:

  Parent.find(:all, :include => [:parent_detail, other includes...])

This find will produce SQL like the following:

  SELECT
    parents.id,
    other parents fields...,
    parent_details.parent_id,
    parent_details.attrib_sum,
  FROM
    parents
    LEFT OUTER JOIN (<table sql for ParentDetail>) parent_details ON parent_details.parent_id = parents.id

To upgrade to future versions of ActiveRecord (this was based on RoR 0.13.1, ActiveRecord 1.11.1):

 * Check for any changes to the overridden methods and update as necessary:
    * columns
    * construct_finder_sql
    * construct_finder_sql_with_included_associations
    * association_join
    * class_name_of_active_record_descendant
    * attributes_from_column_definition
 * Check for any new methods that access connection.columns directly and
   override to call table_sql_columns instead.

Methods

External Aliases

set_table_sql -> table_sql=
set_table_sql_columns -> table_sql_columns=

Public Class methods

Overridden to call table_sql_columns rather than connection.columns.

[Source]

# File base_record.rb, line 175
      def attributes_from_column_definition
        table_sql_columns.inject({}) do |attributes, column|
          attributes[column.name] = column.default unless column.name == self.class.primary_key
          attributes
        end
      end

Overridden from ActiveRecord::Base to use table_sql_columns rather than a direct call to connection.

[Source]

# File base_record.rb, line 95
    def columns
      @columns ||= table_sql_columns
    end

Set the table SQL.

[Source]

# File base_record.rb, line 70
    def set_table_sql( value=nil, &block )
      define_attr_method :table_sql, value, &block
    end

Set the columns to use for table SQL (required if using association eager loading).

[Source]

# File base_record.rb, line 81
    def set_table_sql_columns(value=nil, &block)
      define_val_attr_method :table_sql_columns, value, &block
    end

The name of the table to use in SQL queries - either just hte table name or the table_sql in parentheses followed by the table_name used to alias the sub query.

[Source]

# File base_record.rb, line 89
    def table_name_for_sql
      table_sql.nil? ? table_name : "(#{table_sql}) #{table_name}"
    end

The SQL to use in place of the table name (nil by default => use table_name).

[Source]

# File base_record.rb, line 65
    def table_sql
      nil
    end

Columns for the table, by default retreived from the database connection.

[Source]

# File base_record.rb, line 76
    def table_sql_columns
      connection.columns(table_name, "#{name} Columns")
    end

[Validate]