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

Ticket #7808: active_record_improved_docs_on_base.diff

File active_record_improved_docs_on_base.diff, 29.4 kB (added by fearoffish, 1 year ago)

Revised as per requested changes

  • activerecord/lib/active_record/base.rb

    old new  
    5151    end 
    5252  end 
    5353 
    54   # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with 
    55   # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change 
    56   # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain 
    57   # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones. 
     54  # For a basic overview of what you can do with Active Record, read the link:files/README.html 
     55  #  
    5856  # 
    59   # See the mapping rules in table_name and the full example in link:files/README.html for more insight. 
     57  # == Automated Mapping 
     58  #  
     59  # Active Record objects represent your database tables in an object-relational manner.  By assuming the database table 
     60  # name is a lowercase, plural, underscored version of the class name Active Record removes some of the tedious  
     61  # configuration that is normally required for mapping objects to tables.  Active Record also assumes that the  
     62  # primary key column is named "id", but as with all conventions, this can be overridden. 
     63  #  
     64  # ==== Examples: 
    6065  # 
    61   # == Creation 
     66  #  
     67  #   Class             table_name 
     68  #   ------------------------------ 
     69  #   Product           products 
     70  #   Person            people 
     71  #   WheeledTransport  wheeled_transports 
    6272  # 
    63   # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when 
    64   # you're receiving the data from somewhere else, like a HTTP request. It works like this: 
     73  # The rails generators would do this for you automatically, creating an ActiveRecord::Migration to describe the  
     74  # database table, a Product class and a blank unit test class to hold your test suite.  Like so: 
     75  #  
     76  #   ruby ./script/generate model Product 
    6577  # 
    66   #   user = User.new(:name => "David", :occupation => "Code Artist") 
    67   #   user.name # => "David" 
    6878  # 
    69   # You can also use block initialization
     79  # If we pretend for our example that we have the following database schema for our Product
    7080  # 
    71   #   user = User.new do |u| 
    72   #     u.name = "David" 
    73   #     u.occupation = "Code Artist" 
    74   #   end 
     81  #   CREATE TABLE products ( 
     82  #     id int(11) NOT NULL auto_increment, 
     83  #     name varchar(255), 
     84  #     color varchar(255), 
     85  #     PRIMARY KEY  (id) 
     86  #   ); 
     87  #  
     88  # Now let's create a Product object using the accessors that Active Record has created for us: 
    7589  # 
    76   # And of course you can just create a bare object and specify the attributes after the fact: 
     90  #   product = Product.new 
     91  #   product.name = "Shiny new product" 
     92  #   product.color = "Red" 
     93  #   product.save 
     94  #    
     95  # Notice how we have accessors for each of our table columns as well as other methods like <tt>save</tt>.  Have a look  
     96  # at the method list after this overview to see what else is available. 
    7797  # 
    78   #   user = User.new 
    79   #   user.name = "David" 
    80   #   user.occupation = "Code Artist" 
     98  # Not only do we have instance methods added to our object, but we also have class methods: 
    8199  # 
    82   # == Conditions 
     100  #   product = Product.find(1) 
     101  #   columns = Product.column_names 
     102  #  
     103  # == Conventions 
     104  #  
     105  # Active Record conventions were mentioned in the overview (link:files/README.html), their benefit to a fresh  
     106  # application is clear: Speed.  Not having to worry about the table names, foreign key names and configuration  
     107  # removes some of the burden of developing a web application, reduces development time and improves 
     108  # maintainability. 
    83109  # 
    84   # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. 
    85   # The array form is to be used when the condition input is tainted and requires sanitization. The string form can 
    86   # be used for statements that don't involve tainted data. The hash form works much like the array form, except 
    87   # only equality and range is possible. Examples: 
     110  # The most important conventions are listed here: 
     111  #  
     112  # Plural table names::  Your database tables should be the plural form of the model they represent. 
     113  # Primary keys::        The primary key of a table is assumed to be 'id'. 
     114  # Foreign keys::        Foreign keys in tables should be the singular version of the table they refer to with  
     115  #                       an _id tagged onto the end. 
     116  #  
     117  # == Overriding Conventions 
     118  #  
     119  # Sometimes you can't fit into the Active Record convention because of some other constraints, like sharing a database  
     120  # with another application, for those moments you might need to break away from convention and let Active Record  
     121  # know where you'd like to go instead. 
    88122  # 
    89   #   class User < ActiveRecord::Base 
    90   #     def self.authenticate_unsafely(user_name, password) 
    91   #       find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'") 
    92   #     end 
     123  # ==== Some examples 
     124  #  
     125  # Globally 
     126  #  
     127  #   ActiveRecord::Base.table_name_prefix = "legacy_"  # Assume this is in front of all table names 
     128  #   ActiveRecord::Base.table_name_suffix = "_legacy"  # Assume this is at the end of all table names 
     129  #   ActiveRecord::Base.pluralize_table_names = false 
    93130  # 
    94   #     def self.authenticate_safely(user_name, password) 
    95   #       find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ]) 
    96   #     end 
     131  # Per model 
    97132  # 
    98   #     def self.authenticate_safely_simply(user_name, password) 
    99   #       find(:first, :conditions => { :user_name => user_name, :password => password }) 
    100   #     end 
     133  #   class LegacyModel << ActiveRecord::Base 
     134  #     set_table_name "something_else" # change the expected table name 
     135  #     set_primary_key "primary_id"    # change the expected primary key column 
     136  #     set_sequence_name "my_sequence" # use a sequence instead of auto-incrementing the id column 
    101137  #   end 
    102138  # 
    103   # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection 
    104   # attacks if the <tt>user_name</tt> and +password+ parameters come directly from a HTTP request. The <tt>authenticate_safely</tt>  and 
    105   # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query,  
    106   # which will ensure that an attacker can't escape the query and fake the login (or worse). 
    107139  # 
    108   # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth 
    109   # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing 
    110   # the question marks with symbols and supplying a hash with values for the matching symbol keys: 
     140  # == More on attributes 
    111141  # 
    112   #   Company.find(:first, [ 
    113   #     "id = :id AND name = :name AND division = :division AND created_at > :accounting_date", 
    114   #     { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' } 
    115   #   ]) 
     142  # Active Record objects accept constructor parameters either in a hash or as a block. The hash method is  
     143  # especially useful when you're receiving the data from somewhere else, like a HTTP request. It works like this: 
    116144  # 
    117   # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND 
    118   # operator. For instance: 
     145  #   user = User.new(:name => "David", :occupation => "Code Artist") 
     146  #   user.name # => "David" 
    119147  # 
    120   #   Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 }) 
    121   #   Student.find(:all, :conditions => params[:student]) 
     148  # You can also use block initialization: 
    122149  # 
    123   # A range may be used in the hash to use the SQL BETWEEN operator: 
     150  #   user = User.new do |u| 
     151  #     u.name = "David" 
     152  #     u.occupation = "Code Artist" 
     153  #   end 
    124154  # 
    125   #   Student.find(:all, :conditions => { :grade => 9..12 }) 
     155  # And of course you can just create a bare object and specify the attributes after the fact: 
    126156  # 
    127   # == Overwriting default accessors 
     157  #   user = User.new 
     158  #   user.name = "David" 
     159  #   user.occupation = "Code Artist" 
    128160  # 
    129   # All column values are automatically available through basic accessors on the Active Record object, but some times you 
    130   # want to specialize this behavior. This can be done by either by overwriting the default accessors (using the same 
    131   # name as the attribute) calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. 
    132   # Example: 
    133161  # 
    134   #   class Song < ActiveRecord::Base 
    135   #     # Uses an integer of seconds to hold the length of the song 
     162  # === Accessing attributes before they have been typecasted 
    136163  # 
    137   #     def length=(minutes) 
    138   #       write_attribute(:length, minutes * 60) 
    139   #     end 
     164  # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run  
     165  # its course first. That can be done by using the <attribute>_before_type_cast accessors that all attributes have.  
     166  # For example, if your Account model has a balance attribute, you can call account.balance_before_type_cast or  
     167  # account.id_before_type_cast. 
    140168  # 
    141   #     def length 
    142   #       read_attribute(:length) / 60 
    143   #     end 
    144   #   end 
     169  # This is especially useful in validation situations where the user might supply a string for an integer field  
     170  # and you want to display the original string back in an error message. Accessing the attribute normally would  
     171  # typecast the string to 0, which isn't what you want. 
    145172  # 
    146   # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, vaule) and 
    147   # read_attribute(:attribute) as a shorter form. 
    148   # 
    149   # == Accessing attributes before they have been typecasted 
    150   # 
    151   # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. 
    152   # That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model 
    153   # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. 
    154   # 
    155   # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display 
    156   # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you 
    157   # want. 
    158   # 
    159173  # == Dynamic attribute-based finders 
    160174  # 
    161   # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by 
    162   # 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, 
    163   # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing 
    164   # <tt>Person.find(:first, ["user_name = ?", user_name])</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>. 
    165   # And instead of writing <tt>Person.find(:all, ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>. 
     175  # Dynamic attribute-based finders are a neat way of running simple queries that use the accessor attributes  
     176  # generated by Active Record. They work by appending the name of an attribute to <tt>find_by_</tt> or  
     177  # <tt>find_all_by_</tt>, so you get finders like Person.find_by_user_name, Person.find_all_by_last_name,  
     178  # Payment.find_by_transaction_id. So instead of writing <tt>Person.find(:first, ["user_name = ?", user_name])</tt>,  
     179  # you just do <tt>Person.find_by_user_name(user_name)</tt>, and instead of writing  
     180  # <tt>Person.find(:all, ["last_name = ?", last_name])</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>. 
    166181  # 
    167   # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like 
    168   # <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 
    169   # <tt>Person.find(:first, ["user_name = ? AND password = ?", user_name, password])</tt>, you just do 
     182  # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders  
     183  # like <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>.  
     184  # So instead of writing <tt>Person.find(:first, ["user_name = ? AND password = ?", user_name, password])</tt>, you just do 
    170185  # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>. 
    171186  # 
    172   # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount 
    173   # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is 
    174   # actually Person.find_by_user_name(user_name, options). So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>. 
     187  # It's even possible to use all the additional parameters to find. For example, the full interface for  
     188  # <tt>Payment.find_all_by_amount</tt> is actually <tt>Payment.find_all_by_amount(amount, options)</tt>, and the full  
     189  # interface to Person.find_by_user_name is actually <tt>Person.find_by_user_name(user_name, options)</tt>.  
     190  # So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>. 
    175191  # 
    176   # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with 
    177   # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Example: 
     192  # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is  
     193  # called with <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it,  
     194  # then returns it. Example: 
    178195  # 
    179196  #   # No 'Summer' tag exists 
    180197  #   Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer") 
     
    207224  #   user = User.create(:preferences => { "background" => "black", "display" => large }) 
    208225  #   User.find(user.id).preferences # => { "background" => "black", "display" => large } 
    209226  # 
    210   # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a 
    211   # descendent of a class not in the hierarchy. Example: 
     227  # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is  
     228  # retrieved as a descendent of a class not in the hierarchy. Example: 
    212229  # 
    213230  #   class User < ActiveRecord::Base 
    214231  #     serialize :preferences, Hash 
     
    219236  # 
    220237  # == Single table inheritance 
    221238  # 
    222   # Active Record allows inheritance by storing the name of the class in a column that by default is called "type" (can be changed 
    223   # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this: 
     239  # Active Record allows inheritance by storing the name of the class in a column that by default is called "type"  
     240  # (can be changed by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this: 
    224241  # 
    225242  #   class Company < ActiveRecord::Base; end 
    226243  #   class Firm < Company; end 
    227244  #   class Client < Company; end 
    228245  #   class PriorityClient < Client; end 
    229246  # 
    230   # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then 
    231   # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. 
     247  # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm".  
     248  # You can then fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. 
    232249  # 
    233   # 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 
    234   # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. 
     250  # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case,  
     251  # it'll work just like normal subclasses with no special magic for differentiating between them or reloading the right  
     252  # type with find. 
    235253  # 
    236254  # Note, all the attributes for all the cases are kept in the same table. Read more: 
    237255  # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html 
    238256  # 
    239257  # == Connection to multiple databases in different models 
    240258  # 
    241   # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. 
    242   # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. 
    243   # For example, if Course is a ActiveRecord::Base, but resides in a different database you can just say Course.establish_connection 
    244   # and Course *and all its subclasses* will use this connection instead. 
     259  # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by  
     260  # ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this connection. But you can  
     261  # also set a class-specific connection. 
     262  # For example, if Course is a ActiveRecord::Base, but resides in a different database you can just say  
     263  # Course.establish_connection and Course *and all its subclasses* will use this connection instead. 
    245264  # 
    246   # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is 
    247   # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool. 
     265  # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class.  
     266  # If a connection is requested, the retrieve_connection method will go up the class-hierarchy until a connection is 
     267  #  found in the connection pool. 
    248268  # 
    249269  # == Exceptions 
    250270  # 
     
    358378    @@schema_format = :ruby 
    359379 
    360380    class << self # Class methods 
    361       # Find operates with three different retrieval approaches: 
    362       # 
    363       # * 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]). 
     381      # Find is a very powerful method which constructs sql queries from conditions and options you give it. 
     382      # It operates with three different retrieval approaches: 
     383      #  
     384      # === Find Approaches 
     385      #  
     386      # * id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). 
    364387      #   If no record can be found for all of the listed ids, then RecordNotFound will be raised. 
    365       # * Find first: This will return the first record matched by the options used. These options can either be specific 
     388      # * first: This will return the first record matched by the options used. These options can either be specific 
    366389      #   conditions or merely an order. If no record can matched, nil is returned. 
    367       # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. 
     390      # * all: This will return all the records matched by the options used. If no records are found, an empty  
     391      #   array is returned. 
    368392      # 
     393      # === Options Hash 
     394      #  
    369395      # All approaches accept an option hash as their last parameter. The options are: 
    370396      # 
    371       # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. 
     397      # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions 
     398      #   in the intro. 
    372399      # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name". 
    373400      # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. 
    374401      # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned. 
    375       # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. 
    376       # * <tt>:joins</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed). 
     402      # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would  
     403      #   skip the first 4 rows. 
     404      # * <tt>:joins</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". 
    377405      #   The records will be returned read-only since they will have attributes that do not correspond to the table's columns. 
    378406      #   Pass :readonly => false to override. 
    379407      # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer 
    380408      #   to already defined associations. See eager loading under Associations. 
    381       # * <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 
    382       #   include the joined columns. 
    383       # * <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 
    384       #   of a database view).  
     409      # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a  
     410      #   join, but not include the joined columns. 
     411      # * <tt>:from</tt>: By default, this is the table name of the class, but can be changed to an alternate table name  
     412      #   (or even the name of a database view).  
    385413      # * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated. 
    386414      # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". 
    387415      #   :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". 
    388416      # 
    389       # Examples for find by id: 
     417      # ==== Conditions 
     418      # 
     419      # Conditions fulfil the need to retrieve records based on a certain criteria, without the conditions  
     420      # option find would fetch the first records it came across.  Conditions allow us to build an SQL  
     421      # fragment using ruby syntax and some added extras like SQL injection protection.  We can use conditions  
     422      # with all three types of find query.  If no results are found for a conditional search the result will  
     423      # either be a nil object (if using find :first) or an empty array (if using find :all). 
     424      # 
     425      #   # Simple string SQL fragment 
     426      #   User.find(:first, :conditions => "email = 'example@fearoffish.co.uk'") 
     427      #   # Array placeholder 
     428      #   User.find(:first, :conditions => ["email = ? AND first_name = ?", 'example@fearofcheese.co.uk', 'Jamie']) 
     429      #   # Array with named placeholders 
     430      #   User.find(:first, :conditions => ["email = :email", :email => 'example@fearofcheese.co.uk']) 
     431      #   # OPEN TO SQL INJECTION, DO NOT INSERT STRINGS DIRECTLY INTO THE SQL FRAGMENT 
     432      #   User.find(:first, :conditions => ["email = #{params[:email]}"]) 
     433      #   # Safe version, ActiveRecord sanitizes the value before placing it into the sql fragment 
     434      #   User.find(:first, :conditions => ["email = ?", params[:email]]) 
     435      # 
     436      # ==== Select 
     437      # 
     438      # Sometimes you only need to grab a certain set of columns from a find, or would like to perform  
     439      # a query over a join.  Using the select option you can tell Active Record which columns you'd like  
     440      # returned, it constructs the "SELECT * FROM" part of the SQL query replacing the * with whatever  
     441      # values you pass it.  If you have a table which contains a large amount of data but you only want  
     442      # the first_name and last_name returned, you can use :select. 
     443      # 
     444      #   User.find(:all, :select => "first_name, last_name") 
     445      # 
     446      # Or maybe you're constructing a query over more than one table and only need 1 value from that table,  
     447      # in the next example we grab the id's from one table and the sum of visits on posts for that user from  
     448      # another table, I know it's not the best example but it's for demonstration purposes only: 
     449      # 
     450      #   User.find(:all, :select => "users.id, SUM(posts.views) AS total_views", 
     451      #                   :from => "users, posts",  
     452      #                   :conditions => "posts.user_id = users.id",  
     453      #                   :group => "users.id") 
     454      # 
     455      # ==== Joins 
     456      # 
     457      # Although the use cases for this are rare, you can specify additional tables to include when you run  
     458      # a query.  Whatever you supply will be tagged on to the SQL query after the name of the model  
     459      # you are using and before any conditions given. 
     460      # 
     461      # Note: Be careful with this, as like ActiveRecord#find_by_sql, any database specific syntax you use  
     462      # will lock you to a particular database engine. 
     463      # 
     464      # For more specific documentation on joins and associations, please go to ActiveRecord::Associations. 
     465      #  
     466      # ==== Locks 
     467      # 
     468      # Popular web sites have hundreds, maybe thousands of hits a second on each page of their site.  What  
     469      # would happen if we had the following code: 
     470      # 
     471      #   page = Page.find(1) 
     472      #   page.visits += 1 
     473      #   page.save! 
     474      # 
     475      # This looks like it should work as expected, but with multiple concurrent users you might get 2 or more  
     476      # people reading the page visit count at the same time (therefore holding the same value), and when they  
     477      # come to write to the database they will both write the same value and the value will not have incremented  
     478      # e.g. 2 people read page.visits and receive the value 5, they both add 1 to their own value and then write  
     479      # the result back to the database and the value stored is 6, not 7 like it should be.  Locks solve this 
     480      # by locking the row in the database until the transaction is complete and thus not allowing any other  
     481      # process to unwittingly cause a clash.  The example below is the solution to the problem above: 
     482      # 
     483      #   Page.transaction do 
     484      #     page = Page.find(1, :lock => true) 
     485      #     page.visits += 1 
     486      #     page.save! 
     487      #   end 
     488      #       
     489      # ==== Find Examples 
     490      #  
     491      #   # find by id 
    390492      #   Person.find(1)       # returns the object for ID = 1 
    391493      #   Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) 
    392494      #   Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) 
    393495      #   Person.find([1])     # returns an array for objects the object with ID = 1 
    394496      #   Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC") 
    395497      # 
    396       # Note that returned records may not be in the same order as the ids you 
    397       # provide since database rows are unordered. Give an explicit :order 
    398       # to ensure the results are sorted. 
    399498      # 
    400       # Examples for find first: 
     499      #   # find first 
    401500      #   Person.find(:first) # returns the first object fetched by SELECT * FROM people 
    402501      #   Person.find(:first, :conditions => [ "user_name = ?", user_name]) 
    403502      #   Person.find(:first, :order => "created_on DESC", :offset => 5) 
    404503      # 
    405       # Examples for find all: 
     504      #   # find all 
    406505      #   Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people 
    407506      #   Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) 
    408507      #   Person.find(:all, :offset => 10, :limit => 10) 
    409508      #   Person.find(:all, :include => [ :account, :friends ]) 
    410509      #   Person.find(:all, :group => "category") 
    411510      # 
    412       # Example for find with a lock. Imagine two concurrent transactions: 
    413       # each will read person.visits == 2, add 1 to it, and save, resulting 
    414       # in two saves of person.visits = 3.  By locking the row, the second 
    415       # transaction has to wait until the first is finished; we get the 
    416       # expected person.visits == 4. 
    417       #   Person.transaction do 
    418       #     person = Person.find(1, :lock => true) 
    419       #     person.visits += 1 
    420       #     person.save! 
    421       #   end 
     511      #  
    422512      def find(*args) 
    423513        options = extract_options_from_args!(args) 
    424514        validate_find_options(options) 
     
    451541        false 
    452542      end 
    453543 
    454       # Creates an object, instantly saves it as a record (if the validation permits it), and returns it. If the save 
    455       # fails under validations, the unsaved object is still returned. 
     544      # Creates an object and saves it to the database, if validations pass, the resulting object is returned whether  
     545      # the object was saved successfully to the database or not. 
     546      # 
     547      # The +attributes+ parameter can be either be a Hash or an Array of Hashes.  These Hashes describe tbe 
     548      # attributes on the objects that are to be created 
     549      # 
     550      # ==== Examples 
     551      #   # Create a single new object 
     552      #   User.create(:first_name => 'Jamie') 
     553      #   # Create an Array of new objects 
     554      #   User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}]) 
    456555      def create(attributes = nil) 
    457556        if attributes.is_a?(Array) 
    458557          attributes.collect { |attr| create(attr) }