activerecord 1.10.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +187 -19
 - data/RUNNING_UNIT_TESTS +11 -0
 - data/lib/active_record.rb +3 -1
 - data/lib/active_record/acts/list.rb +25 -14
 - data/lib/active_record/acts/nested_set.rb +4 -4
 - data/lib/active_record/acts/tree.rb +18 -1
 - data/lib/active_record/associations.rb +90 -17
 - data/lib/active_record/associations/association_collection.rb +44 -5
 - data/lib/active_record/associations/has_and_belongs_to_many_association.rb +17 -4
 - data/lib/active_record/associations/has_many_association.rb +13 -3
 - data/lib/active_record/associations/has_one_association.rb +19 -0
 - data/lib/active_record/base.rb +292 -268
 - data/lib/active_record/callbacks.rb +14 -14
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +137 -75
 - data/lib/active_record/connection_adapters/db2_adapter.rb +10 -8
 - data/lib/active_record/connection_adapters/mysql_adapter.rb +91 -64
 - data/lib/active_record/connection_adapters/oci_adapter.rb +6 -6
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +113 -60
 - data/lib/active_record/connection_adapters/sqlite_adapter.rb +15 -12
 - data/lib/active_record/connection_adapters/sqlserver_adapter.rb +159 -132
 - data/lib/active_record/fixtures.rb +59 -12
 - data/lib/active_record/locking.rb +10 -9
 - data/lib/active_record/migration.rb +112 -5
 - data/lib/active_record/query_cache.rb +64 -0
 - data/lib/active_record/timestamp.rb +10 -8
 - data/lib/active_record/validations.rb +121 -26
 - data/rakefile +16 -10
 - data/test/aaa_create_tables_test.rb +26 -48
 - data/test/abstract_unit.rb +3 -0
 - data/test/aggregations_test.rb +19 -19
 - data/test/association_callbacks_test.rb +110 -0
 - data/test/associations_go_eager_test.rb +48 -14
 - data/test/associations_test.rb +344 -142
 - data/test/base_test.rb +150 -31
 - data/test/binary_test.rb +7 -0
 - data/test/callbacks_test.rb +24 -5
 - data/test/column_alias_test.rb +2 -2
 - data/test/connections/native_sqlserver_odbc/connection.rb +26 -0
 - data/test/deprecated_associations_test.rb +27 -28
 - data/test/deprecated_finder_test.rb +8 -9
 - data/test/finder_test.rb +52 -17
 - data/test/fixtures/author.rb +39 -0
 - data/test/fixtures/categories.yml +7 -0
 - data/test/fixtures/categories_posts.yml +8 -0
 - data/test/fixtures/category.rb +2 -0
 - data/test/fixtures/comment.rb +3 -1
 - data/test/fixtures/comments.yml +43 -1
 - data/test/fixtures/companies.yml +14 -0
 - data/test/fixtures/company.rb +1 -1
 - data/test/fixtures/computers.yml +2 -1
 - data/test/fixtures/db_definitions/db2.sql +7 -2
 - data/test/fixtures/db_definitions/mysql.drop.sql +2 -0
 - data/test/fixtures/db_definitions/mysql.sql +11 -6
 - data/test/fixtures/db_definitions/oci.sql +7 -2
 - data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
 - data/test/fixtures/db_definitions/postgresql.sql +8 -5
 - data/test/fixtures/db_definitions/sqlite.drop.sql +2 -0
 - data/test/fixtures/db_definitions/sqlite.sql +9 -4
 - data/test/fixtures/db_definitions/sqlserver.drop.sql +2 -0
 - data/test/fixtures/db_definitions/sqlserver.sql +12 -7
 - data/test/fixtures/developer.rb +8 -1
 - data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
 - data/test/fixtures/post.rb +8 -2
 - data/test/fixtures/posts.yml +21 -0
 - data/test/fixtures/project.rb +14 -1
 - data/test/fixtures/subscriber.rb +3 -0
 - data/test/fixtures_test.rb +14 -0
 - data/test/inheritance_test.rb +30 -22
 - data/test/lifecycle_test.rb +3 -4
 - data/test/locking_test.rb +2 -4
 - data/test/migration_test.rb +186 -0
 - data/test/mixin_nested_set_test.rb +19 -19
 - data/test/mixin_test.rb +88 -88
 - data/test/modules_test.rb +5 -10
 - data/test/multiple_db_test.rb +2 -0
 - data/test/pk_test.rb +8 -12
 - data/test/reflection_test.rb +8 -4
 - data/test/schema_test_postgresql.rb +63 -0
 - data/test/thread_safety_test.rb +4 -1
 - data/test/transactions_test.rb +9 -2
 - data/test/unconnected_test.rb +1 -0
 - data/test/validations_test.rb +151 -8
 - metadata +11 -5
 - data/test/migration_mysql.rb +0 -104
 
| 
         @@ -101,8 +101,8 @@ require 'csv' 
     | 
|
| 
       101 
101 
     | 
    
         
             
            #   ...
         
     | 
| 
       102 
102 
     | 
    
         
             
            #
         
     | 
| 
       103 
103 
     | 
    
         
             
            # By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here tho), we trigger
         
     | 
| 
       104 
     | 
    
         
            -
            # the testing environment to automatically load the appropriate fixtures into the database before each test 
     | 
| 
       105 
     | 
    
         
            -
            #  
     | 
| 
      
 104 
     | 
    
         
            +
            # the testing environment to automatically load the appropriate fixtures into the database before each test.  
         
     | 
| 
      
 105 
     | 
    
         
            +
            # To ensure consistent data, the environment deletes the fixtures before running the load.
         
     | 
| 
       106 
106 
     | 
    
         
             
            #
         
     | 
| 
       107 
107 
     | 
    
         
             
            # In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable
         
     | 
| 
       108 
108 
     | 
    
         
             
            # of the test case.  It is named after the symbol... so, in our example, there would be a hash available called
         
     | 
| 
         @@ -129,6 +129,16 @@ require 'csv' 
     | 
|
| 
       129 
129 
     | 
    
         
             
            #   - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
         
     | 
| 
       130 
130 
     | 
    
         
             
            #       self.use_instantiated_fixtures = :no_instances 
         
     | 
| 
       131 
131 
     | 
    
         
             
            #
         
     | 
| 
      
 132 
     | 
    
         
            +
            # Even if auto-instantiated fixtures are disabled, you can still access them
         
     | 
| 
      
 133 
     | 
    
         
            +
            # by name via special dynamic methods. Each method has the same name as the
         
     | 
| 
      
 134 
     | 
    
         
            +
            # model, and accepts the name of the fixture to instantiate:
         
     | 
| 
      
 135 
     | 
    
         
            +
            #
         
     | 
| 
      
 136 
     | 
    
         
            +
            #   fixtures :web_sites
         
     | 
| 
      
 137 
     | 
    
         
            +
            #
         
     | 
| 
      
 138 
     | 
    
         
            +
            #   def test_find
         
     | 
| 
      
 139 
     | 
    
         
            +
            #     assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
         
     | 
| 
      
 140 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 141 
     | 
    
         
            +
            #
         
     | 
| 
       132 
142 
     | 
    
         
             
            # = Dynamic fixtures with ERb
         
     | 
| 
       133 
143 
     | 
    
         
             
            #
         
     | 
| 
       134 
144 
     | 
    
         
             
            # Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
         
     | 
| 
         @@ -159,13 +169,13 @@ require 'csv' 
     | 
|
| 
       159 
169 
     | 
    
         
             
            #     fixtures :foos
         
     | 
| 
       160 
170 
     | 
    
         
             
            #   
         
     | 
| 
       161 
171 
     | 
    
         
             
            #     def test_godzilla
         
     | 
| 
       162 
     | 
    
         
            -
            #       assert !Foo. 
     | 
| 
      
 172 
     | 
    
         
            +
            #       assert !Foo.find(:all).empty?
         
     | 
| 
       163 
173 
     | 
    
         
             
            #       Foo.destroy_all
         
     | 
| 
       164 
     | 
    
         
            -
            #       assert Foo. 
     | 
