base_record.rb

Path: base_record.rb
Last Update: Tue Aug 16 23:54:41 GMT Standard Time 2005

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.

[Validate]