Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/activerecord/lib/active_record/base.rb

Revision 9235, 115.1 kB (checked in by pratik, 8 months ago)

Ensure that respond_to? considers dynamic finder methods. Closes #11538. [floehopper]

  • Property svn:executable set to *
Line 
1 require 'yaml'
2 require 'set'
3
4 module ActiveRecord #:nodoc:
5   # Generic ActiveRecord exception class.
6   class ActiveRecordError < StandardError
7   end
8
9   # Raised when the single-table inheritance mechanism failes to locate the subclass
10   # (for example due to improper usage of column that +inheritance_column+ points to).
11   class SubclassNotFound < ActiveRecordError #:nodoc:
12   end
13
14   # Raised when object assigned to association is of incorrect type.
15   #
16   # Example:
17   #
18   # class Ticket < ActiveRecord::Base
19   #   has_many :patches
20   # end
21   #
22   # class Patch < ActiveRecord::Base
23   #   belongs_to :ticket
24   # end
25   #
26   # and somewhere in the code:
27   #
28   # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
29   # @ticket.save
30   class AssociationTypeMismatch < ActiveRecordError
31   end
32
33   # Raised when unserialized object's type mismatches one specified for serializable field.
34   class SerializationTypeMismatch < ActiveRecordError
35   end
36
37   # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field).
38   class AdapterNotSpecified < ActiveRecordError
39   end
40
41   # Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically.
42   class AdapterNotFound < ActiveRecordError
43   end
44
45   # Raised when connection to the database could not been established (for example when connection= is given a nil object).
46   class ConnectionNotEstablished < ActiveRecordError
47   end
48
49   # Raised when ActiveRecord cannot find record by given id or set of ids.
50   class RecordNotFound < ActiveRecordError
51   end
52
53   # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
54   # saved because record is invalid.
55   class RecordNotSaved < ActiveRecordError
56   end
57
58   # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old).
59   class StatementInvalid < ActiveRecordError
60   end
61
62   # Raised when number of bind variables in statement given to :condition key (for example, when using +find+ method)
63   # does not match number of expected variables.
64   #
65   # Example:
66   #
67   # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
68   #
69   # in example above two placeholders are given but only one variable to fill them.
70   class PreparedStatementInvalid < ActiveRecordError
71   end
72
73   # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
74   # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
75   # the page before the other.
76   #
77   # Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc.
78   class StaleObjectError < ActiveRecordError
79   end
80
81   # Raised when association is being configured improperly or
82   # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
83   class ConfigurationError < ActiveRecordError
84   end
85
86   # Raised on attempt to update record that is instantiated as read only.
87   class ReadOnlyRecord < ActiveRecordError
88   end
89
90   # Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations.
91   # You can use it to roll your transaction back explicitly in the block passed to +transaction+ method.
92   class Rollback < ActiveRecordError
93   end
94
95   # Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods).
96   class DangerousAttributeError < ActiveRecordError
97   end
98
99   # Raised when you've tried to access a column which wasn't
100   # loaded by your finder.  Typically this is because :select
101   # has been specified
102   class MissingAttributeError < NoMethodError
103   end
104
105   class AttributeAssignmentError < ActiveRecordError #:nodoc:
106     attr_reader :exception, :attribute
107     def initialize(message, exception, attribute)
108       @exception = exception
109       @attribute = attribute
110       @message = message
111     end
112   end
113
114   class MultiparameterAssignmentErrors < ActiveRecordError #:nodoc:
115     attr_reader :errors
116     def initialize(errors)
117       @errors = errors
118     end
119   end
120
121   # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
122   # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
123   # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain
124   # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
125   #
126   # See the mapping rules in table_name and the full example in link:files/README.html for more insight.
127   #
128   # == Creation
129   #
130   # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when
131   # you're receiving the data from somewhere else, like an HTTP request. It works like this:
132   #
133   #   user = User.new(:name => "David", :occupation => "Code Artist")
134   #   user.name # => "David"
135   #
136   # You can also use block initialization:
137   #
138   #   user = User.new do |u|
139   #     u.name = "David"
140   #     u.occupation = "Code Artist"
141   #   end
142   #
143   # And of course you can just create a bare object and specify the attributes after the fact:
144   #
145   #   user = User.new
146   #   user.name = "David"
147   #   user.occupation = "Code Artist"
148   #
149   # == Conditions
150   #
151   # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
152   # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
153   # be used for statements that don't involve tainted data. The hash form works much like the array form, except
154   # only equality and range is possible. Examples:
155   #
156   #   class User < ActiveRecord::Base
157   #     def self.authenticate_unsafely(user_name, password)
158   #       find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")
159   #     end
160   #
161   #     def self.authenticate_safely(user_name, password)
162   #       find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])
163   #     end
164   #
165   #     def self.authenticate_safely_simply(user_name, password)
166   #       find(:first, :conditions => { :user_name => user_name, :password => password })
167   #     end
168   #   end
169   #
170   # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection
171   # attacks if the <tt>user_name</tt> and +password+ parameters come directly from an HTTP request. The <tt>authenticate_safely</tt>  and
172   # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query,
173   # which will ensure that an attacker can't escape the query and fake the login (or worse).
174   #
175   # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth
176   # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing
177   # the question marks with symbols and supplying a hash with values for the matching symbol keys:
178   #
179   #   Company.find(:first, :conditions => [
180   #     "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
181   #     { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' }
182   #   ])
183   #
184   # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
185   # operator. For instance:
186   #
187   #   Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 })
188   #   Student.find(:all, :conditions => params[:student])
189   #
190   # A range may be used in the hash to use the SQL BETWEEN operator:
191   #
192   #   Student.find(:all, :conditions => { :grade => 9..12 })
193   #
194   # An array may be used in the hash to use the SQL IN operator:
195   #
196   #   Student.find(:all, :conditions => { :grade => [9,11,12] })
197   #
198   # == Overwriting default accessors
199   #
200   # All column values are automatically available through basic accessors on the Active Record object, but sometimes you
201   # want to specialize this behavior. This can be done by overwriting the default accessors (using the same
202   # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things.
203   # Example:
204   #
205   #   class Song < ActiveRecord::Base
206   #     # Uses an integer of seconds to hold the length of the song
207   #
208   #     def length=(minutes)
209   #       write_attribute(:length, minutes * 60)
210   #     end
211   #
212   #     def length
213   #       read_attribute(:length) / 60
214   #     end
215   #   end
216   #
217   # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and
218   # read_attribute(:attribute) as a shorter form.
219   #
220   # == Attribute query methods
221   #
222   # In addition to the basic accessors, query methods are also automatically available on the Active Record object.
223   # Query methods allow you to test whether an attribute value is present.
224   #
225   # For example, an Active Record User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
226   # to determine whether the user has a name:
227   #
228   #   user = User.new(:name => "David")
229   #   user.name? # => true
230   #
231   #   anonymous = User.new(:name => "")
232   #   anonymous.name? # => false
233   #
234   # == Accessing attributes before they have been typecasted
235   #
236   # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first.
237   # That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model
238   # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.
239   #
240   # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display
241   # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you
242   # want.
243   #
244   # == Dynamic attribute-based finders
245   #
246   # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by
247   # appending the name of an attribute to <tt>find_by_</tt> or <tt>find_all_by_</tt>, so you get finders like Person.find_by_user_name,
248   # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing
249   # <tt>Person.find(:first, :conditions => ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
250   # And instead of writing <tt>Person.find(:all, :conditions => ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
251   #
252   # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
253   # <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>. So instead of writing
254   # <tt>Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password])</tt>, you just do
255   # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
256   #
257   # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount
258   # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is
259   # actually Person.find_by_user_name(user_name, options). So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
260   #
261   # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
262   # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example:
263   #
264   #   # No 'Summer' tag exists
265   #   Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
266   #
267   #   # Now the 'Summer' tag does exist
268   #   Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
269   #
270   #   # Now 'Bob' exist and is an 'admin'
271   #   User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
272   #
273   # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without saving it first. Protected attributes won't be setted unless they are given in a block. For example:
274   #
275   #   # No 'Winter' tag exists
276   #   winter = Tag.find_or_initialize_by_name("Winter")
277   #   winter.new_record? # true
278   #
279   # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
280   # a list of parameters. For example:
281   #
282   #   Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
283   #
284   # That will either find an existing tag named "rails", or create a new one while setting the user that created it.
285   #
286   # == Saving arrays, hashes, and other non-mappable objects in text columns
287   #
288   # Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method +serialize+.
289   # This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:
290   #
291   #   class User < ActiveRecord::Base
292   #     serialize :preferences
293   #   end
294   #
295   #   user = User.create(:preferences => { "background" => "black", "display" => large })
296   #   User.find(user.id).preferences # => { "background" => "black", "display" => large }
297   #
298   # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a
299   # descendent of a class not in the hierarchy. Example:
300   #
301   #   class User < ActiveRecord::Base
302   #     serialize :preferences, Hash
303   #   end
304   #
305   #   user = User.create(:preferences => %w( one two three ))
306   #   User.find(user.id).preferences    # raises SerializationTypeMismatch
307   #
308   # == Single table inheritance
309   #
310   # Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed
311   # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this:
312   #
313   #   class Company < ActiveRecord::Base; end
314   #   class Firm < Company; end
315   #   class Client < Company; end
316   #   class PriorityClient < Client; end
317   #
318   # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then
319   # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object.
320   #
321   # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just
322   # like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
323   #
324   # Note, all the attributes for all the cases are kept in the same table. Read more:
325   # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
326   #
327   # == Connection to multiple databases in different models
328   #
329   # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection.
330   # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
331   # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection
332   # and Course *and all its subclasses* will use this connection instead.
333   #
334   # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
335   # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
336   #
337   # == Exceptions
338   #
339   # * +ActiveRecordError+ -- generic error class and superclass of all other errors raised by Active Record
340   # * +AdapterNotSpecified+ -- the configuration hash used in <tt>establish_connection</tt> didn't include an
341   #   <tt>:adapter</tt> key.
342   # * +AdapterNotFound+ -- the <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a non-existent adapter
343   #   (or a bad spelling of an existing one).
344   # * +AssociationTypeMismatch+ -- the object assigned to the association wasn't of the type specified in the association definition.
345   # * +SerializationTypeMismatch+ -- the serialized object wasn't of the class specified as the second parameter.
346   # * +ConnectionNotEstablished+ -- no connection has been established. Use <tt>establish_connection</tt> before querying.
347   # * +RecordNotFound+ -- no record responded to the find* method.
348   #   Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
349   # * +StatementInvalid+ -- the database server rejected the SQL statement. The precise error is added in the  message.
350   #   Either the record with the given ID doesn't exist or the record didn't meet the additional restrictions.
351   # * +MultiparameterAssignmentErrors+ -- collection of errors that occurred during a mass assignment using the
352   #   +attributes=+ method. The +errors+ property of this exception contains an array of +AttributeAssignmentError+
353   #   objects that should be inspected to determine which attributes triggered the errors.
354   # * +AttributeAssignmentError+ -- an error occurred while doing a mass assignment through the +attributes=+ method.
355   #   You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
356   #
357   # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
358   # So it's possible to assign a logger to the class through Base.logger= which will then be used by all
359   # instances in the current object space.
360   class Base
361     # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
362     # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
363     cattr_accessor :logger, :instance_writer => false
364
365     def self.inherited(child) #:nodoc:
366       @@subclasses[self] ||= []
367       @@subclasses[self] << child
368       super
369     end
370
371     def self.reset_subclasses #:nodoc:
372       nonreloadables = []
373       subclasses.each do |klass|
374         unless Dependencies.autoloaded? klass
375           nonreloadables << klass
376           next
377         end
378         klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
379         klass.instance_methods(false).each { |m| klass.send :undef_method, m }
380       end
381       @@subclasses = {}
382       nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
383     end
384
385     @@subclasses = {}
386
387     cattr_accessor :configurations, :instance_writer => false
388     @@configurations = {}
389
390     # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and
391     # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
392     # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember
393     # that this is a global setting for all Active Records.
394     cattr_accessor :primary_key_prefix_type, :instance_writer => false
395     @@primary_key_prefix_type = nil
396
397     # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
398     # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
399     # for tables in a shared database. By default, the prefix is the empty string.
400     cattr_accessor :table_name_prefix, :instance_writer => false
401     @@table_name_prefix = ""
402
403     # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
404     # "people_basecamp"). By default, the suffix is the empty string.
405     cattr_accessor :table_name_suffix, :instance_writer => false
406     @@table_name_suffix = ""
407
408     # Indicates whether table names should be the pluralized versions of the corresponding class names.
409     # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+.
410     # See table_name for the full rules on table/class naming. This is true, by default.
411     cattr_accessor :pluralize_table_names, :instance_writer => false
412     @@pluralize_table_names = true
413
414     # Determines whether to use ANSI codes to colorize the logging statements committed by the connection adapter. These colors
415     # make it much easier to overview things during debugging (when used through a reader like +tail+ and on a black background), but
416     # may complicate matters if you use software like syslog. This is true, by default.
417     cattr_accessor :colorize_logging, :instance_writer => false
418     @@colorize_logging = true
419
420     # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
421     # This is set to :local by default.
422     cattr_accessor :default_timezone, :instance_writer => false
423     @@default_timezone = :local
424
425     # Determines whether to use a connection for each thread, or a single shared connection for all threads.
426     # Defaults to false. Set to true if you're writing a threaded application.
427     cattr_accessor :allow_concurrency, :instance_writer => false
428     @@allow_concurrency = false
429
430     # Specifies the format to use when dumping the database schema with Rails'
431     # Rakefile.  If :sql, the schema is dumped as (potentially database-
432     # specific) SQL statements.  If :ruby, the schema is dumped as an
433     # ActiveRecord::Schema file which can be loaded into any database that
434     # supports migrations.  Use :ruby if you want to have different database
435     # adapters for, e.g., your development and test environments.
436     cattr_accessor :schema_format , :instance_writer => false
437     @@schema_format = :ruby
438    
439     class << self # Class methods
440       # Find operates with four different retrieval approaches:
441       #
442       # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
443       #   If no record can be found for all of the listed ids, then RecordNotFound will be raised.
444       # * Find first: This will return the first record matched by the options used. These options can either be specific
445       #   conditions or merely an order. If no record can be matched, nil is returned.
446       # * Find last: This will return the last record matched by the options used. These options can either be specific
447       #   conditions or merely an order. If no record can be matched, nil is returned.
448       # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned.
449       #
450       # All approaches accept an options hash as their last parameter. The options are:
451       #
452       # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
453       # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name".
454       # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
455       # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
456       # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
457       # * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
458       #   or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s).
459       #   If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
460       #   Pass :readonly => false to override.
461       # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
462       #   to already defined associations. See eager loading under Associations.
463       # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
464       #   include the joined columns.
465       # * <tt>:from</tt>: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
466       #   of a database view).
467       # * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated.
468       # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
469       #   :lock => true gives connection's default exclusive lock, usually "FOR UPDATE".
470       #
471       # Examples for find by id:
472       #   Person.find(1)       # returns the object for ID = 1
473       #   Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
474       #   Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
475       #   Person.find([1])     # returns an array for the object with ID = 1
476       #   Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
477       #
478       # Note that returned records may not be in the same order as the ids you
479       # provide since database rows are unordered. Give an explicit :order
480       # to ensure the results are sorted.
481       #
482       # Examples for find first:
483       #   Person.find(:first) # returns the first object fetched by SELECT * FROM people
484       #   Person.find(:first, :conditions => [ "user_name = ?", user_name])
485       #   Person.find(:first, :order => "created_on DESC", :offset => 5)
486       #
487       # Examples for find last:
488       #   Person.find(:last) # returns the last object fetched by SELECT * FROM people
489       #   Person.find(:last, :conditions => [ "user_name = ?", user_name])
490       #   Person.find(:last, :order => "created_on DESC", :offset => 5)
491       #
492       # Examples for find all:
493       #   Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
494       #   Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
495       #   Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] }
496       #   Person.find(:all, :offset => 10, :limit => 10)
497       #   Person.find(:all, :include => [ :account, :friends ])
498       #   Person.find(:all, :group => "category")
499       #
500       # Example for find with a lock. Imagine two concurrent transactions:
501       # each will read person.visits == 2, add 1 to it, and save, resulting
502       # in two saves of person.visits = 3.  By locking the row, the second
503       # transaction has to wait until the first is finished; we get the
504       # expected person.visits == 4.
505       #   Person.transaction do
506       #     person = Person.find(1, :lock => true)
507       #     person.visits += 1
508       #     person.save!
509       #   end
510       def find(*args)
511         options = args.extract_options!
512         validate_find_options(options)
513         set_readonly_option!(options)
514
515         case args.first
516           when :first then find_initial(options)
517           when :last  then find_last(options)
518           when :all   then find_every(options)
519           else             find_from_ids(args, options)
520         end
521       end
522      
523       # This is an alias for find(:first).  You can pass in all the same arguments to this method as you can
524       # to find(:first)
525       def first(*args)
526         find(:first, *args)
527       end
528
529       # This is an alias for find(:last).  You can pass in all the same arguments to this method as you can
530       # to find(:last)
531       def last(*args)
532         find(:last, *args)
533       end
534      
535       #
536       # Executes a custom sql query against your database and returns all the results.  The results will
537       # be returned as an array with columns requested encapsulated as attributes of the model you call
538       # this method from.  If you call +Product.find_by_sql+ then the results will be returned in a Product
539       # object with the attributes you specified in the SQL query.
540       #
541       # If you call a complicated SQL query which spans multiple tables the columns specified by the
542       # SELECT will be attributes of the model, whether or not they are columns of the corresponding
543       # table.
544       #
545       # The +sql+ parameter is a full sql query as a string.  It will be called as is, there will be
546       # no database agnostic conversions performed.  This should be a last resort because using, for example,
547       # MySQL specific terms will lock you to using that particular database engine or require you to
548       # change your call if you switch engines
549       #
550       # ==== Examples
551       #   # A simple sql query spanning multiple tables
552       #   Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
553       #   > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
554       #
555       #   # You can use the same string replacement techniques as you can with ActiveRecord#find
556       #   Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
557       #   > [#<Post:0x36bff9c @attributes={"first_name"=>"The Cheap Man Buys Twice"}>, ...]
558       def find_by_sql(sql)
559         connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) }
560       end
561
562       # Checks whether a record exists in the database that matches conditions given.  These conditions
563       # can either be a single integer representing a primary key id to be found, or a condition to be
564       # matched like using ActiveRecord#find.
565       #
566       # The +id_or_conditions+ parameter can be an Integer or a String if you want to search the primary key
567       # column of the table for a matching id, or if you're looking to match against a condition you can use
568       # an Array or a Hash.
569       #
570       # Possible gotcha: You can't pass in a condition as a string e.g. "name = 'Jamie'", this would be
571       # sanitized and then queried against the primary key column as "id = 'name = \'Jamie"
572       #
573       # ==== Examples
574       #   Person.exists?(5)
575       #   Person.exists?('5')
576       #   Person.exists?(:name => "David")
577       #   Person.exists?(['name LIKE ?', "%#{query}%"])
578       def exists?(id_or_conditions)
579         connection.select_all(
580           construct_finder_sql(
581             :select     => "#{quoted_table_name}.#{primary_key}",
582             :conditions => expand_id_conditions(id_or_conditions),
583             :limit      => 1
584           ),
585           "#{name} Exists"
586         ).size > 0
587       end
588
589       # Creates an object (or multiple objects) and saves it to the database, if validations pass.
590       # The resulting object is returned whether the object was saved successfully to the database or not.
591       #
592       # The +attributes+ parameter can be either be a Hash or an Array of Hashes.  These Hashes describe the
593       # attributes on the objects that are to be created.
594       #
595       # ==== Examples
596       #   # Create a single new object
597       #   User.create(:first_name => 'Jamie')
598       #   # Create an Array of new objects
599       #   User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}])
600       def create(attributes = nil)
601         if attributes.is_a?(Array)
602           attributes.collect { |attr| create(attr) }
603         else
604           object = new(attributes)
605           object.save
606           object
607         end
608       end
609
610       # Updates an object (or multiple objects) and saves it to the database, if validations pass.
611       # The resulting object is returned whether the object was saved successfully to the database or not.
612       #
613       # ==== Options
614       #
615       # +id+          This should be the id or an array of ids to be updated
616       # +attributes+  This should be a Hash of attributes to be set on the object, or an array of Hashes.
617       #
618       # ==== Examples
619       #
620       #   # Updating one record:
621       #   Person.update(15, {:user_name => 'Samuel', :group => 'expert'})
622       #
623       #   # Updating multiple records:
624       #   people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
625       #   Person.update(people.keys, people.values)
626       def update(id, attributes)
627         if id.is_a?(Array)
628           idx = -1
629           id.collect { |one_id| idx += 1; update(one_id, attributes[idx]) }
630         else
631           object = find(id)
632           object.update_attributes(attributes)
633           object
634         end
635       end
636
637       # Delete an object (or multiple objects) where the +id+ given matches the primary_key.  A SQL +DELETE+ command
638       # is executed on the database which means that no callbacks are fired off running this.  This is an efficient method
639       # of deleting records that don't need cleaning up after or other actions to be taken.
640       #
641       # Objects are _not_ instantiated with this method.
642       #
643       # ==== Options
644       #
645       # +id+  Can be either an Integer or an Array of Integers
646       #
647       # ==== Examples
648       #
649       #   # Delete a single object
650       #   Todo.delete(1)
651       #
652       #   # Delete multiple objects
653       #   todos = [1,2,3]
654       #   Todo.delete(todos)
655       def delete(id)
656         delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ])
657       end
658
659       # Destroy an object (or multiple objects) that has the given id, the object is instantiated first,
660       # therefore all callbacks and filters are fired off before the object is deleted.  This method is
661       # less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.
662       #
663       # This essentially finds the object (or multiple objects) with the given id, creates a new object
664       # from the attributes, and then calls destroy on it.
665       #
666       # ==== Options
667       #
668       # +id+  Can be either an Integer or an Array of Integers
669       #
670       # ==== Examples
671       #
672       #   # Destroy a single object
673       #   Todo.destroy(1)
674       #
675       #   # Destroy multiple objects
676       #   todos = [1,2,3]
677       #   Todo.destroy(todos)
678       def destroy(id)
679         if id.is_a?(Array)
680           id.map { |one_id| destroy(one_id) }
681         else
682           find(id).destroy
683         end
684       end
685
686       # Updates all records with details given if they match a set of conditions supplied, limits and order can
687       # also be supplied.
688       #
689       # ==== Options
690       #
691       # +updates+     A String of column and value pairs that will be set on any records that match conditions
692       # +conditions+  An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
693       #               See conditions in the intro for more info.
694       # +options+     Additional options are :limit and/or :order, see the examples for usage.
695       #
696       # ==== Examples
697       #
698       #   # Update all billing objects with the 3 different attributes given
699       #   Billing.update_all( "category = 'authorized', approved = 1, author = 'David'" )
700       #
701       #   # Update records that match our conditions
702     &nbs