| 
      
 174 
     | 
    
         
            +
            #       assert Foo.find(:all).empty?
         
     | 
| 
       165 
175 
     | 
    
         
             
            #     end
         
     | 
| 
       166 
176 
     | 
    
         
             
            #   
         
     | 
| 
       167 
177 
     | 
    
         
             
            #     def test_godzilla_aftermath
         
     | 
| 
       168 
     | 
    
         
            -
            #       assert !Foo. 
     | 
| 
      
 178 
     | 
    
         
            +
            #       assert !Foo.find(:all).empty?
         
     | 
| 
       169 
179 
     | 
    
         
             
            #     end
         
     | 
| 
       170 
180 
     | 
    
         
             
            #   end
         
     | 
| 
       171 
181 
     | 
    
         
             
            #   
         
     | 
| 
         @@ -278,7 +288,7 @@ class Fixtures < Hash 
     | 
|
| 
       278 
288 
     | 
    
         
             
                      yaml = YAML::load(erb_render(IO.read(yaml_file_path)))
         
     | 
| 
       279 
289 
     | 
    
         
             
                      yaml.each { |name, data| self[name] = Fixture.new(data, @class_name) } if yaml
         
     | 
| 
       280 
290 
     | 
    
         
             
                    rescue Exception=>boom
         
     | 
| 
       281 
     | 
    
         
            -
                      raise Fixture::FormatError, "a YAML error occured parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html"
         
     | 
| 
      
 291 
     | 
    
         
            +
                      raise Fixture::FormatError, "a YAML error occured parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n  #{boom.class}: #{boom}"
         
     | 
| 
       282 
292 
     | 
    
         
             
                    end
         
     | 
| 
       283 
293 
     | 
    
         
             
                  elsif File.file?(csv_file_path)
         
     | 
| 
       284 
294 
     | 
    
         
             
                    # CSV fixtures
         
     | 
| 
         @@ -400,9 +410,13 @@ module Test #:nodoc: 
     | 
|
| 
       400 
410 
     | 
    
         
             
                  self.use_instantiated_fixtures = true
         
     | 
| 
       401 
411 
     | 
    
         
             
                  self.pre_loaded_fixtures = false
         
     | 
| 
       402 
412 
     | 
    
         | 
| 
      
 413 
     | 
    
         
            +
                  @@already_loaded_fixtures = {}
         
     | 
| 
      
 414 
     | 
    
         
            +
             
     | 
| 
       403 
415 
     | 
    
         
             
                  def self.fixtures(*table_names)
         
     | 
| 
       404 
     | 
    
         
            -
                     
     | 
| 
       405 
     | 
    
         
            -
                     
     | 
| 
      
 416 
     | 
    
         
            +
                    table_names = table_names.flatten
         
     | 
| 
      
 417 
     | 
    
         
            +
                    self.fixture_table_names |= table_names
         
     | 
| 
      
 418 
     | 
    
         
            +
                    require_fixture_classes(table_names)
         
     | 
| 
      
 419 
     | 
    
         
            +
                    setup_fixture_accessors(table_names)
         
     | 
| 
       406 
420 
     | 
    
         
             
                  end
         
     | 
| 
       407 
421 
     | 
    
         | 
| 
       408 
422 
     | 
    
         
             
                  def self.require_fixture_classes(table_names=nil)
         
     | 
| 
         @@ -415,20 +429,53 @@ module Test #:nodoc: 
     | 
|
| 
       415 
429 
     | 
    
         
             
                    end
         
     | 
| 
       416 
430 
     | 
    
         
             
                  end
         
     | 
| 
       417 
431 
     | 
    
         | 
| 
      
 432 
     | 
    
         
            +
                  def self.setup_fixture_accessors(table_names=nil)
         
     | 
| 
      
 433 
     | 
    
         
            +
                    (table_names || fixture_table_names).each do |table_name|
         
     | 
| 
      
 434 
     | 
    
         
            +
                      table_name = table_name.to_s.tr('.','_')
         
     | 
| 
      
 435 
     | 
    
         
            +
                      define_method(table_name) do |fixture, *optionals|
         
     | 
| 
      
 436 
     | 
    
         
            +
                        force_reload = optionals.shift
         
     | 
| 
      
 437 
     | 
    
         
            +
                        @fixture_cache[table_name] ||= Hash.new
         
     | 
| 
      
 438 
     | 
    
         
            +
                        @fixture_cache[table_name][fixture] = nil if force_reload
         
     | 
| 
      
 439 
     | 
    
         
            +
                        @fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
         
     | 
| 
      
 440 
     | 
    
         
            +
                      end
         
     | 
| 
      
 441 
     | 
    
         
            +
                    end
         
     | 
| 
      
 442 
     | 
    
         
            +
                  end
         
     | 
| 
      
 443 
     | 
    
         
            +
             
     | 
| 
      
 444 
     | 
    
         
            +
                  def self.uses_transaction(*methods)
         
     | 
| 
      
 445 
     | 
    
         
            +
                    @uses_transaction ||= []
         
     | 
| 
      
 446 
     | 
    
         
            +
                    @uses_transaction.concat methods.map { |m| m.to_s }
         
     | 
| 
      
 447 
     | 
    
         
            +
                  end
         
     | 
| 
      
 448 
     | 
    
         
            +
             
     | 
| 
      
 449 
     | 
    
         
            +
                  def self.uses_transaction?(method)
         
     | 
| 
      
 450 
     | 
    
         
            +
                    @uses_transaction && @uses_transaction.include?(method.to_s)
         
     | 
| 
      
 451 
     | 
    
         
            +
                  end
         
     | 
| 
      
 452 
     | 
    
         
            +
             
     | 
| 
      
 453 
     | 
    
         
            +
                  def use_transactional_fixtures?
         
     | 
| 
      
 454 
     | 
    
         
            +
                    use_transactional_fixtures &&
         
     | 
| 
      
 455 
     | 
    
         
            +
                      !self.class.uses_transaction?(method_name)
         
     | 
| 
      
 456 
     | 
    
         
            +
                  end
         
     | 
| 
      
 457 
     | 
    
         
            +
             
     | 
| 
       418 
458 
     | 
    
         
             
                  def setup_with_fixtures
         
     | 
| 
       419 
459 
     | 
    
         
             
                    if pre_loaded_fixtures && !use_transactional_fixtures
         
     | 
| 
       420 
460 
     | 
    
         
             
                      raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures' 
         
     | 
| 
       421 
461 
     | 
    
         
             
                    end
         
     | 
| 
       422 
462 
     | 
    
         | 
| 
      
 463 
     | 
    
         
            +
                    @fixture_cache = Hash.new
         
     | 
| 
      
 464 
     | 
    
         
            +
             
     | 
| 
       423 
465 
     | 
    
         
             
                    # Load fixtures once and begin transaction.
         
     | 
| 
       424 
     | 
    
         
            -
                    if use_transactional_fixtures
         
     | 
| 
       425 
     | 
    
         
            -
                       
     | 
| 
       426 
     | 
    
         
            -
             
     | 
| 
      
 466 
     | 
    
         
            +
                    if use_transactional_fixtures?
         
     | 
| 
      
 467 
     | 
    
         
            +
                      if @@already_loaded_fixtures[self.class]
         
     | 
| 
      
 468 
     | 
    
         
            +
                        @loaded_fixtures = @@already_loaded_fixtures[self.class]
         
     | 
| 
      
 469 
     | 
    
         
            +
                      else
         
     | 
| 
      
 470 
     | 
    
         
            +
                        load_fixtures
         
     | 
| 
      
 471 
     | 
    
         
            +
                        @@already_loaded_fixtures[self.class] = @loaded_fixtures
         
     | 
| 
      
 472 
     | 
    
         
            +
                      end
         
     | 
| 
       427 
473 
     | 
    
         
             
                      ActiveRecord::Base.lock_mutex
         
     | 
| 
       428 
474 
     | 
    
         
             
                      ActiveRecord::Base.connection.begin_db_transaction
         
     | 
