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) |
|---|
-
activerecord/lib/active_record/base.rb
old new 51 51 end 52 52 end 53 53 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 # 58 56 # 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: 60 65 # 61 # == Creation 66 # 67 # Class table_name 68 # ------------------------------ 69 # Product products 70 # Person people 71 # WheeledTransport wheeled_transports 62 72 # 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 65 77 # 66 # user = User.new(:name => "David", :occupation => "Code Artist")67 # user.name # => "David"68 78 # 69 # You can also use block initialization:79 # If we pretend for our example that we have the following database schema for our Product: 70 80 # 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: 75 89 # 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. 77 97 # 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: 81 99 # 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. 83 109 # 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. 88 122 # 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 93 130 # 94 # def self.authenticate_safely(user_name, password) 95 # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ]) 96 # end 131 # Per model 97 132 # 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 101 137 # end 102 138 # 103 # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection104 # attacks if the <tt>user_name</tt> and +password+ parameters come directly from a HTTP request. The <tt>authenticate_safely</tt> and105 # <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).107 139 # 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 111 141 # 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: 116 144 # 117 # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND118 # operator. For instance:145 # user = User.new(:name => "David", :occupation => "Code Artist") 146 # user.name # => "David" 119 147 # 120 # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 }) 121 # Student.find(:all, :conditions => params[:student]) 148 # You can also use block initialization: 122 149 # 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 124 154 # 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: 126 156 # 127 # == Overwriting default accessors 157 # user = User.new 158 # user.name = "David" 159 # user.occupation = "Code Artist" 128 160 # 129 # All column values are automatically available through basic accessors on the Active Record object, but some times you130 # want to specialize this behavior. This can be done by either by overwriting the default accessors (using the same131 # name as the attribute) calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things.132 # Example:133 161 # 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 136 163 # 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. 140 168 # 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. 145 172 # 146 # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, vaule) and147 # read_attribute(:attribute) as a shorter form.148 #149 # == Accessing attributes before they have been typecasted150 #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 model153 # 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 display156 # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you157 # want.158 #159 173 # == Dynamic attribute-based finders 160 174 # 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>. 166 181 # 167 # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like168 # <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>. So instead of writing169 # <tt>Person.find(:first, ["user_name = ? AND password = ?", user_name, password])</tt>, you just do182 # 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 170 185 # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>. 171 186 # 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>. 175 191 # 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: 178 195 # 179 196 # # No 'Summer' tag exists 180 197 # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer") … … 207 224 # user = User.create(:preferences => { "background" => "black", "display" => large }) 208 225 # User.find(user.id).preferences # => { "background" => "black", "display" => large } 209 226 # 210 # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a211 # 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: 212 229 # 213 230 # class User < ActiveRecord::Base 214 231 # serialize :preferences, Hash … … 219 236 # 220 237 # == Single table inheritance 221 238 # 222 # Active Record allows inheritance by storing the name of the class in a column that by default is called "type" (can be changed223 # 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: 224 241 # 225 242 # class Company < ActiveRecord::Base; end 226 243 # class Firm < Company; end 227 244 # class Client < Company; end 228 245 # class PriorityClient < Client; end 229 246 # 230 # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then231 # 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. 232 249 # 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. 235 253 # 236 254 # Note, all the attributes for all the cases are kept in the same table. Read more: 237 255 # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html 238 256 # 239 257 # == Connection to multiple databases in different models 240 258 # 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. 245 264 # 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. 248 268 # 249 269 # == Exceptions 250 270 # … … 358 378 @@schema_format = :ruby 359 379 360 380 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]). 364 387 # If no record can be found for all of the listed ids, then RecordNotFound will be raised. 365 # * Findfirst: This will return the first record matched by the options used. These options can either be specific388 # * first: This will return the first record matched by the options used. These options can either be specific 366 389 # 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. 368 392 # 393 # === Options Hash 394 # 369 395 # All approaches accept an option hash as their last parameter. The options are: 370 396 # 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. 372 399 # * <tt>:order</tt>: An SQL fragment like "created_at DESC, name". 373 400 # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. 374 401 # * <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". 377 405 # The records will be returned read-only since they will have attributes that do not correspond to the table's columns. 378 406 # Pass :readonly => false to override. 379 407 # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer 380 408 # 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 not382 # 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 name384 # 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). 385 413 # * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated. 386 414 # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". 387 415 # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". 388 416 # 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 390 492 # Person.find(1) # returns the object for ID = 1 391 493 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) 392 494 # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) 393 495 # Person.find([1]) # returns an array for objects the object with ID = 1 394 496 # Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC") 395 497 # 396 # Note that returned records may not be in the same order as the ids you397 # provide since database rows are unordered. Give an explicit :order398 # to ensure the results are sorted.399 498 # 400 # Examples for find first:499 # # find first 401 500 # Person.find(:first) # returns the first object fetched by SELECT * FROM people 402 501 # Person.find(:first, :conditions => [ "user_name = ?", user_name]) 403 502 # Person.find(:first, :order => "created_on DESC", :offset => 5) 404 503 # 405 # Examples for find all:504 # # find all 406 505 # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people 407 506 # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) 408 507 # Person.find(:all, :offset => 10, :limit => 10) 409 508 # Person.find(:all, :include => [ :account, :friends ]) 410 509 # Person.find(:all, :group => "category") 411 510 # 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 # 422 512 def find(*args) 423 513 options = extract_options_from_args!(args) 424 514 validate_find_options(options) … … 451 541 false 452 542 end 453 543 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'}]) 456 555 def create(attributes = nil) 457 556 if attributes.is_a?(Array) 458 557 attributes.collect { |attr| create(attr) }