diff options
Diffstat (limited to 'activerecord')
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 65 | ||||
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 3 | ||||
-rw-r--r-- | activerecord/lib/active_record/callbacks.rb | 38 | ||||
-rw-r--r-- | activerecord/lib/active_record/fixtures.rb | 103 |
4 files changed, 110 insertions, 99 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 05ce8ff0b5..e2dc883b1b 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -133,41 +133,40 @@ module ActiveRecord # | | belongs_to | # generated methods | belongs_to | :polymorphic | has_one # ----------------------------------+------------+--------------+--------- - # #other | X | X | X - # #other=(other) | X | X | X - # #build_other(attributes={}) | X | | X - # #create_other(attributes={}) | X | | X - # #other.create!(attributes={}) | | | X - # #other.nil? | X | X | + # other | X | X | X + # other=(other) | X | X | X + # build_other(attributes={}) | X | | X + # create_other(attributes={}) | X | | X + # other.create!(attributes={}) | | | X # # ===Collection associations (one-to-many / many-to-many) # | | | has_many # generated methods | habtm | has_many | :through # ----------------------------------+-------+----------+---------- - # #others | X | X | X - # #others=(other,other,...) | X | X | X - # #other_ids | X | X | X - # #other_ids=(id,id,...) | X | X | X - # #others<< | X | X | X - # #others.push | X | X | X - # #others.concat | X | X | X - # #others.build(attributes={}) | X | X | X - # #others.create(attributes={}) | X | X | X - # #others.create!(attributes={}) | X | X | X - # #others.size | X | X | X - # #others.length | X | X | X - # #others.count | X | X | X - # #others.sum(args*,&block) | X | X | X - # #others.empty? | X | X | X - # #others.clear | X | X | X - # #others.delete(other,other,...) | X | X | X - # #others.delete_all | X | X | - # #others.destroy_all | X | X | X - # #others.find(*args) | X | X | X - # #others.find_first | X | | - # #others.exists? | X | X | X - # #others.uniq | X | X | X - # #others.reset | X | X | X + # others | X | X | X + # others=(other,other,...) | X | X | X + # other_ids | X | X | X + # other_ids=(id,id,...) | X | X | X + # others<< | X | X | X + # others.push | X | X | X + # others.concat | X | X | X + # others.build(attributes={}) | X | X | X + # others.create(attributes={}) | X | X | X + # others.create!(attributes={}) | X | X | X + # others.size | X | X | X + # others.length | X | X | X + # others.count | X | X | X + # others.sum(args*,&block) | X | X | X + # others.empty? | X | X | X + # others.clear | X | X | X + # others.delete(other,other,...) | X | X | X + # others.delete_all | X | X | + # others.destroy_all | X | X | X + # others.find(*args) | X | X | X + # others.find_first | X | | + # others.exists? | X | X | X + # others.uniq | X | X | X + # others.reset | X | X | X # # == Cardinality and associations # @@ -813,8 +812,6 @@ module ActiveRecord # [association=(associate)] # Assigns the associate object, extracts the primary key, sets it as the foreign key, # and saves the associate object. - # [association.nil?] - # Returns +true+ if there is no associated object. # [build_association(attributes = {})] # Returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key, but has not @@ -833,7 +830,6 @@ module ActiveRecord # An Account class declares <tt>has_one :beneficiary</tt>, which will add: # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find(:first, :conditions => "account_id = #{id}")</tt>) # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>) - # * <tt>Account#beneficiary.nil?</tt> # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>) # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>) # @@ -934,8 +930,6 @@ module ActiveRecord # Returns the associated object. +nil+ is returned if none is found. # [association=(associate)] # Assigns the associate object, extracts the primary key, and sets it as the foreign key. - # [association.nil?] - # Returns +true+ if there is no associated object. # [build_association(attributes = {})] # Returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. @@ -953,7 +947,6 @@ module ActiveRecord # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>) # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>) # * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>) - # * <tt>Post#author.nil?</tt> # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>) # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>) # The declaration can also include an options hash to specialize the behavior of the association. diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 982342e509..55ab1facf2 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -886,7 +886,8 @@ module ActiveRecord #:nodoc: # Deletes the records matching +conditions+ without instantiating the records first, and hence not # calling the +destroy+ method nor invoking callbacks. This is a single SQL DELETE statement that # goes straight to the database, much more efficient than +destroy_all+. Be careful with relations - # though, in particular <tt>:dependent</tt> rules defined on associations are not honored. + # though, in particular <tt>:dependent</tt> rules defined on associations are not honored. Returns + # the number of rows affected. # # ==== Parameters # diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 88958f4583..e375037b5b 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -104,6 +104,37 @@ module ActiveRecord # The callback objects have methods named after the callback called with the record as the only parameter, such as: # # class BankAccount < ActiveRecord::Base + # before_save EncryptionWrapper.new + # after_save EncryptionWrapper.new + # after_initialize EncryptionWrapper.new + # end + # + # class EncryptionWrapper + # def before_save(record) + # record.credit_card_number = encrypt(record.credit_card_number) + # end + # + # def after_save(record) + # record.credit_card_number = decrypt(record.credit_card_number) + # end + # + # alias_method :after_find, :after_save + # + # private + # def encrypt(value) + # # Secrecy is committed + # end + # + # def decrypt(value) + # # Secrecy is unveiled + # end + # end + # + # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has + # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other + # initialization data such as the name of the attribute to work with: + # + # class BankAccount < ActiveRecord::Base # before_save EncryptionWrapper.new("credit_card_number") # after_save EncryptionWrapper.new("credit_card_number") # after_initialize EncryptionWrapper.new("credit_card_number") @@ -115,11 +146,11 @@ module ActiveRecord # end # # def before_save(record) - # record.credit_card_number = encrypt(record.credit_card_number) + # record.send("#{@attribute}=", encrypt(record.send("#{@attribute}"))) # end # # def after_save(record) - # record.credit_card_number = decrypt(record.credit_card_number) + # record.send("#{@attribute}=", decrypt(record.send("#{@attribute}"))) # end # # alias_method :after_find, :after_save @@ -134,9 +165,6 @@ module ActiveRecord # end # end # - # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has - # a method by the name of the callback messaged. - # # The callback macros usually accept a symbol for the method they're supposed to run, but you can also pass a "method string", # which will then be evaluated within the binding of the callback. Example: # diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 0131d9fac5..c6501113bf 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -21,13 +21,17 @@ else end end -# Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavors: +# Fixtures are a way of organizing data that you want to test against; in short, sample data. +# +# = Fixture formats +# +# Fixtures come in 3 flavors: # # 1. YAML fixtures # 2. CSV fixtures # 3. Single-file fixtures # -# = YAML fixtures +# == YAML fixtures # # This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures # in a non-verbose, human-readable format. It ships with Ruby 1.8.1+. @@ -65,9 +69,9 @@ end # parent_id: 1 # title: Child # -# = CSV fixtures +# == CSV fixtures # -# Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored +# Fixtures can also be kept in the Comma Separated Value (CSV) format. Akin to YAML fixtures, CSV fixtures are stored # in a single file, but instead end with the <tt>.csv</tt> file extension # (Rails example: <tt><your-rails-app>/test/fixtures/web_sites.csv</tt>). # @@ -90,7 +94,7 @@ end # Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you # have existing data somewhere already. # -# = Single-file fixtures +# == Single-file fixtures # # This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats. # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory @@ -113,65 +117,53 @@ end # name => Ruby on Rails # url => http://www.rubyonrails.org # -# = Using Fixtures +# = Using fixtures in testcases # # Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the # fixtures, but first let's take a look at a sample unit test: # -# require 'web_site' +# require 'test_helper' # # class WebSiteTest < ActiveSupport::TestCase -# def test_web_site_count +# test "web_site_count" do # assert_equal 2, WebSite.count # end # end # -# As it stands, unless we pre-load the web_site table in our database with two records, this test will fail. Here's the -# easiest way to add fixtures to the database: -# -# ... -# class WebSiteTest < ActiveSupport::TestCase -# fixtures :web_sites # add more by separating the symbols with commas -# ... -# -# By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here though), we trigger -# the testing environment to automatically load the appropriate fixtures into the database before each test. +# By default, the <tt>test_helper module</tt> will load all of your fixtures into your test database, so this test will succeed. +# The testing environment will automatically load the all fixtures into the database before each test. # To ensure consistent data, the environment deletes the fixtures before running the load. # -# In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable -# of the test case. It is named after the symbol... so, in our example, there would be a hash available called -# <tt>@web_sites</tt>. This is where the "fixture name" comes into play. -# -# On top of that, each record is automatically "found" (using <tt>Model.find(id)</tt>) and placed in the instance variable of its name. -# So for the YAML fixtures, we'd get <tt>@rubyonrails</tt> and <tt>@google</tt>, which could be interrogated using regular Active Record semantics: +# In addition to being available in the database, the fixture's data may also be accessed by +# using a special dynamic method, which has the same name as the model, and accepts the +# name of the fixture to instantiate: # -# # test if the object created from the fixture data has the same attributes as the data itself -# def test_find -# assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name +# test "find" do +# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name # end # -# As seen above, the data hash created from the YAML fixtures would have <tt>@web_sites["rubyonrails"]["url"]</tt> return -# "http://www.rubyonrails.org" and <tt>@web_sites["google"]["name"]</tt> would return "Google". The same fixtures, but loaded -# from a CSV fixture file, would be accessible via <tt>@web_sites["web_site_1"]["name"] == "Ruby on Rails"</tt> and have the individual -# fixtures available as instance variables <tt>@web_site_1</tt> and <tt>@web_site_2</tt>. +# Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the following tests: # -# If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options. +# test "find_alt_method_1" do +# assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name'] +# end # -# - to completely disable instantiated fixtures: -# self.use_instantiated_fixtures = false +# test "find_alt_method_2" do +# assert_equal "Ruby on Rails", @rubyonrails.news +# end # -# - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance: -# self.use_instantiated_fixtures = :no_instances +# In order to use these methods to access fixtured data within your testcases, you must specify one of the +# following in your <tt>ActiveSupport::TestCase</tt>-derived class: # -# Even if auto-instantiated fixtures are disabled, you can still access them -# by name via special dynamic methods. Each method has the same name as the -# model, and accepts the name of the fixture to instantiate: +# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above) +# self.use_instantiated_fixtures = true # -# fixtures :web_sites +# - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only) +# self.use_instantiated_fixtures = :no_instances # -# def test_find -# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name -# end +# Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully +# traversed in the database to create the fixture hash and/or instance variables. This is expensive for +# large sets of fixtured data. # # = Dynamic fixtures with ERb # @@ -194,21 +186,17 @@ end # = Transactional fixtures # # TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case. -# They can also turn off auto-instantiation of fixture data since the feature is costly and often unused. # # class FooTest < ActiveSupport::TestCase # self.use_transactional_fixtures = true -# self.use_instantiated_fixtures = false -# -# fixtures :foos # -# def test_godzilla +# test "godzilla" do # assert !Foo.find(:all).empty? # Foo.destroy_all # assert Foo.find(:all).empty? # end # -# def test_godzilla_aftermath +# test "godzilla aftermath" do # assert !Foo.find(:all).empty? # end # end @@ -220,24 +208,25 @@ end # access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+) # # When *not* to use transactional fixtures: -# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit, -# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify -# the results of your transaction until Active Record supports nested transactions or savepoints (in progress). -# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM. -# Use InnoDB, MaxDB, or NDB instead. +# +# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit, +# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify +# the results of your transaction until Active Record supports nested transactions or savepoints (in progress). +# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM. +# Use InnoDB, MaxDB, or NDB instead. # # = Advanced YAML Fixtures # # YAML fixtures that don't specify an ID get some extra features: # -# * Stable, autogenerated ID's +# * Stable, autogenerated IDs # * Label references for associations (belongs_to, has_one, has_many) # * HABTM associations as inline lists # * Autofilled timestamp columns # * Fixture label interpolation # * Support for YAML defaults # -# == Stable, autogenerated ID's +# == Stable, autogenerated IDs # # Here, have a monkey fixture: # @@ -292,7 +281,7 @@ end # # Add a few more monkeys and pirates and break this into multiple files, # and it gets pretty hard to keep track of what's going on. Let's -# use labels instead of ID's: +# use labels instead of IDs: # # ### in pirates.yml # |