| 
       429 
475 
     | 
    
         | 
| 
       430 
476 
     | 
    
         
             
                    # Load fixtures for every test.
         
     | 
| 
       431 
477 
     | 
    
         
             
                    else
         
     | 
| 
      
 478 
     | 
    
         
            +
                      @@already_loaded_fixtures[self.class] = nil
         
     | 
| 
       432 
479 
     | 
    
         
             
                      load_fixtures
         
     | 
| 
       433 
480 
     | 
    
         
             
                    end
         
     | 
| 
       434 
481 
     | 
    
         | 
| 
         @@ -440,7 +487,7 @@ module Test #:nodoc: 
     | 
|
| 
       440 
487 
     | 
    
         | 
| 
       441 
488 
     | 
    
         
             
                  def teardown_with_fixtures
         
     | 
| 
       442 
489 
     | 
    
         
             
                    # Rollback changes.
         
     | 
| 
       443 
     | 
    
         
            -
                    if use_transactional_fixtures
         
     | 
| 
      
 490 
     | 
    
         
            +
                    if use_transactional_fixtures?
         
     | 
| 
       444 
491 
     | 
    
         
             
                      ActiveRecord::Base.connection.rollback_db_transaction
         
     | 
| 
       445 
492 
     | 
    
         
             
                      ActiveRecord::Base.unlock_mutex
         
     | 
| 
       446 
493 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -32,14 +32,15 @@ module ActiveRecord 
     | 
|
| 
       32 
32 
     | 
    
         
             
                    previous_value    = self.lock_version
         
     | 
| 
       33 
33 
     | 
    
         
             
                    self.lock_version = previous_value + 1
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                    affected_rows = connection.update(
         
     | 
| 
       36 
     | 
    
         
            -
                       
     | 
| 
       37 
     | 
    
         
            -
                       
     | 
| 
       38 
     | 
    
         
            -
                       
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                    
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
                    affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking")
         
     | 
| 
      
 36 
     | 
    
         
            +
                      UPDATE #{self.class.table_name}
         
     | 
| 
      
 37 
     | 
    
         
            +
                      SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))}
         
     | 
| 
      
 38 
     | 
    
         
            +
                      WHERE #{self.class.primary_key} = #{quote(id)} AND lock_version = #{quote(previous_value)}
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end_sql
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    unless affected_rows == 1
         
     | 
| 
      
 42 
     | 
    
         
            +
                      raise ActiveRecord::StaleObjectError, "Attempted to update a stale object"
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
       43 
44 
     | 
    
         
             
                  else
         
     | 
| 
       44 
45 
     | 
    
         
             
                    update_without_lock
         
     | 
| 
       45 
46 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -54,4 +55,4 @@ module ActiveRecord 
     | 
|
| 
       54 
55 
     | 
    
         
             
                  lock_optimistically && respond_to?(:lock_version)
         
     | 
| 
       55 
56 
     | 
    
         
             
                end
         
     | 
| 
       56 
57 
     | 
    
         
             
              end
         
     | 
| 
       57 
     | 
    
         
            -
            end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,7 +2,113 @@ module ActiveRecord 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class IrreversibleMigration < ActiveRecordError#:nodoc:
         
     | 
| 
       3 
3 
     | 
    
         
             
              end
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
      
 5 
     | 
    
         
            +
              # Migrations can manage the evolution of a schema used by several physical databases. It's a solution
         
     | 
| 
      
 6 
     | 
    
         
            +
              # to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to
         
     | 
| 
      
 7 
     | 
    
         
            +
              # push that change to other developers and to the production server. With migrations, you can describe the transformations
         
     | 
| 
      
 8 
     | 
    
         
            +
              # in self-contained classes that can be checked into version control systems and executed against another database that
         
     | 
| 
      
 9 
     | 
    
         
            +
              # might be one, two, or five versions behind.
         
     | 
| 
      
 10 
     | 
    
         
            +
              #
         
     | 
| 
      
 11 
     | 
    
         
            +
              # Example of a simple migration:
         
     | 
| 
      
 12 
     | 
    
         
            +
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   class AddSsl < ActiveRecord::Migration
         
     | 
| 
      
 14 
     | 
    
         
            +
              #     def self.up
         
     | 
| 
      
 15 
     | 
    
         
            +
              #       add_column :accounts, :ssl_enabled, :boolean, :default => 1
         
     | 
| 
      
 16 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 17 
     | 
    
         
            +
              #   
         
     | 
| 
      
 18 
     | 
    
         
            +
              #     def self.down
         
     | 
| 
      
 19 
     | 
    
         
            +
              #       remove_column :accounts, :ssl_enabled
         
     | 
| 
      
 20 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 21 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 22 
     | 
    
         
            +
              #
         
     | 
| 
      
 23 
     | 
    
         
            +
              # This migration will add a boolean flag to the accounts table and remove it again, if you're backing out of the migration.
         
     | 
| 
      
 24 
     | 
    
         
            +
              # It shows how all migrations have two class methods +up+ and +down+ that describes the transformations required to implement
         
     | 
| 
      
 25 
     | 
    
         
            +
              # or remove the migration. These methods can consist of both the migration specific methods, like add_column and remove_column, 
         
     | 
| 
      
 26 
     | 
    
         
            +
              # but may also contain regular Ruby code for generating data needed for the transformations.
         
     | 
| 
      
 27 
     | 
    
         
            +
              #
         
     | 
| 
      
 28 
     | 
    
         
            +
              # Example of a more complex migration that also needs to initialize data:
         
     | 
| 
      
 29 
     | 
    
         
            +
              #
         
     | 
| 
      
 30 
     | 
    
         
            +
              #   class AddSystemSettings < ActiveRecord::Migration
         
     | 
| 
      
 31 
     | 
    
         
            +
              #     def self.up
         
     | 
| 
      
 32 
     | 
    
         
            +
              #       create_table :system_settings do |t|
         
     | 
| 
      
 33 
     | 
    
         
            +
              #         t.column :name,     :string
         
     | 
| 
      
 34 
     | 
    
         
            +
              #         t.column :label,    :string
         
     | 
| 
      
 35 
     | 
    
         
            +
              #         t.column :value,    :text
         
     | 
| 
      
 36 
     | 
    
         
            +
              #         t.column :type,     :string
         
     | 
| 
      
 37 
     | 
    
         
            +
              #         t.column :position, :integer
         
     | 
| 
      
 38 
     | 
    
         
            +
              #       end
         
     | 
| 
      
 39 
     | 
    
         
            +
              #   
         
     | 
| 
      
 40 
     | 
    
         
            +
              #       SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
         
     | 
| 
      
 41 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 42 
     | 
    
         
            +
              #   
         
     | 
| 
      
 43 
     | 
    
         
            +
              #     def self.down
         
     | 
| 
      
 44 
     | 
    
         
            +
              #       drop_table :system_settings
         
     | 
| 
      
 45 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 46 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 47 
     | 
    
         
            +
              #
         
     | 
| 
      
 48 
     | 
    
         
            +
              # This migration first adds the system_settings table, then creates the very first row in it using the Active Record model
         
     | 
| 
      
 49 
     | 
    
         
            +
              # that relies on the table. It also uses the more advanced create_table syntax where you can specify a complete table schema
         
     | 
| 
      
 50 
     | 
    
         
            +
              # in one block call.
         
     | 
| 
      
 51 
     | 
    
         
            +
              #
         
     | 
| 
      
 52 
     | 
    
         
            +
              # == Available transformations
         
     | 
| 
      
 53 
     | 
    
         
            +
              #
         
     | 
| 
      
 54 
     | 
    
         
            +
              # * <tt>create_table(name, options)</tt> Creates a table called +name+ and makes the table object available to a block
         
     | 
| 
      
 55 
     | 
    
         
            +
              #   that can then add columns to it, following the same format as add_column. See example above. The options hash is for
         
     | 
| 
      
 56 
     | 
    
         
            +
              #   fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create table definition.
         
     | 
| 
      
 57 
     | 
    
         
            +
              # * <tt>drop_table(name)</tt>: Drops the table called +name+.
         
     | 
