D
David Heinemeier Hansson
What's new in Active Record 0.8.1?
==================================
The release of 0.8.0 prompted a discussion of object-level transactions
and the Transaction::Simple library by Austin Ziegler was mentioned.
Thanks to this wonderful library, Active Record now supports
object-level transactions on top of the database-backed ones. You just
have to name the active records that you want to place under
object-transactions, like this:
Account.transaction(david, mary) do
david.withdrawal(100)
mary.deposit(100)
end
On exception or return of false, both the database and the objects will
be rolled back to their pre-transactional state. It's entirely optional
to use the object-transaction. Just don't pass any active records to
the transaction method.
This release also features a new generic connection method, which
breaks the interface of the old style. So be sure to update. Two
examples:
ActiveRecord::Base.establish_connection
adapter => "sqlite", :dbfile
=> "dbfile")
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "me",
assword => "secret",
:database => "activerecord"
)
Read more in:
http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000081
Also in 0.8.1:
* Fixed SQLite adapter so objects fetched from has_and_belongs_to_many
have proper
attributes (t.name is now name). [Spotted by Garrett Rooney]
* Fixed SQLite adapter so dates are returned as Date objects, not Time
objects
[Spotted by Gavin Sinclair]
* Fixed requirement of date class, so date conversions are succesful
regardless of
whether you manually require date or not.
Get the release and read more at http://activerecord.rubyonrails.org/
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 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
* Observers for the entire lifecycle
class CommentObserver < ActiveRecord::Observer
def after_create(comment) # is called just after Comment#save
NotificationService.send_email("(e-mail address removed)", 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",
assword => "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
==================================
The release of 0.8.0 prompted a discussion of object-level transactions
and the Transaction::Simple library by Austin Ziegler was mentioned.
Thanks to this wonderful library, Active Record now supports
object-level transactions on top of the database-backed ones. You just
have to name the active records that you want to place under
object-transactions, like this:
Account.transaction(david, mary) do
david.withdrawal(100)
mary.deposit(100)
end
On exception or return of false, both the database and the objects will
be rolled back to their pre-transactional state. It's entirely optional
to use the object-transaction. Just don't pass any active records to
the transaction method.
This release also features a new generic connection method, which
breaks the interface of the old style. So be sure to update. Two
examples:
ActiveRecord::Base.establish_connection
=> "dbfile")
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "me",
:database => "activerecord"
)
Read more in:
http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000081
Also in 0.8.1:
* Fixed SQLite adapter so objects fetched from has_and_belongs_to_many
have proper
attributes (t.name is now name). [Spotted by Garrett Rooney]
* Fixed SQLite adapter so dates are returned as Date objects, not Time
objects
[Spotted by Gavin Sinclair]
* Fixed requirement of date class, so date conversions are succesful
regardless of
whether you manually require date or not.
Get the release and read more at http://activerecord.rubyonrails.org/
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 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
* Observers for the entire lifecycle
class CommentObserver < ActiveRecord::Observer
def after_create(comment) # is called just after Comment#save
NotificationService.send_email("(e-mail address removed)", 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
:dbfile => "dbfile")
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "me",
: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