Froze rails gems
[depot.git] / vendor / rails / activerecord / README
1 = Active Record -- Object-relation mapping put on rails
2
3 Active Record connects business objects and database tables to create a persistable
4 domain model where logic and data are presented in one wrapping. It's an implementation
5 of the object-relational mapping (ORM) pattern[http://www.martinfowler.com/eaaCatalog/activeRecord.html]
6 by the same name as described by Martin Fowler:
7
8 "An object that wraps a row in a database table or view, encapsulates
9 the database access, and adds domain logic on that data."
10
11 Active Record's main contribution to the pattern is to relieve the original of two stunting problems:
12 lack of associations and inheritance. By adding a simple domain language-like set of macros to describe
13 the former and integrating the Single Table Inheritance pattern for the latter, Active Record narrows the
14 gap of functionality between the data mapper and active record approach.
15
16 A short rundown of the major features:
17
18 * Automated mapping between classes and tables, attributes and columns.
19
20 class Product < ActiveRecord::Base; end
21
22 ...is automatically mapped to the table named "products", such as:
23
24 CREATE TABLE products (
25 id int(11) NOT NULL auto_increment,
26 name varchar(255),
27 PRIMARY KEY (id)
28 );
29
30 ...which again gives Product#name and Product#name=(new_name)
31
32 {Learn more}[link:classes/ActiveRecord/Base.html]
33
34
35 * Associations between objects controlled by simple meta-programming macros.
36
37 class Firm < ActiveRecord::Base
38 has_many :clients
39 has_one :account
40 belongs_to :conglomorate
41 end
42
43 {Learn more}[link:classes/ActiveRecord/Associations/ClassMethods.html]
44
45
46 * Aggregations of value objects controlled by simple meta-programming macros.
47
48 class Account < ActiveRecord::Base
49 composed_of :balance, :class_name => "Money",
50 :mapping => %w(balance amount)
51 composed_of :address,
52 :mapping => [%w(address_street street), %w(address_city city)]
53 end
54
55 {Learn more}[link:classes/ActiveRecord/Aggregations/ClassMethods.html]
56
57
58 * Validation rules that can differ for new or existing objects.
59
60 class Account < ActiveRecord::Base
61 validates_presence_of :subdomain, :name, :email_address, :password
62 validates_uniqueness_of :subdomain
63 validates_acceptance_of :terms_of_service, :on => :create
64 validates_confirmation_of :password, :email_address, :on => :create
65 end
66
67 {Learn more}[link:classes/ActiveRecord/Validations.html]
68
69 * Callbacks as methods or queues on the entire lifecycle (instantiation, saving, destroying, validating, etc).
70
71 class Person < ActiveRecord::Base
72 def before_destroy # is called just before Person#destroy
73 CreditCard.find(credit_card_id).destroy
74 end
75 end
76
77 class Account < ActiveRecord::Base
78 after_find :eager_load, 'self.class.announce(#{id})'
79 end
80
81 {Learn more}[link:classes/ActiveRecord/Callbacks.html]
82
83
84 * Observers for the entire lifecycle
85
86 class CommentObserver < ActiveRecord::Observer
87 def after_create(comment) # is called just after Comment#save
88 Notifications.deliver_new_comment("david@loudthinking.com", comment)
89 end
90 end
91
92 {Learn more}[link:classes/ActiveRecord/Observer.html]
93
94
95 * Inheritance hierarchies
96
97 class Company < ActiveRecord::Base; end
98 class Firm < Company; end
99 class Client < Company; end
100 class PriorityClient < Client; end
101
102 {Learn more}[link:classes/ActiveRecord/Base.html]
103
104
105 * Transactions
106
107 # Database transaction
108 Account.transaction do
109 david.withdrawal(100)
110 mary.deposit(100)
111 end
112
113 {Learn more}[link:classes/ActiveRecord/Transactions/ClassMethods.html]
114
115
116 * Reflections on columns, associations, and aggregations
117
118 reflection = Firm.reflect_on_association(:clients)
119 reflection.klass # => Client (class)
120 Firm.columns # Returns an array of column descriptors for the firms table
121
122 {Learn more}[link:classes/ActiveRecord/Reflection/ClassMethods.html]
123
124
125 * Direct manipulation (instead of service invocation)
126
127 So instead of (Hibernate[http://www.hibernate.org/] example):
128
129 long pkId = 1234;
130 DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );
131 // something interesting involving a cat...
132 sess.save(cat);
133 sess.flush(); // force the SQL INSERT
134
135 Active Record lets you:
136
137 pkId = 1234
138 cat = Cat.find(pkId)
139 # something even more interesting involving the same cat...
140 cat.save
141
142 {Learn more}[link:classes/ActiveRecord/Base.html]
143
144
145 * Database abstraction through simple adapters (~100 lines) with a shared connector
146
147 ActiveRecord::Base.establish_connection(:adapter => "sqlite", :database => "dbfile")
148
149 ActiveRecord::Base.establish_connection(
150 :adapter => "mysql",
151 :host => "localhost",
152 :username => "me",
153 :password => "secret",
154 :database => "activerecord"
155 )
156
157 {Learn more}[link:classes/ActiveRecord/Base.html#M000081] and read about the built-in support for
158 MySQL[link:classes/ActiveRecord/ConnectionAdapters/MysqlAdapter.html], PostgreSQL[link:classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html], SQLite[link:classes/ActiveRecord/ConnectionAdapters/SQLiteAdapter.html], Oracle[link:classes/ActiveRecord/ConnectionAdapters/OracleAdapter.html], SQLServer[link:classes/ActiveRecord/ConnectionAdapters/SQLServerAdapter.html], and DB2[link:classes/ActiveRecord/ConnectionAdapters/DB2Adapter.html].
159
160
161 * Logging support for Log4r[http://log4r.sourceforge.net] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc]
162
163 ActiveRecord::Base.logger = Logger.new(STDOUT)
164 ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")
165
166
167 * Database agnostic schema management with Migrations
168
169 class AddSystemSettings < ActiveRecord::Migration
170 def self.up
171 create_table :system_settings do |t|
172 t.string :name
173 t.string :label
174 t.text :value
175 t.string :type
176 t.integer :position
177 end
178
179 SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
180 end
181
182 def self.down
183 drop_table :system_settings
184 end
185 end
186
187 {Learn more}[link:classes/ActiveRecord/Migration.html]
188
189 == Simple example (1/2): Defining tables and classes (using MySQL)
190
191 Data definitions are specified only in the database. Active Record queries the database for
192 the column names (that then serves to determine which attributes are valid) on regular
193 object instantiation through the new constructor and relies on the column names in the rows
194 with the finders.
195
196 # CREATE TABLE companies (
197 # id int(11) unsigned NOT NULL auto_increment,
198 # client_of int(11),
199 # name varchar(255),
200 # type varchar(100),
201 # PRIMARY KEY (id)
202 # )
203
204 Active Record automatically links the "Company" object to the "companies" table
205
206 class Company < ActiveRecord::Base
207 has_many :people, :class_name => "Person"
208 end
209
210 class Firm < Company
211 has_many :clients
212
213 def people_with_all_clients
214 clients.inject([]) { |people, client| people + client.people }
215 end
216 end
217
218 The foreign_key is only necessary because we didn't use "firm_id" in the data definition
219
220 class Client < Company
221 belongs_to :firm, :foreign_key => "client_of"
222 end
223
224 # CREATE TABLE people (
225 # id int(11) unsigned NOT NULL auto_increment,
226 # name text,
227 # company_id text,
228 # PRIMARY KEY (id)
229 # )
230
231 Active Record will also automatically link the "Person" object to the "people" table
232
233 class Person < ActiveRecord::Base
234 belongs_to :company
235 end
236
237 == Simple example (2/2): Using the domain
238
239 Picking a database connection for all the Active Records
240
241 ActiveRecord::Base.establish_connection(
242 :adapter => "mysql",
243 :host => "localhost",
244 :username => "me",
245 :password => "secret",
246 :database => "activerecord"
247 )
248
249 Create some fixtures
250
251 firm = Firm.new("name" => "Next Angle")
252 # SQL: INSERT INTO companies (name, type) VALUES("Next Angle", "Firm")
253 firm.save
254
255 client = Client.new("name" => "37signals", "client_of" => firm.id)
256 # SQL: INSERT INTO companies (name, client_of, type) VALUES("37signals", 1, "Firm")
257 client.save
258
259 Lots of different finders
260
261 # SQL: SELECT * FROM companies WHERE id = 1
262 next_angle = Company.find(1)
263
264 # SQL: SELECT * FROM companies WHERE id = 1 AND type = 'Firm'
265 next_angle = Firm.find(1)
266
267 # SQL: SELECT * FROM companies WHERE id = 1 AND name = 'Next Angle'
268 next_angle = Company.find(:first, :conditions => "name = 'Next Angle'")
269
270 next_angle = Firm.find_by_sql("SELECT * FROM companies WHERE id = 1").first
271
272 The supertype, Company, will return subtype instances
273
274 Firm === next_angle
275
276 All the dynamic methods added by the has_many macro
277
278 next_angle.clients.empty? # true
279 next_angle.clients.size # total number of clients
280 all_clients = next_angle.clients
281
282 Constrained finds makes access security easier when ID comes from a web-app
283
284 # SQL: SELECT * FROM companies WHERE client_of = 1 AND type = 'Client' AND id = 2
285 thirty_seven_signals = next_angle.clients.find(2)
286
287 Bi-directional associations thanks to the "belongs_to" macro
288
289 thirty_seven_signals.firm.nil? # true
290
291
292 == Philosophy
293
294 Active Record attempts to provide a coherent wrapper as a solution for the inconvenience that is
295 object-relational mapping. The prime directive for this mapping has been to minimize
296 the amount of code needed to build a real-world domain model. This is made possible
297 by relying on a number of conventions that make it easy for Active Record to infer
298 complex relations and structures from a minimal amount of explicit direction.
299
300 Convention over Configuration:
301 * No XML-files!
302 * Lots of reflection and run-time extension
303 * Magic is not inherently a bad word
304
305 Admit the Database:
306 * Lets you drop down to SQL for odd cases and performance
307 * Doesn't attempt to duplicate or replace data definitions
308
309
310 == Download
311
312 The latest version of Active Record can be found at
313
314 * http://rubyforge.org/project/showfiles.php?group_id=182
315
316 Documentation can be found at
317
318 * http://ar.rubyonrails.com
319
320
321 == Installation
322
323 The prefered method of installing Active Record is through its GEM file. You'll need to have
324 RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have,
325 then use:
326
327 % [sudo] gem install activerecord-1.10.0.gem
328
329 You can also install Active Record the old-fashioned way with the following command:
330
331 % [sudo] ruby install.rb
332
333 from its distribution directory.
334
335
336 == License
337
338 Active Record is released under the MIT license.
339
340
341 == Support
342
343 The Active Record homepage is http://www.rubyonrails.com. You can find the Active Record
344 RubyForge page at http://rubyforge.org/projects/activerecord. And as Jim from Rake says:
345
346 Feel free to submit commits or feature requests. If you send a patch,
347 remember to update the corresponding unit tests. If fact, I prefer
348 new feature to be submitted in the form of new unit tests.
349
350 For other information, feel free to ask on the rubyonrails-talk
351 (http://groups.google.com/group/rubyonrails-talk) mailing list.