| 
      
 58 
     | 
    
         
            +
              # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column to the table called +table_name+
         
     | 
| 
      
 59 
     | 
    
         
            +
              #   named +column_name+ specified to be one of the following types:
         
     | 
| 
      
 60 
     | 
    
         
            +
              #   :string, :text, :integer, :float, :datetime, :timestamp, :time, :date, :binary, :boolean. A default value can be specified
         
     | 
| 
      
 61 
     | 
    
         
            +
              #   by passing an +options+ hash like { :default => 11 }.
         
     | 
| 
      
 62 
     | 
    
         
            +
              # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames a column but keeps the type and content.
         
     | 
| 
      
 63 
     | 
    
         
            +
              # * <tt>change_column(table_name, column_name, type, options)</tt>:  Changes the column to a different type using the same
         
     | 
| 
      
 64 
     | 
    
         
            +
              #   parameters as add_column.
         
     | 
| 
      
 65 
     | 
    
         
            +
              # * <tt>remove_column(table_name, column_name)</tt>: Removes the column named +column_name+ from the table called +table_name+.
         
     | 
| 
      
 66 
     | 
    
         
            +
              # * <tt>add_index(table_name, column_name)</tt>: Add a new index with the name of the column on the column.
         
     | 
| 
      
 67 
     | 
    
         
            +
              # * <tt>remove_index(table_name, column_name)</tt>: Remove the index called the same as the column.
         
     | 
| 
      
 68 
     | 
    
         
            +
              #
         
     | 
| 
      
 69 
     | 
    
         
            +
              # == Irreversible transformations
         
     | 
| 
      
 70 
     | 
    
         
            +
              #
         
     | 
| 
      
 71 
     | 
    
         
            +
              # Some transformations are destructive in a manner that cannot be reversed. Migrations of that kind should raise
         
     | 
| 
      
 72 
     | 
    
         
            +
              # an <tt>IrreversibleMigration</tt> exception in their +down+ method.
         
     | 
| 
      
 73 
     | 
    
         
            +
              #
         
     | 
| 
      
 74 
     | 
    
         
            +
              # == Running migrations from within Rails
         
     | 
| 
      
 75 
     | 
    
         
            +
              #
         
     | 
| 
      
 76 
     | 
    
         
            +
              # The Rails package has support for migrations with the <tt>script/generate migration my_new_migration</tt> command and
         
     | 
| 
      
 77 
     | 
    
         
            +
              # with the <tt>rake migrate</tt> command that'll run all the pending migrations. It'll even create the needed schema_info
         
     | 
| 
      
 78 
     | 
    
         
            +
              # table automatically if it's missing.
         
     | 
| 
      
 79 
     | 
    
         
            +
              #
         
     | 
| 
      
 80 
     | 
    
         
            +
              # == Database support
         
     | 
| 
      
 81 
     | 
    
         
            +
              #
         
     | 
| 
      
 82 
     | 
    
         
            +
              # Migrations are currently only supported in MySQL and PostgreSQL.
         
     | 
| 
      
 83 
     | 
    
         
            +
              #
         
     | 
| 
      
 84 
     | 
    
         
            +
              # == More examples
         
     | 
| 
      
 85 
     | 
    
         
            +
              #
         
     | 
| 
      
 86 
     | 
    
         
            +
              # Not all migrations change the schema. Some just fix the data:
         
     | 
| 
      
 87 
     | 
    
         
            +
              #
         
     | 
| 
      
 88 
     | 
    
         
            +
              #   class RemoveEmptyTags < ActiveRecord::Migration
         
     | 
| 
      
 89 
     | 
    
         
            +
              #     def self.up
         
     | 
| 
      
 90 
     | 
    
         
            +
              #       Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }
         
     | 
| 
      
 91 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 92 
     | 
    
         
            +
              #   
         
     | 
| 
      
 93 
     | 
    
         
            +
              #     def self.down
         
     | 
| 
      
 94 
     | 
    
         
            +
              #       # not much we can do to restore deleted data
         
     | 
| 
      
 95 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 96 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 97 
     | 
    
         
            +
              #
         
     | 
| 
      
 98 
     | 
    
         
            +
              # Others remove columns when they migrate up instead of down:
         
     | 
| 
      
 99 
     | 
    
         
            +
              #
         
     | 
| 
      
 100 
     | 
    
         
            +
              #   class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
         
     | 
| 
      
 101 
     | 
    
         
            +
              #     def self.up
         
     | 
| 
      
 102 
     | 
    
         
            +
              #       remove_column :items, :incomplete_items_count
         
     | 
| 
      
 103 
     | 
    
         
            +
              #       remove_column :items, :completed_items_count
         
     | 
| 
      
 104 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 105 
     | 
    
         
            +
              #
         
     | 
| 
      
 106 
     | 
    
         
            +
              #     def self.down
         
     | 
| 
      
 107 
     | 
    
         
            +
              #       add_column :items, :incomplete_items_count
         
     | 
| 
      
 108 
     | 
    
         
            +
              #       add_column :items, :completed_items_count
         
     | 
| 
      
 109 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 110 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 111 
     | 
    
         
            +
              class Migration
         
     | 
| 
       6 
112 
     | 
    
         
             
                class << self
         
     | 
| 
       7 
113 
     | 
    
         
             
                  def up() end
         
     | 
| 
       8 
114 
     | 
    
         
             
                  def down() end
         
     | 
| 
         @@ -17,11 +123,11 @@ module ActiveRecord 
     | 
|
| 
       17 
123 
     | 
    
         
             
              class Migrator#:nodoc:
         
     | 
| 
       18 
124 
     | 
    
         
             
                class << self
         
     | 
| 
       19 
125 
     | 
    
         
             
                  def up(migrations_path, target_version = nil)
         
     | 
| 
       20 
     | 
    
         
            -
                    new(:up, migrations_path, target_version).migrate
         
     | 
| 
      
 126 
     | 
    
         
            +
                    self.new(:up, migrations_path, target_version).migrate
         
     | 
| 
       21 
127 
     | 
    
         
             
                  end
         
     | 
| 
       22 
128 
     | 
    
         | 
| 
       23 
129 
     | 
    
         
             
                  def down(migrations_path, target_version = nil)
         
     | 
| 
       24 
     | 
    
         
            -
                    new(:down, migrations_path, target_version).migrate
         
     | 
| 
      
 130 
     | 
    
         
            +
                    self.new(:down, migrations_path, target_version).migrate
         
     | 
| 
       25 
131 
     | 
    
         
             
                  end
         
     | 
| 
       26 
132 
     | 
    
         | 
| 
       27 
133 
     | 
    
         
             
                  def current_version
         
     | 
| 
         @@ -30,6 +136,7 @@ module ActiveRecord 
     | 
|
| 
       30 
136 
     | 
    
         
             
                end
         
     | 
| 
       31 
137 
     | 
    
         | 
| 
       32 
138 
     | 
    
         
             
                def initialize(direction, migrations_path, target_version = nil)
         
     | 
| 
      
 139 
     | 
    
         
            +
                  raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
         
     | 
| 
       33 
140 
     | 
    
         
             
                  @direction, @migrations_path, @target_version = direction, migrations_path, target_version
         
     | 
| 
       34 
141 
     | 
    
         
             
                  Base.connection.initialize_schema_information
         
     | 
| 
       35 
142 
     | 
    
         
             
                end
         
     | 
| 
         @@ -59,7 +166,7 @@ module ActiveRecord 
     | 
|
| 
       59 
166 
     | 
    
         
             
                  end
         
     | 
| 
       60 
167 
     | 
    
         | 
| 
       61 
168 
     | 
    
         
             
                  def migration_files
         
     | 
| 
       62 
     | 
    
         
            -
                    files = Dir["#{@migrations_path}/[0-9]*_*.rb"]
         
     | 
| 
      
 169 
     | 
    
         
            +
                    files = Dir["#{@migrations_path}/[0-9]*_*.rb"].sort
         
     | 
| 
       63 
