What's new in Active Record 0.8.2?
···
==================================
Besides the overwriteable callback methods, it's now also possible to register callbacks through the use of the callback macros. Their main advantage is that the macros add behavior into a callback que that is kept intact down through an inheritance hierarchy. Example:
class Topic < ActiveRecord::Base
before_destroy :destroy_author
end
class Reply < Topic
before_destroy :destroy_readers
end
Now, when Topic#destroy is run only destroy_author is called. When Reply#destroy is run both destroy_author and destroy_readers is called. Contrast this to the situation where we've implemented the save behavior through overwriteable methods:
class Topic < ActiveRecord::Base
def before_destroy() destroy_author end
end
class Reply < Topic
def before_destroy() destroy_readers end
end
In that case, Reply#destroy would only run destroy_readers and _not_ destroy_author. So use the callback macros when you want to ensure that a certain callback is called for the entire hierarchy and the regular overwriteable methods when you want to leave it up to each descendent to decide whether they want to call super and trigger the inherited callbacks.
Additionally, these new callback macros will accept method fragments, which will be evaluated with the binding of the callback spot.
All this might seem pretty hard to understand why it's really cool. That's until you see the first application of it:
* Added :dependent option to has_many and has_one, which will automatically destroy associated objects when the holder is destroyed:
class Album < ActiveRecord::Base
has_many :tracks, :dependent => true
end
All the associated tracks are destroyed when the album is.
Pretty neat, hu?
Read more about inheritable callback ques:
http://ar.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Read more about dependent option for has_many/one:
http://ar.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M000005
Also in 0.8.2:
* Added Base.create as a factory that'll create, save, and return a new object in
one step.
* Automatically convert strings in config hashes to symbols for the _connection methods.
This allows you to pass the argument hashes directly from yaml. (Luke)
* Fixed the install.rb to include simple.rb [Spotted by Kevin Bullock]
* Modified block syntax to better follow our code standards outlined in
http://rails.rubyonrails.org/show/CodingStandards
Get the release and read more at http://activerecord.rubyonrails.org/
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