What's new in Active Record 0.8.3?
==================================

Active Records in modules are now treated nicely by both the mapping  
and association logic. The mapping can be more finely controlled with  
options for different primary keys than ┼╩dand for non-integer keys.  
The dependent option on associations are now treated as a transaction.  
And many other changes:


Transactions
------------

* Added transactional protection for destroy
   (important for the new :dependent option) [Suggested by Carl  
Youngblood]

* Fixed so transactions are ignored on MyISAM tables for MySQL
   (use InnoDB to get transactions)

* Changed transactions so only exceptions will cause a rollback, not  
returned false.


Mapping
-------

* Added support for non-integer primary keys [Aredridel/earlier work by  
Michael Neumann]

     User.find "jdoe"
     Product.find "PDKEY-INT-12"

* Added option to specify naming method for primary key column.
   ActiveRecord::Base.primary_key_prefix_type can either  be set to nil,  
:table_name, or
   :table_name_with_underscore. :table_name will assume that Product  
class has a primary key
   of "productid" and :table_name_with_underscore will assume  
"product_id".
   The default nil will just give "id".

* Added an overwriteable primary_key method that'll instruct AR to the  
name of the
   id column [Aredridele/earlier work by Guan Yang]

     class Project < ActiveRecord::Base
       def self.primary_key() "project_id" end
     end

* Fixed that Active Records can safely associate inside and out of  
modules.

     class MyApplication::Account < ActiveRecord::Base
       has_many :clients # will look for MyApplication::Client
       has_many :interests, :class_name => "Business::Interest" # will  
look for Business::Interest
     end

* Fixed that Active Records can safely live inside modules [Aredridel]

     class MyApplication::Account < ActiveRecord::Base
     end


Misc
----

* Added freeze call to value object assignments to ensure they remain  
immutable
   [Spotted by Gavin Sinclair]

* Changed interface for specifying observed class in observers. Was  
OBSERVED_CLASS constant,
   now is observed_class() class method. This is more consistant with  
things like
   self.table_name(). Works like this:

     class AuditObserver < ActiveRecord::Observer
       def self.observed_class() Account end
       def after_update(account)
         AuditTrail.new(account, "UPDATED")
       end
     end

   [Suggested by Gavin Sinclair]

* Create new Active Record objects by setting the attributes through a  
block. Like this:

     person = Person.new do |p|
       p.name = 'Freddy'
       p.age  = 19
     end

   [Suggested by Gavin Sinclair]

Get the new version on http://activerecord.rubyonrails.org or, even  
better, type "gem -Ri activerecord"
when the 0.8.3 version appears on the "gem -Rl" list (it should very  
soon).


Hang out with the Ruby on Rails crowd
=====================================

Come by the IRC channel #rubyonrails on Freenode. Design decisions are  
aired here and you'll be able to ask questions about Active Record and  
the framework in general. Oh, and we're really friendly too!


Call for help!
==============

Do you have working knowledge with and access to either Oracle, ODBC,  
Sybase, or DB2, I'd be really grateful if you would consider writing an  
adapter for Active Record. Adapters are usually just around 100 lines  
of code. You'll have three examples to look at, a well-specified  
interface[1], and almost 100 test cases to make it real easy. Luke  
Holden reports that he spent just a few hours getting SQLite and  
PostgreSQL adapters working.

[1]  
http://ar.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ 
AbstractAdapter.html


Active Record -- Object-relation mapping put on rails
=====================================================

Active Record connects business objects and database tables to create a  
persistable
domain model where logic and data is presented in one wrapping. It's an  
implementation of the object-relational mapping (ORM) pattern by the  
same name as described by Martin Fowler:

   "An object that wraps a row in a database table or view, encapsulates
        the database access, and adds domain logic on that data."

Active Records main contribution to the pattern is to relieve the  
original of two stunting problems: lack of associations and  
inheritance. By adding a simple domain language-like set of macros to  
describe the former and integrating the Single Table Inheritance  
pattern for the latter, Active Record narrows the gap of functionality  
between the data mapper and active record approach.