170 
     | 
    
         
             
                    down? ? files.reverse : files
         
     | 
| 
       64 
171 
     | 
    
         
             
                  end
         
     | 
| 
       65 
172 
     | 
    
         | 
| 
         @@ -91,4 +198,4 @@ module ActiveRecord 
     | 
|
| 
       91 
198 
     | 
    
         
             
                    (up? && version.to_i <= current_version) || (down? && version.to_i > current_version)
         
     | 
| 
       92 
199 
     | 
    
         
             
                  end
         
     | 
| 
       93 
200 
     | 
    
         
             
              end
         
     | 
| 
       94 
     | 
    
         
            -
            end
         
     | 
| 
      
 201 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,64 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 2 
     | 
    
         
            +
              class QueryCache #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(connection)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @connection = connection
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @query_cache = {}
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def clear_query_cache
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @query_cache = {}
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def select_all(sql, name = nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @query_cache[sql] ||= @connection.select_all(sql, name)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def select_one(sql, name = nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @query_cache[sql] ||= @connection.select_one(sql, name)
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def columns(table_name, name = nil)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @query_cache["SHOW FIELDS FROM #{table_name}"] ||= @connection.columns(table_name, name)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def insert(sql, name = nil, pk = nil, id_value = nil)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  clear_query_cache
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @connection.insert(sql, name, pk, id_value)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def update(sql, name = nil)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  clear_query_cache
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @connection.update(sql, name)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def delete(sql, name = nil)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  clear_query_cache
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @connection.delete(sql, name)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                private
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def method_missing(method, *arguments)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @connection.send(method, *arguments)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
              
         
     | 
| 
      
 45 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 46 
     | 
    
         
            +
                # Set the connection for the class with caching on
         
     | 
| 
      
 47 
     | 
    
         
            +
                def self.connection=(spec)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  raise ConnectionNotEstablished unless spec
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  conn = spec.config[:query_cache] ?
         
     | 
| 
      
 51 
     | 
    
         
            +
                    QueryCache.new(self.send(spec.adapter_method, spec.config)) :
         
     | 
| 
      
 52 
     | 
    
         
            +
                    self.send(spec.adapter_method, spec.config)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  
         
     | 
| 
      
 54 
     | 
    
         
            +
                  Thread.current['active_connections'] ||= {}
         
     | 
| 
      
 55 
     | 
    
         
            +
                  Thread.current['active_connections'][self] = conn
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
              
         
     | 
| 
      
 59 
     | 
    
         
            +
              class AbstractAdapter #:nodoc:
         
     | 
| 
      
 60 
     | 
    
         
            +
                # Stub method to be able to treat the connection the same whether the query cache has been turned on or not
         
     | 
| 
      
 61 
     | 
    
         
            +
                def clear_query_cache
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -19,21 +19,23 @@ module ActiveRecord 
     | 
|
| 
       19 
19 
     | 
    
         
             
                end    
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                def create_with_timestamps #:nodoc:
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if record_timestamps
         
     | 
| 
       22 
23 
     | 
    
         
             
                  t = ( self.class.default_timezone == :utc ? Time.now.utc : Time.now )
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                  write_attribute("updated_at", t) if record_timestamps && respond_to?(:updated_at)
         
     | 
| 
       27 
     | 
    
         
            -
                  write_attribute("updated_on", t) if record_timestamps && respond_to?(:updated_on)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    write_attribute('created_at', t) if respond_to?(:created_at) && created_at.nil?
         
     | 
| 
      
 25 
     | 
    
         
            +
                    write_attribute('created_on', t) if respond_to?(:created_on) && created_on.nil?
         
     | 
| 
       28 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
                    write_attribute('updated_at', t) if respond_to?(:updated_at)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    write_attribute('updated_on', t) if respond_to?(:updated_on)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
       29 
30 
     | 
    
         
             
                  create_without_timestamps
         
     | 
| 
       30 
31 
     | 
    
         
             
                end
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
       32 
33 
     | 
    
         
             
                def update_with_timestamps #:nodoc:
         
     | 
| 
      
 34 
     | 
    
         
            +
                  if record_timestamps
         
     | 
| 
       33 
35 
     | 
    
         
             
                  t = ( self.class.default_timezone == :utc ? Time.now.utc : Time.now )
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
                    write_attribute('updated_at', t) if respond_to?(:updated_at)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    write_attribute('updated_on', t) if respond_to?(:updated_on)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
       37 
39 
     | 
    
         
             
                  update_without_timestamps
         
     | 
| 
       38 
40 
     | 
    
         
             
                end
         
     | 
| 
       39 
41 
     | 
    
         
             
              end 
         
     | 
| 
         @@ -11,10 +11,12 @@ module ActiveRecord 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                @@default_error_messages = {
         
     | 
| 
       13 
13 
     | 
    
         
             
                  :inclusion => "is not included in the list",
         
     | 
| 
      
 14 
     | 
    
         
            +
                  :exclusion => "is reserved",
         
     | 
| 
       14 
15 
     | 
    
         
             
                  :invalid => "is invalid",
         
     | 
| 
       15 
16 
     | 
    
         
             
                  :confirmation => "doesn't match confirmation",
         
     | 
| 
       16 
17 
     | 
    
         
             
                  :accepted  => "must be accepted",
         
     | 
| 
       17 
18 
     | 
    
         
             
                  :empty => "can't be empty",
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :blank => "can't be blank",
         
     | 
| 
       18 
20 
     | 
    
         
             
                  :too_long => "is too long (max is %d characters)", 
         
     | 
| 
       19 
21 
     | 
    
         
             
                  :too_short => "is too short (min is %d characters)", 
         
     | 
| 
       20 
22 
     | 
    
         
             
                  :wrong_length => "is the wrong length (should be %d characters)", 
         
     | 
| 
         @@ -43,7 +45,7 @@ module ActiveRecord 
     | 
|
| 
       43 
45 
     | 
    
         
             
                  @errors[attribute.to_s] << msg
         
     | 
| 
       44 
46 
     | 
    
         
             
                end
         
     | 
| 
       45 
47 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                # Will add an error message to each of the attributes in +attributes+ that is empty 
     | 
| 
      
 48 
     | 
    
         
            +
                # Will add an error message to each of the attributes in +attributes+ that is empty.
         
     | 
| 
       47 
49 
     | 
    
         
             
                def add_on_empty(attributes, msg = @@default_error_messages[:empty])
         
     | 
| 
       48 
50 
     | 
    
         
             
                  for attr in [attributes].flatten
         
     | 
| 
       49 
51 
     | 
    
         
             
                    value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
         
     | 
| 
         @@ -51,6 +53,14 @@ module ActiveRecord 
     | 
|
| 
       51 
53 
     | 
    
         
             
                    add(attr, msg) unless !value.nil? && !is_empty
         
     | 
| 
       52 
54 
     | 
    
         
             
                  end
         
     | 
| 
       53 
55 
     | 
    
         
             
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
                # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?).
         
     | 
| 
      
 58 
     | 
    
         
            +
                def add_on_blank(attributes, msg = @@default_error_messages[:blank])
         
     | 
| 
      
 59 
     | 
    
         
            +
                  for attr in [attributes].flatten
         
     | 
| 
      
 60 
     | 
    
         
            +
                    value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
         
     | 
| 
      
 61 
     | 
    
         
            +
                    add(attr, msg) if value.blank?
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
       54 
64 
     | 
    
         | 
| 
       55 
65 
     | 
    
         
             
                # Will add an error message to each of the attributes in +attributes+ that has a length outside of the passed boundary +range+. 
         
     | 
| 
       56 
66 
     | 
    
         
             
                # If the length is above the boundary, the too_long_msg message will be used. If below, the too_short_msg.
         
     | 
| 
         @@ -203,12 +213,6 @@ module ActiveRecord 
     | 
|
| 
       203 
213 
     | 
    
         
             
                    :message => nil
         
     | 
| 
       204 
214 
     | 
    
         
             
                  }.freeze
         
     | 
| 
       205 
215 
     | 
    
         | 
| 
       206 
     | 
    
         
            -
                  DEFAULT_SIZE_VALIDATION_OPTIONS = DEFAULT_VALIDATION_OPTIONS.merge(
         
     | 
| 
       207 
     | 
    
         
            -
                    :too_long => ActiveRecord::Errors.default_error_messages[:too_long],
         
     | 
| 
       208 
     | 
    
         
            -
                    :too_short => ActiveRecord::Errors.default_error_messages[:too_short],
         
     | 
| 
       209 
     | 
    
         
            -
                    :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
         
     | 
| 
       210 
     | 
    
         
            -
                  ).freeze
         
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
216 
     | 
    
         
             
                  ALL_RANGE_OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
         
     | 
| 
       213 
217 
     | 
    
         | 
| 
       214 
218 
     | 
    
         
             
                  def validate(*methods, &block)
         
     | 
| 
         @@ -226,6 +230,29 @@ module ActiveRecord 
     | 
|
| 
       226 
230 
     | 
    
         
             
                    write_inheritable_set(:validate_on_update, methods)
         
     | 
| 
       227 
231 
     | 
    
         
             
                  end
         
     | 
| 
       228 
232 
     | 
    
         | 
| 
      
 233 
     | 
    
         
            +
                  def condition_block?(condition)
         
     | 
| 
      
 234 
     | 
    
         
            +
                    condition.respond_to?("call") && (condition.arity == 1 || condition.arity == -1)
         
     | 
| 
      
 235 
     | 
    
         
            +
                  end
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  # Determine from the given condition (whether a block, procedure, method or string)
         
     | 
| 
      
 238 
     | 
    
         
            +
                  # whether or not to validate the record.  See #validates_each.
         
     | 
| 
      
 239 
     | 
    
         
            +
                  def evaluate_condition(condition, record)
         
     | 
| 
      
 240 
     | 
    
         
            +
                    case condition
         
     | 
| 
      
 241 
     | 
    
         
            +
                      when Symbol: record.send(condition)
         
     | 
| 
      
 242 
     | 
    
         
            +
                      when String: eval(condition, binding)
         
     | 
| 
      
 243 
     | 
    
         
            +
                      else
         
     | 
| 
      
 244 
     | 
    
         
            +
                        if condition_block?(condition)
         
     | 
| 
      
 245 
     | 
    
         
            +
                          condition.call(record)
         
     | 
| 
      
 246 
     | 
    
         
            +
                        else
         
     | 
| 
      
 247 
     | 
    
         
            +
                          raise(
         
     | 
| 
      
 248 
     | 
    
         
            +
                            ActiveRecordError,
         
     | 
| 
      
 249 
     | 
    
         
            +
                            "Validations need to be either a symbol, string (to be eval'ed), proc/method, or " +
         
     | 
| 
      
 250 
     | 
    
         
            +
                            "class implementing a static validation method"
         
     | 
| 
      
 251 
     | 
    
         
            +
                          )
         
     | 
| 
      
 252 
     | 
    
         
            +
                        end
         
     | 
| 
      
 253 
     | 
    
         
            +
                      end
         
     | 
| 
      
 254 
     | 
    
         
            +
                  end
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
       229 
256 
     | 
    
         
             
                  # Validates each attribute against a block.
         
     | 
| 
       230 
257 
     | 
    
         
             
                  #
         
     | 
| 
       231 
258 
     | 
    
         
             
                  #   class Person < ActiveRecord::Base
         
     | 
| 
         @@ -237,16 +264,22 @@ module ActiveRecord 
     | 
|
| 
       237 
264 
     | 
    
         
             
                  # Options:
         
     | 
| 
       238 
265 
     | 
    
         
             
                  # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
       239 
266 
     | 
    
         
             
                  # * <tt>allow_nil</tt> - Skip validation if attribute is nil.
         
     | 
| 
      
 267 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 268 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 269 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       240 
270 
     | 
    
         
             
                  def validates_each(*attrs)
         
     | 
| 
       241 
271 
     | 
    
         
             
                    options = attrs.last.is_a?(Hash) ? attrs.pop.symbolize_keys : {}
         
     | 
| 
       242 
272 
     | 
    
         
             
                    attrs = attrs.flatten
         
     | 
| 
       243 
273 
     | 
    
         | 
| 
       244 
274 
     | 
    
         
             
                    # Declare the validation.
         
     | 
| 
       245 
275 
     | 
    
         
             
                    send(validation_method(options[:on] || :save)) do |record|
         
     | 
| 
       246 
     | 
    
         
            -
                       
     | 
| 
       247 
     | 
    
         
            -
             
     | 
| 
       248 
     | 
    
         
            -
                         
     | 
| 
       249 
     | 
    
         
            -
             
     | 
| 
      
 276 
     | 
    
         
            +
                      # Don't validate when there is an :if condition and that condition is false
         
     | 
| 
      
 277 
     | 
    
         
            +
                      unless options[:if] && !evaluate_condition(options[:if], record)
         
     | 
| 
      
 278 
     | 
    
         
            +
                        attrs.each do |attr|
         
     | 
| 
      
 279 
     | 
    
         
            +
                          value = record.send(attr)
         
     | 
| 
      
 280 
     | 
    
         
            +
                          next if value.nil? && options[:allow_nil]
         
     | 
| 
      
 281 
     | 
    
         
            +
                          yield record, attr, value
         
     | 
| 
      
 282 
     | 
    
         
            +
                        end
         
     | 
| 
       250 
283 
     | 
    
         
             
                      end
         
     | 
| 
       251 
284 
     | 
    
         
             
                    end
         
     | 
| 
       252 
285 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -270,6 +303,9 @@ module ActiveRecord 
     | 
|
| 
       270 
303 
     | 
    
         
             
                  # Configuration options:
         
     | 
| 
       271 
304 
     | 
    
         
             
                  # * <tt>message</tt> - A custom error message (default is: "doesn't match confirmation")
         
     | 
| 
       272 
305 
     | 
    
         
             
                  # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
      
 306 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 307 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 308 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       273 
309 
     | 
    
         
             
                  def validates_confirmation_of(*attr_names)
         
     | 
| 
       274 
310 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }
         
     | 
| 
       275 
311 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
         @@ -292,12 +328,13 @@ module ActiveRecord 
     | 
|
| 
       292 
328 
     | 
    
         
             
                  # terms_of_service is not nil and by default on save.
         
     | 
| 
       293 
329 
     | 
    
         
             
                  #
         
     | 
| 
       294 
330 
     | 
    
         
             
                  # Configuration options:
         
     | 
| 
       295 
     | 
    
         
            -
                  # * <tt>message</tt> - A custom error message (default is: " 
     | 
| 
      
 331 
     | 
    
         
            +
                  # * <tt>message</tt> - A custom error message (default is: "must be accepted")
         
     | 
| 
       296 
332 
     | 
    
         
             
                  # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
       297 
333 
     | 
    
         
             
                  # * <tt>accept</tt> - Specifies value that is considered accepted.  The default value is a string "1", which
         
     | 
| 
       298 
334 
     | 
    
         
             
                  # makes it easy to relate to an HTML checkbox.
         
     | 
| 
       299 
     | 
    
         
            -
                  #
         
     | 
| 
       300 
     | 
    
         
            -
             
     | 
| 
      
 335 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 336 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 337 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       301 
338 
     | 
    
         
             
                  def validates_acceptance_of(*attr_names)
         
     | 
| 
       302 
339 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" }
         
     | 
| 
       303 
340 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
         @@ -309,20 +346,25 @@ module ActiveRecord 
     | 
|
| 
       309 
346 
     | 
    
         
             
                    end
         
     | 
| 
       310 
347 
     | 
    
         
             
                  end
         
     | 
| 
       311 
348 
     | 
    
         | 
| 
       312 
     | 
    
         
            -
                  # Validates that the specified attributes are  
     | 
| 
      
 349 
     | 
    
         
            +
                  # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save.
         
     | 
| 
       313 
350 
     | 
    
         
             
                  #
         
     | 
| 
       314 
351 
     | 
    
         
             
                  # Configuration options:
         
     | 
| 
       315 
     | 
    
         
            -
                  # * <tt>message</tt> - A custom error message (default is: " 
     | 
| 
      
 352 
     | 
    
         
            +
                  # * <tt>message</tt> - A custom error message (default is: "can't be blank")
         
     | 
| 
       316 
353 
     | 
    
         
             
                  # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
      
 354 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 355 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 356 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       317 
357 
     | 
    
         
             
                  def validates_presence_of(*attr_names)
         
     | 
| 
       318 
     | 
    
         
            -
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[: 
     | 
| 
      
 358 
     | 
    
         
            +
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save }
         
     | 
| 
       319 
359 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
       320 
360 
     | 
    
         | 
| 
       321 
361 
     | 
    
         
             
                    # can't use validates_each here, because it cannot cope with non-existant attributes,
         
     | 
| 
       322 
362 
     | 
    
         
             
                    # while errors.add_on_empty can	
         
     | 
| 
       323 
363 
     | 
    
         
             
                    attr_names.each do |attr_name|
         
     | 
| 
       324 
364 
     | 
    
         
             
                      send(validation_method(configuration[:on])) do |record|
         
     | 
| 
       325 
     | 
    
         
            -
                         
     | 
| 
      
 365 
     | 
    
         
            +
                        unless configuration[:if] and not evaluate_condition(configuration[:if], record)
         
     | 
| 
      
 366 
     | 
    
         
            +
                          record.errors.add_on_blank(attr_name,configuration[:message])
         
     | 
| 
      
 367 
     | 
    
         
            +
                        end
         
     | 
| 
       326 
368 
     | 
    
         
             
                      end
         
     | 
| 
       327 
369 
     | 
    
         
             
                    end
         
     | 
| 
       328 
370 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -351,9 +393,14 @@ module ActiveRecord 
     | 
|
| 
       351 
393 
     | 
    
         
             
                  # * <tt>wrong_length</tt> - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)")
         
     | 
| 
       352 
394 
     | 
    
         
             
                  # * <tt>message</tt> - The error message to use for a :minimum, :maximum, or :is violation.  An alias of the appropriate too_long/too_short/wrong_length message
         
     | 
| 
       353 
395 
     | 
    
         
             
                  # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
      
 396 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 397 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 398 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       354 
399 
     | 
    
         
             
                  def validates_length_of(*attrs)
         
     | 
| 
       355 
400 
     | 
    
         
             
                    # Merge given options with defaults.
         
     | 
| 
       356 
     | 
    
         
            -
                    options =  
     | 
| 
      
 401 
     | 
    
         
            +
                    options = {:too_long     => ActiveRecord::Errors.default_error_messages[:too_long],
         
     | 
| 
      
 402 
     | 
    
         
            +
                               :too_short    => ActiveRecord::Errors.default_error_messages[:too_short],
         
     | 
| 
      
 403 
     | 
    
         
            +
                               :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]}.merge(DEFAULT_VALIDATION_OPTIONS)
         
     | 
| 
       357 
404 
     | 
    
         
             
                    options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash)
         
     | 
| 
       358 
405 
     | 
    
         | 
| 
       359 
406 
     | 
    
         
             
                    # Ensure that one and only one range option is specified.
         
     | 
| 
         @@ -372,15 +419,17 @@ module ActiveRecord 
     | 
|
| 
       372 
419 
     | 
    
         
             
                    option_value = options[range_options.first]
         
     | 
| 
       373 
420 
     | 
    
         | 
| 
       374 
421 
     | 
    
         
             
                    # Declare different validations per option.
         
     | 
| 
       375 
     | 
    
         
            -
                    
         
     | 
| 
       376 
422 
     | 
    
         
             
                    validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
         
     | 
| 
       377 
423 
     | 
    
         
             
                    message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
         
     | 
| 
       378 
424 
     | 
    
         | 
| 
       379 
425 
     | 
    
         
             
                    case option
         
     | 
| 
       380 
426 
     | 
    
         
             
                    when :within, :in
         
     | 
| 
       381 
427 
     | 
    
         
             
                      raise ArgumentError, ':within must be a Range' unless option_value.is_a?(Range) # '
         
     | 
| 
       382 
     | 
    
         
            -
                       
     | 
| 
       383 
     | 
    
         
            -
                       
     | 