A short rundown of the major features:

* Automated mapping between classes and tables, attributes and columns.
    class Product < ActiveRecord::Base; end

    ...is automatically mapped to the table named "products", such as:

    CREATE TABLE products (
      id int(11) NOT NULL auto_increment,
      name varchar(255),
      PRIMARY KEY  (id)
    );

    ...which again gives Product#name and Product#name=(new_name)


* Associations between objects controlled by simple meta-programming  
macros.
    class Firm < ActiveRecord::Base
      has_many  :clients
      has_one   :account
      belong_to :conglomorate
    end


* Aggregations of value objects controlled by simple meta-programming  
macros.
    class Account < ActiveRecord::Base
      composed_of :balance, :class_name => "Money",
                  :mapping => %w(balance amount)
      composed_of :address,
                  :mapping => [%w(address_street street),  
%w(address_city city)]
    end


* Validation rules that can differ for new or existing objects.
    class Post < ActiveRecord::Base
      def validate # validates on both creates and updates
        errors.add_on_empty "title"
      end

      def validate_on_update
        errors.add_on_empty "password"
      end
    end


* Callbacks as methods or ques on the entire lifecycle
   (instantiation, saving, destroying, validating, etc).

    class Person < ActiveRecord::Base
      def before_destroy # is called just before Person#destroy
        CreditCard.find(credit_card_id).destroy
      end
    end

    class Account < ActiveRecord::Base
      after_find :eager_load, 'self.class.announce(#{id})'
    end

   Learn more in link:classes/ActiveRecord/Callbacks.html


* Observers for the entire lifecycle
    class CommentObserver < ActiveRecord::Observer
      def after_create(comment) # is called just after Comment#save
        NotificationService.send_email("david / loudthinking.com", comment)
      end
    end


* Inheritance hierarchies
    class Company < ActiveRecord::Base; end
    class Firm < Company; end
    class Client < Company; end
    class PriorityClient < Client; end


* Transaction support on both a database and object level. The latter  
is implemented
   by using Transaction::Simple

     # Just database transaction
     Account.transaction do
       david.withdrawal(100)
       mary.deposit(100)
     end

     # Database and object transaction
     Account.transaction(david, mary) do
       david.withdrawal(100)
       mary.deposit(100)
     end


* Direct manipulation (instead of service invocation)

   So instead of (Hibernate example):

      long pkId = 1234;
      DomesticCat pk = (DomesticCat) sess.load( Cat.class, new  
Long(pkId) );
      // something interesting involving a cat...
      sess.save(cat);
      sess.flush(); // force the SQL INSERT

   Active Record lets you:

      pkId = 1234
      cat = Cat.find(pkId)
      # something even more interesting involving a the same cat...
      cat.save


* Database abstraction through simple adapters (~100 lines) with a  
shared connector

    ActiveRecord::Base.establish_connection(:adapter => "sqlite",  
:dbfile => "dbfile")

    ActiveRecord::Base.establish_connection(
      :adapter  => "mysql",
      :host     => "localhost",
      :username => "me",
      :password => "secret",
      :database => "activerecord"
    )


* Logging support for Log4r and Logger

     ActiveRecord::Base.logger = Logger.new(STDOUT)
     ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")


Philosophy
==========

Active Record attempts to provide a coherent wrapping for the  
inconvenience that is object-relational mapping. The prime directive  
for this mapping has been to minimize the amount of code needed to  
built a real-world domain model. This is made possible by relying on a  
number of conventions that make it easy for Active Record to infer  
complex relations and structures from a minimal amount of explicit  
direction.

Convention over Configuration:
* No XML-files!
* Lots of reflection and run-time extension
* Magic is not inherently a bad word

Admit the Database:
* Lets you drop down to SQL for odd cases and performance
* Doesn't attempt to duplicate or replace data definitions