| 
      
 428 
     | 
    
         
            +
                      (options_without_range = options.dup).delete(option)
         
     | 
| 
      
 429 
     | 
    
         
            +
                      (options_with_minimum = options_without_range.dup).store(:minimum, option_value.begin)
         
     | 
| 
      
 430 
     | 
    
         
            +
                      validates_length_of attrs, options_with_minimum
         
     | 
| 
      
 431 
     | 
    
         
            +
                      (options_with_maximum = options_without_range.dup).store(:maximum, option_value.end)
         
     | 
| 
      
 432 
     | 
    
         
            +
                      validates_length_of attrs, options_with_maximum
         
     | 
| 
       384 
433 
     | 
    
         
             
                    when :is, :minimum, :maximum
         
     | 
| 
       385 
434 
     | 
    
         
             
                      raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 # '
         
     | 
| 
       386 
435 
     | 
    
         
             
                      message = options[:message] || options[message_options[option]]
         
     | 
| 
         @@ -407,17 +456,20 @@ module ActiveRecord 
     | 
|
| 
       407 
456 
     | 
    
         
             
                  # Configuration options:
         
     | 
| 
       408 
457 
     | 
    
         
             
                  # * <tt>message</tt> - Specifies a custom error message (default is: "has already been taken")
         
     | 
| 
       409 
458 
     | 
    
         
             
                  # * <tt>scope</tt> - Ensures that the uniqueness is restricted to a condition of "scope = record.scope"
         
     | 
| 
      
 459 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 460 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 461 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       410 
462 
     | 
    
         
             
                  def validates_uniqueness_of(*attr_names)
         
     | 
| 
       411 
463 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken] }
         
     | 
| 
       412 
464 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
       413 
465 
     | 
    
         | 
| 
       414 
466 
     | 
    
         
             
                    if scope = configuration[:scope]
         
     | 
| 
       415 
467 
     | 
    
         
             
                      validates_each(attr_names,configuration) do |record, attr_name, value|
         
     | 
| 
       416 
     | 
    
         
            -
                        record.errors.add(attr_name, configuration[:message]) if record.class. 
     | 
| 
      
 468 
     | 
    
         
            +
                        record.errors.add(attr_name, configuration[:message]) if record.class.find(:first, :conditions => (record.new_record? ? ["#{attr_name} = ? AND #{scope} = ?", record.send(attr_name), record.send(scope)] : ["#{attr_name} = ? AND #{record.class.primary_key} <> ? AND #{scope} = ?", record.send(attr_name), record.send(:id), record.send(scope)]))
         
     | 
| 
       417 
469 
     | 
    
         
             
                      end
         
     | 
| 
       418 
470 
     | 
    
         
             
                    else
         
     | 
| 
       419 
471 
     | 
    
         
             
                      validates_each(attr_names,configuration) do |record, attr_name, value|
         
     | 
| 
       420 
     | 
    
         
            -
                        record.errors.add(attr_name, configuration[:message]) if record.class. 
     | 
| 
      
 472 
     | 
    
         
            +
                        record.errors.add(attr_name, configuration[:message]) if record.class.find(:first, :conditions => (record.new_record? ? ["#{attr_name} = ?", record.send(attr_name)] : ["#{attr_name} = ? AND #{record.class.primary_key} <> ?", record.send(attr_name), record.send(:id) ] ))
         
     | 
| 
       421 
473 
     | 
    
         
             
                      end
         
     | 
| 
       422 
474 
     | 
    
         
             
                    end
         
     | 
| 
       423 
475 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -435,6 +487,9 @@ module ActiveRecord 
     | 
|
| 
       435 
487 
     | 
    
         
             
                  # * <tt>message</tt> - A custom error message (default is: "is invalid")
         
     | 
| 
       436 
488 
     | 
    
         
             
                  # * <tt>with</tt> - The regular expression used to validate the format with (note: must be supplied!)
         
     | 
| 
       437 
489 
     | 
    
         
             
                  # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
      
 490 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 491 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 492 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       438 
493 
     | 
    
         
             
                  def validates_format_of(*attr_names)
         
     | 
| 
       439 
494 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
         
     | 
| 
       440 
495 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
         @@ -457,6 +512,9 @@ module ActiveRecord 
     | 
|
| 
       457 
512 
     | 
    
         
             
                  # * <tt>in</tt> - An enumerable object of available items
         
     | 
| 
       458 
513 
     | 
    
         
             
                  # * <tt>message</tt> - Specifies a customer error message (default is: "is not included in the list")
         
     | 
| 
       459 
514 
     | 
    
         
             
                  # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
         
     | 
| 
      
 515 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 516 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 517 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       460 
518 
     | 
    
         
             
                  def validates_inclusion_of(*attr_names)
         
     | 
| 
       461 
519 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }
         
     | 
| 
       462 
520 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
         @@ -470,6 +528,33 @@ module ActiveRecord 
     | 
|
| 
       470 
528 
     | 
    
         
             
                    end
         
     | 
| 
       471 
529 
     | 
    
         
             
                  end
         
     | 
| 
       472 
530 
     | 
    
         | 
| 
      
 531 
     | 
    
         
            +
                  # Validates that the value of the specified attribute is not in a particular enumerable object.
         
     | 
| 
      
 532 
     | 
    
         
            +
                  #
         
     | 
| 
      
 533 
     | 
    
         
            +
                  #   class Person < ActiveRecord::Base
         
     | 
| 
      
 534 
     | 
    
         
            +
                  #     validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
         
     | 
| 
      
 535 
     | 
    
         
            +
                  #     validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
         
     | 
| 
      
 536 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 537 
     | 
    
         
            +
                  #
         
     | 
| 
      
 538 
     | 
    
         
            +
                  # Configuration options:
         
     | 
| 
      
 539 
     | 
    
         
            +
                  # * <tt>in</tt> - An enumerable object of items that the value shouldn't be part of
         
     | 
| 
      
 540 
     | 
    
         
            +
                  # * <tt>message</tt> - Specifies a customer error message (default is: "is reserved")
         
     | 
| 
      
 541 
     | 
    
         
            +
                  # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
         
     | 
| 
      
 542 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 543 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 544 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
      
 545 
     | 
    
         
            +
                  def validates_exclusion_of(*attr_names)
         
     | 
| 
      
 546 
     | 
    
         
            +
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save }
         
     | 
| 
      
 547 
     | 
    
         
            +
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
      
 548 
     | 
    
         
            +
             
     | 
| 
      
 549 
     | 
    
         
            +
                    enum = configuration[:in] || configuration[:within]
         
     | 
| 
      
 550 
     | 
    
         
            +
             
     | 
| 
      
 551 
     | 
    
         
            +
                    raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?")
         
     | 
| 
      
 552 
     | 
    
         
            +
             
     | 
| 
      
 553 
     | 
    
         
            +
                    validates_each(attr_names, configuration) do |record, attr_name, value|
         
     | 
| 
      
 554 
     | 
    
         
            +
                      record.errors.add(attr_name, configuration[:message]) if enum.include?(value)
         
     | 
| 
      
 555 
     | 
    
         
            +
                    end
         
     | 
| 
      
 556 
     | 
    
         
            +
                  end
         
     | 
| 
      
 557 
     | 
    
         
            +
             
     | 
| 
       473 
558 
     | 
    
         
             
                  # Validates whether the associated object or objects are all themselves valid. Works with any kind of association.
         
     | 
| 
       474 
559 
     | 
    
         
             
                  #
         
     | 
| 
       475 
560 
     | 
    
         
             
                  #   class Book < ActiveRecord::Base
         
     | 
| 
         @@ -487,10 +572,16 @@ module ActiveRecord 
     | 
|
| 
       487 
572 
     | 
    
         
             
                  #     validates_associated :book
         
     | 
| 
       488 
573 
     | 
    
         
             
                  #   end
         
     | 
| 
       489 
574 
     | 
    
         
             
                  #
         
     | 
| 
       490 
     | 
    
         
            -
                  # this would specify a circular dependency and cause infinite recursion. 
     | 
| 
      
 575 
     | 
    
         
            +
                  # ...this would specify a circular dependency and cause infinite recursion.
         
     | 
| 
      
 576 
     | 
    
         
            +
                  #
         
     | 
| 
      
 577 
     | 
    
         
            +
                  # NOTE: This validation will not fail if the association hasn't been assigned. If you want to ensure that the association
         
     | 
| 
      
 578 
     | 
    
         
            +
                  # is both present and guaranteed to be valid, you also need to use validates_presence_of.
         
     | 
| 
       491 
579 
     | 
    
         
             
                  #
         
     | 
| 
       492 
580 
     | 
    
         
             
                  # Configuration options:
         
     | 
| 
       493 
581 
     | 
    
         
             
                  # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
      
 582 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 583 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 584 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       494 
585 
     | 
    
         
             
                  def validates_associated(*attr_names)
         
     | 
| 
       495 
586 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }
         
     | 
| 
       496 
587 
     | 
    
         
             
                    configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
         
     | 
| 
         @@ -514,6 +605,9 @@ module ActiveRecord 
     | 
|
| 
       514 
605 
     | 
    
         
             
                  # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
         
     | 
| 
       515 
606 
     | 
    
         
             
                  # * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
         
     | 
| 
       516 
607 
     | 
    
         
             
                  # * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columsn empty strings are converted to nil
         
     | 
| 
      
 608 
     | 
    
         
            +
                  # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
         
     | 
| 
      
 609 
     | 
    
         
            +
                  # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
         
     | 
| 
      
 610 
     | 
    
         
            +
                  # method, proc or string should return or evaluate to a true or false value.
         
     | 
| 
       517 
611 
     | 
    
         
             
                  def validates_numericality_of(*attr_names)
         
     | 
| 
       518 
612 
     | 
    
         
             
                    configuration = { :message => ActiveRecord::Errors.default_error_messages[:not_a_number], :on => :save,
         
     | 
| 
       519 
613 
     | 
    
         
             
                                       :only_integer => false, :allow_nil => false }
         
     | 
| 
         @@ -525,6 +619,7 @@ module ActiveRecord 
     | 
|
| 
       525 
619 
     | 
    
         
             
                      end
         
     | 
| 
       526 
620 
     | 
    
         
             
                    else
         
     | 
| 
       527 
621 
     | 
    
         
             
                      validates_each(attr_names,configuration) do |record, attr_name,value|
         
     | 
| 
      
 622 
     | 
    
         
            +
                       next if configuration[:allow_nil] and record.send("#{attr_name}_before_type_cast").nil?
         
     | 
| 
       528 
623 
     | 
    
         
             
                        begin
         
     | 
| 
       529 
624 
     | 
    
         
             
                          Kernel.Float(record.send("#{attr_name}_before_type_cast").to_s)
         
     | 
| 
       530 
625 
     | 
    
         
             
                        rescue ArgumentError, TypeError
         
     | 
| 
         @@ -558,7 +653,7 @@ module ActiveRecord 
     | 
|
| 
       558 
653 
     | 
    
         
             
                # Attempts to save the record just like Base.save but will raise a RecordInvalid exception instead of returning false
         
     | 
| 
       559 
654 
     | 
    
         
             
                # if the record is not valid.
         
     | 
| 
       560 
655 
     | 
    
         
             
                def save!
         
     | 
| 
       561 
     | 
    
         
            -
                  valid? ?  
     | 
| 
      
 656 
     | 
    
         
            +
                  valid? ? save(false) : raise(RecordInvalid)
         
     | 
| 
       562 
657 
     | 
    
         
             
                end
         
     | 
| 
       563 
658 
     | 
    
         | 
| 
       564 
659 
     | 
    
         
             
                # Updates a single attribute and saves the record without going through the normal validation procedure.
         
     |