From 5a3fd46d42f05a241b3178af60d38fe5e0cebee6 Mon Sep 17 00:00:00 2001 From: Rodrigo Kochenburger Date: Tue, 13 May 2008 22:08:31 -0300 Subject: Fixing test for named_scope through a has_many :through The test that checks if a has_many :through association has access to named_scope had a typo and didn't have the proper fixtures loaded. [#190 state:resolved] --- activerecord/test/cases/named_scope_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 30c074c9d8..9730f93579 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -6,7 +6,7 @@ require 'models/reply' require 'models/author' class NamedScopeTest < ActiveRecord::TestCase - fixtures :posts, :authors, :topics + fixtures :posts, :authors, :topics, :comments def test_implements_enumerable assert !Topic.find(:all).empty? @@ -95,7 +95,7 @@ class NamedScopeTest < ActiveRecord::TestCase end def test_has_many_through_associations_have_access_to_named_scopes - assert_not_equal Comment.containing_the_letter_e, authors(:david).posts + assert_not_equal Comment.containing_the_letter_e, authors(:david).comments assert !Comment.containing_the_letter_e.empty? assert_equal authors(:david).comments & Comment.containing_the_letter_e, authors(:david).comments.containing_the_letter_e -- cgit v1.2.3 From 46f30f902fb5e705683dea19ec22179c61e5f208 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 16 May 2008 23:01:32 +0100 Subject: Merge documentation changes from docrails. commit 0fc3381aa5359f31b36057d7bfba2e0eb6a3c064 Author: Xavier Noria Date: Fri May 16 23:44:51 2008 +0200 Conventions. Formatting. Revising docs all over the rails. This revision encourages the modern resource-oriented form_for usage. In addition corrects some markup and other details. commit 70e4bcf5cb039bea073851faed2df9f465e6f2f8 Author: Chris Kampmeier Date: Fri May 16 12:09:46 2008 -0700 Fix a couple spelling errors in docs commit 6ea5e4208f724b50e774e6a1af027336c3ee3de1 Author: Chris O'Sullivan Date: Fri May 16 16:09:11 2008 +0100 Added docs about source_type for has_one association commit a01a0178be297b0eb62909819a15a01c6b69a841 Author: miloops Date: Wed May 14 09:22:39 2008 +0000 Change migration generator USAGE to explain the timestamped migrations behaviour commit 4e2bc02163aa646ab1304b1b5bec98a7af8927f5 Author: Xavier Noria Date: Fri May 16 00:43:03 2008 +0200 minor revision in url_for docs Made explicit that RESTful and controller/action styles are not interchangeable, and revised some markup. commit d6ecce66f4e125531875006eea8022b73fe135b5 Author: Michael Hartl Date: Thu May 15 10:46:40 2008 -0700 Expanded and updated the link_to documentation commit b8c46c86f0b785f6afc3c58eeb1b347543f5901e Author: Cody Fauser Date: Wed May 14 09:10:02 2008 -0400 Improve and cleanup ActionMailer documentation commit 9546ee299952c86329c4854f9b3776382c0575ff Author: Yehuda Katz Date: Mon May 12 23:41:43 2008 -0700 Add documentation for Inflector.inflections commit cbd5db8f5165f013069b02414f9bf762d88f619f Author: Manik Juneja Date: Mon May 12 23:43:31 2008 +0530 minor changes in railties/README. Added dbconsole introduction commit 130a280ddee1f96ccf378b52c17ee742b5e54f4a Author: Gaurav Sharma Date: Mon May 12 18:00:19 2008 +0530 adding documentation for cached_attributes commit 164c9586480f0a02522ea15ec7fb42c6a783a74d Author: TomK32 Date: Mon May 12 10:59:33 2008 +0200 proper heading for "Example:" commit 35634feb474cc55fbc95edeffe98cec241d45f23 Author: Matt Boehlig Date: Sun May 11 16:46:07 2008 -0500 Cleanup whitespace and change_table documentation commit 80bba28a1a56a0cafeb0fc94659905e88129bc31 Author: Xavier Noria Date: Sun May 11 02:54:02 2008 +0200 documented the source annotation extractor commit e6823bb1650d9b0fea58bd2d355f388961a408b3 Author: Mike Mondragon Date: Fri May 9 13:49:56 2008 -0700 Added additional information about processing email with ActionMailer and the strategy one might want to employ to do so. commit e6afd8b2736364322b673bbdcca3e9b38b6d3da0 Author: Xavier Noria Date: Thu May 8 23:49:36 2008 +0200 corrected and completed docs of increment/decrement/toggle in AR::Base commit 2fead68b3192332eee27945ed95a94a64ca73f70 Author: Austin Putman Date: Wed May 7 19:35:46 2008 -0700 Documented class methods on ActionController::Routing. These are dangerous, and mostly used for testing. commit f5b84182dbc39bea79c8ee319c688d00fa99f9d1 Author: Teflon Ted Date: Wed May 7 16:08:49 2008 -0400 Added explanation about errant inflections not being patched in the future in order to avoid breaking legacy applications. commit 370f4f51722cec49ace17093d29e9ce9e8f15cfb Author: Sunny Ripert Date: Wed May 7 14:00:59 2008 +0200 Applied list conventions in AR::Base commit 5bd18429f09d44e75191bec42a6db04bd33f3030 Author: Sunny Ripert Date: Wed May 7 13:53:35 2008 +0200 Renamed Options list to Attributes list whenever they weren't option hashes in AR::Base commit 2fa628e34b25166afb49e3afeea87e770ab84256 Author: Xavier Noria Date: Wed May 7 11:52:33 2008 +0200 revised details in Exceptions section of AR::Base docs commit d912bd5672316454457ae83f6e9dda5197beeb6f Author: Yaroslav Markin Date: Wed May 7 13:50:28 2008 +0400 Add a filter_parameter_logging usage hint to generated ApplicationController. This may help to remind the developer to filter sensitive information from application logs. Closes #11578 commit f81d771f0657ae8375b84a77a059812cce5d6fd9 Author: Jack Danger Canty Date: Tue May 6 23:35:05 2008 -0700 doc: ActiveRecord::Reflection::AssociationReflection#through_reflection Added documentation demonstrating the use of #through_reflection for finding intervening reflection objects for HasManyThrough and HasOneThrough. commit ae6b46f00b5b8b2939c6b37ce3329c83de7e71db Author: Cheah Chu Yeow Date: Wed May 7 13:47:41 2008 +0800 Document AttributeAssignmentError and MultiparameterAssignmentErrors. commit 8f463550b597db2156b67733f31aed13487fbc3a Author: John Barnette Date: Tue May 6 22:46:44 2008 -0700 Killing/fixing a bunch of outdated language in the AR README. commit 284a930a93fbee16e25d06392779dbf2f03e9e12 Author: Jonathan Dance Date: Tue May 6 14:58:26 2008 -0400 improvements to the page caching docs commit 9482da621390c874da7c921c8bd6230caae7035a Author: Sunny Ripert Date: Mon May 5 18:13:40 2008 +0200 validates_numericality_of() "integer" option really is "only_integer" commit e9afd6790a8f530528f6597a7f59bb283be754f6 Author: Sunny Ripert Date: Mon May 5 12:11:59 2008 +0200 Harmonized hash notation in AR::Base commit 67ebf14a91ffd970b582be4ff2991d691a9cf3e1 Author: Sunny Ripert Date: Mon May 5 12:06:19 2008 +0200 Turned options into rdoc-lists in AR::Base commit 0ec7c0a41d889d4e5382b9dff72f1aaba89bf297 Author: Marshall Huss Date: Sun May 4 23:21:33 2008 -0400 Added information of how to set element_name in the case the user has a name confliction with an existing model Signed-off-by: Pratik Naik --- activerecord/CHANGELOG | 2 +- activerecord/lib/active_record/associations.rb | 2 + .../lib/active_record/attribute_methods.rb | 40 ++++++---- .../abstract/schema_definitions.rb | 90 +++++++++++----------- .../abstract/schema_statements.rb | 20 ++--- 5 files changed, 81 insertions(+), 73 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 9b936863ba..cd526a52a7 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -12,7 +12,7 @@ change_table :videos do |t| t.timestamps # adds created_at, updated_at - t.belongs_to :goat # add goat_id integer + t.belongs_to :goat # adds goat_id integer t.string :name, :email, :limit => 20 # adds name and email both with a 20 char limit t.remove :name, :email # removes the name and email columns end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c17e35f5e0..95caf68692 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -753,6 +753,8 @@ module ActiveRecord # * :source - Specifies the source association name used by has_one :through queries. Only use it if the name cannot be # inferred from the association. has_one :favorite, :through => :favorites will look for a # :favorite on Favorite, unless a :source is given. + # * :source_type - Specifies type of the source association used by has_one :through queries where the source + # association is a polymorphic +belongs_to+. # * :readonly - If true, the associated object is readonly through the association. # # Option examples: diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 2db27226f2..c2604894a8 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -16,16 +16,20 @@ module ActiveRecord # Declare and check for suffixed attribute methods. module ClassMethods - # Declare a method available for all attributes with the given suffix. - # Uses method_missing and respond_to? to rewrite the method + # Declares a method available for all attributes with the given suffix. + # Uses +method_missing+ and respond_to? to rewrite the method + # # #{attr}#{suffix}(*args, &block) + # # to + # # attribute#{suffix}(#{attr}, *args, &block) # - # An attribute#{suffix} instance method must exist and accept at least - # the attr argument. + # An attribute#{suffix} instance method must exist and accept at least + # the +attr+ argument. # # For example: + # # class Person < ActiveRecord::Base # attribute_method_suffix '_changed?' # @@ -60,8 +64,8 @@ module ActiveRecord !generated_methods.empty? end - # generates all the attribute related methods for columns in the database - # accessors, mutators and query methods + # Generates all the attribute related methods for columns in the database + # accessors, mutators and query methods. def define_attribute_methods return if generated_methods? columns_hash.each do |name, column| @@ -89,8 +93,9 @@ module ActiveRecord end end - # Check to see if the method is defined in the model or any of its subclasses that also derive from ActiveRecord. - # Raise DangerousAttributeError if the method is defined by ActiveRecord though. + # Checks whether the method is defined in the model or any of its subclasses + # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s return true if method_name =~ /^id(=$|\?$|$)/ @@ -104,17 +109,19 @@ module ActiveRecord # +cache_attributes+ allows you to declare which converted attribute values should # be cached. Usually caching only pays off for attributes with expensive conversion - # methods, like date columns (e.g. created_at, updated_at). + # methods, like time related columns (e.g. +created_at+, +updated_at+). def cache_attributes(*attribute_names) attribute_names.each {|attr| cached_attributes << attr.to_s} end - # returns the attributes where + # Returns the attributes which are cached. By default time related columns + # with datatype :datetime, :timestamp, :time, :date are cached. def cached_attributes @cached_attributes ||= columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map(&:name).to_set end + # Returns +true+ if the provided attribute is being cached. def cache_attribute?(attr_name) cached_attributes.include?(attr_name) end @@ -210,14 +217,14 @@ module ActiveRecord end # ClassMethods - # Allows access to the object attributes, which are held in the @attributes hash, as though they + # Allows access to the object attributes, which are held in the @attributes hash, as though they # were first-class methods. So a Person class with a name attribute can use Person#name and # Person#name= and never directly use the attributes hash -- except for multiple assigns with # ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that - # the completed attribute is not nil or 0. + # the completed attribute is not +nil+ or 0. # # It's also possible to instantiate related objects, so a Client class belonging to the clients - # table with a master_id foreign key can instantiate master through Client#master. + # table with a +master_id+ foreign key can instantiate master through Client#master. def method_missing(method_id, *args, &block) method_name = method_id.to_s @@ -288,7 +295,7 @@ module ActiveRecord # Updates the attribute identified by attr_name with the specified +value+. Empty strings for fixnum and float - # columns are turned into nil. + # columns are turned into +nil+. def write_attribute(attr_name, value) attr_name = attr_name.to_s @attributes_cache.delete(attr_name) @@ -319,8 +326,9 @@ module ActiveRecord end end - # A Person object with a name attribute can ask person.respond_to?("name"), person.respond_to?("name="), and - # person.respond_to?("name?") which will all return true. + # A Person object with a name attribute can ask person.respond_to?("name"), + # person.respond_to?("name="), and person.respond_to?("name?") + # which will all return +true+. alias :respond_to_without_attributes? :respond_to? def respond_to?(method, include_priv = false) method_name = method.to_s diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index d73ffc3da6..fdb18b234c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -18,11 +18,11 @@ module ActiveRecord # # +name+ is the column's name, as in supplier_id int(11). # +default+ is the type-casted default value, such as sales_stage varchar(20) default 'new'. - # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). + # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @name, @sql_type, @null = name, sql_type, null - @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type) + @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type) @type = simplified_type(sql_type) @default = extract_default(default) @@ -172,7 +172,7 @@ module ActiveRecord def new_time(year, mon, mday, hour, min, sec, microsec) # Treat 0000-00-00 00:00:00 as nil. return nil if year.nil? || year == 0 - + Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil end @@ -250,11 +250,11 @@ module ActiveRecord end class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc: - + def sql_type base.type_to_sql(type.to_sym, limit, precision, scale) rescue type end - + def to_sql column_sql = "#{base.quote_column_name(name)} #{sql_type}" add_column_options!(column_sql, :null => null, :default => default) unless type.to_sym == :primary_key @@ -309,39 +309,39 @@ module ActiveRecord # * :default - # The column's default value. Use nil for NULL. # * :null - - # Allows or disallows +NULL+ values in the column. This option could + # Allows or disallows +NULL+ values in the column. This option could # have been named :null_allowed. # * :precision - - # Specifies the precision for a :decimal column. + # Specifies the precision for a :decimal column. # * :scale - - # Specifies the scale for a :decimal column. + # Specifies the scale for a :decimal column. # # Please be aware of different RDBMS implementations behavior with # :decimal columns: # * The SQL standard says the default scale should be 0, :scale <= # :precision, and makes no comments about the requirements of # :precision. - # * MySQL: :precision [1..63], :scale [0..30]. + # * MySQL: :precision [1..63], :scale [0..30]. # Default is (10,0). - # * PostgreSQL: :precision [1..infinity], + # * PostgreSQL: :precision [1..infinity], # :scale [0..infinity]. No default. - # * SQLite2: Any :precision and :scale may be used. + # * SQLite2: Any :precision and :scale may be used. # Internal storage as strings. No default. # * SQLite3: No restrictions on :precision and :scale, # but the maximum supported :precision is 16. No default. - # * Oracle: :precision [1..38], :scale [-84..127]. + # * Oracle: :precision [1..38], :scale [-84..127]. # Default is (38,0). - # * DB2: :precision [1..63], :scale [0..62]. + # * DB2: :precision [1..63], :scale [0..62]. # Default unknown. - # * Firebird: :precision [1..18], :scale [0..18]. + # * Firebird: :precision [1..18], :scale [0..18]. # Default (9,0). Internal types NUMERIC and DECIMAL have different # storage rules, decimal being better. - # * FrontBase?: :precision [1..38], :scale [0..38]. + # * FrontBase?: :precision [1..38], :scale [0..38]. # Default (38,0). WARNING Max :precision/:scale for # NUMERIC is 19, and DECIMAL is 38. - # * SqlServer?: :precision [1..38], :scale [0..38]. + # * SqlServer?: :precision [1..38], :scale [0..38]. # Default (38,0). - # * Sybase: :precision [1..38], :scale [0..38]. + # * Sybase: :precision [1..38], :scale [0..38]. # Default (38,0). # * OpenBase?: Documentation unclear. Claims storage in double. # @@ -394,7 +394,7 @@ module ActiveRecord # t.timestamps # end # - # There's a short-hand method for each of the type values declared at the top. And then there's + # There's a short-hand method for each of the type values declared at the top. And then there's # TableDefinition#timestamps that'll add created_at and updated_at as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type @@ -434,13 +434,13 @@ module ActiveRecord def #{column_type}(*args) options = args.extract_options! column_names = args - + column_names.each { |name| column(name, '#{column_type}', options) } end EOV end - - # Appends :datetime columns :created_at and + + # Appends :datetime columns :created_at and # :updated_at to the table. def timestamps column(:created_at, :datetime) @@ -458,7 +458,7 @@ module ActiveRecord alias :belongs_to :references # Returns a String whose contents are the column definitions - # concatenated together. This string can then be prepended and appended to + # concatenated together. This string can then be prepended and appended to # to generate the final SQL to create the table. def to_sql @columns * ', ' @@ -510,15 +510,15 @@ module ActiveRecord # Adds a new column to the named table. # See TableDefinition#column for details of the options you can use. - # ===== Examples - # ====== Creating a simple columns + # ===== Example + # ====== Creating a simple column # t.column(:name, :string) def column(column_name, type, options = {}) @base.add_column(@table_name, column_name, type, options) end - # Adds a new index to the table. +column_name+ can be a single Symbol, or - # an Array of Symbols. See SchemaStatements#add_index + # Adds a new index to the table. +column_name+ can be a single Symbol, or + # an Array of Symbols. See SchemaStatements#add_index # # ===== Examples # ====== Creating a simple index @@ -531,8 +531,8 @@ module ActiveRecord @base.add_index(@table_name, column_name, options) end - # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#timestamps - # ===== Examples + # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps + # ===== Example # t.timestamps def timestamps @base.add_timestamps(@table_name) @@ -547,7 +547,7 @@ module ActiveRecord @base.change_column(@table_name, column_name, type, options) end - # Sets a new default value for a column. See + # Sets a new default value for a column. See SchemaStatements#change_column_default # ===== Examples # t.change_default(:qualification, 'new') # t.change_default(:authorized, 1) @@ -559,27 +559,27 @@ module ActiveRecord # ===== Examples # t.remove(:qualification) # t.remove(:qualification, :experience) - # t.removes(:qualification, :experience) def remove(*column_names) @base.remove_column(@table_name, column_names) end - # Remove the given index from the table. + # Removes the given index from the table. # - # Remove the suppliers_name_index in the suppliers table. + # ===== Examples + # ====== Remove the suppliers_name_index in the suppliers table # t.remove_index :name - # Remove the index named accounts_branch_id_index in the accounts table. + # ====== Remove the index named accounts_branch_id_index in the accounts table # t.remove_index :column => :branch_id - # Remove the index named accounts_branch_id_party_id_index in the accounts table. + # ====== Remove the index named accounts_branch_id_party_id_index in the accounts table # t.remove_index :column => [:branch_id, :party_id] - # Remove the index named by_branch_party in the accounts table. + # ====== Remove the index named by_branch_party in the accounts table # t.remove_index :name => :by_branch_party def remove_index(options = {}) @base.remove_index(@table_name, options) end # Removes the timestamp columns (created_at and updated_at) from the table. - # ===== Examples + # ===== Example # t.remove_timestamps def remove_timestamps @base.remove_timestamps(@table_name) @@ -592,12 +592,11 @@ module ActiveRecord @base.rename_column(@table_name, column_name, new_column_name) end - # Adds a reference. Optionally adds a +type+ column. reference, - # references and belongs_to are all acceptable - # ===== Example + # Adds a reference. Optionally adds a +type+ column. + # references and belongs_to are acceptable. + # ===== Examples # t.references(:goat) # t.references(:goat, :polymorphic => true) - # t.references(:goat) # t.belongs_to(:goat) def references(*args) options = args.extract_options! @@ -609,12 +608,11 @@ module ActiveRecord end alias :belongs_to :references - # Adds a reference. Optionally removes a +type+ column. remove_reference, - # remove_references and remove_belongs_to are all acceptable - # ===== Example - # t.remove_reference(:goat) - # t.remove_reference(:goat, :polymorphic => true) + # Removes a reference. Optionally removes a +type+ column. + # remove_references and remove_belongs_to are acceptable. + # ===== Examples # t.remove_references(:goat) + # t.remove_references(:goat, :polymorphic => true) # t.remove_belongs_to(:goat) def remove_references(*args) options = args.extract_options! @@ -627,7 +625,7 @@ module ActiveRecord alias :remove_belongs_to :remove_references # Adds a column or columns of a specified type - # ===== Example + # ===== Examples # t.string(:goat) # t.string(:goat, :sheep) %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 1594be40e2..ac24e920fe 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -13,7 +13,7 @@ module ActiveRecord 255 end - # Truncates a table alias according to the limits of the current adapter. + # Truncates a table alias according to the limits of the current adapter. def table_alias_for(table_name) table_name[0..table_alias_length-1].gsub(/\./, '_') end @@ -152,7 +152,7 @@ module ActiveRecord # t.remove :company # end # - # ====== Remove a column + # ====== Remove several columns # change_table(:suppliers) do |t| # t.remove :company_id # t.remove :width, :height @@ -168,7 +168,7 @@ module ActiveRecord def change_table(table_name) yield Table.new(table_name, self) end - + # Renames a table. # ===== Example # rename_table('octopuses', 'octopi') @@ -199,7 +199,7 @@ module ActiveRecord end end alias :remove_columns :remove_column - + # Changes the column's definition according to the new options. # See TableDefinition#column for details of the options you can use. # ===== Examples @@ -389,7 +389,7 @@ module ActiveRecord def distinct(columns, order_by) "DISTINCT #{columns}" end - + # ORDER BY clause for the passed order option. # PostgreSQL overrides this due to its stricter standards compliance. def add_order_by_for_association_limiting!(sql, options) @@ -401,17 +401,17 @@ module ActiveRecord # add_timestamps(:suppliers) def add_timestamps(table_name) add_column table_name, :created_at, :datetime - add_column table_name, :updated_at, :datetime + add_column table_name, :updated_at, :datetime end - + # Removes the timestamp columns (created_at and updated_at) from the table definition. # ===== Examples # remove_timestamps(:suppliers) def remove_timestamps(table_name) - remove_column table_name, :updated_at - remove_column table_name, :created_at + remove_column table_name, :updated_at + remove_column table_name, :created_at end - + protected def options_include_default?(options) options.include?(:default) && !(options[:null] == false && options[:default].nil?) -- cgit v1.2.3 From 2183c220ada046993274ccdc6f1f86e9e8a3a5c6 Mon Sep 17 00:00:00 2001 From: Steven Soroka Date: Fri, 16 May 2008 17:41:59 -0500 Subject: Make sure clone_structure can load the results of dump_schema_information SchemaStatements#dump_schema_information joins inserts with a single \n, but is later split on \n\n, and fails when trying to execute all the inserts as a single sql statement. Signed-off-by: Michael Koziarski [#201 state:resolved] --- .../lib/active_record/connection_adapters/abstract/schema_statements.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index ac24e920fe..b57d0a3ef7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -302,7 +302,7 @@ module ActiveRecord def dump_schema_information #:nodoc: sm_table = ActiveRecord::Migrator.schema_migrations_table_name migrated = select_values("SELECT version FROM #{sm_table}") - migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n") + migrated.map { |v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}');" }.join("\n\n") end # Should not be called normally, but this operation is non-destructive. -- cgit v1.2.3 From a49ebf6d7909c344d2fe570cb82c97fa271db03e Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 17 May 2008 17:33:44 +0200 Subject: revised documentation of attr_(protected|accessible) Revised wording and coherence between both docs, avoided the term "hacker" to refer to a malicious user, revised markup and structure. --- activerecord/lib/active_record/base.rb | 38 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5351f55200..00083a50fd 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -860,9 +860,15 @@ module ActiveRecord #:nodoc: end - # Attributes named in this macro are protected from mass-assignment, such as new(attributes) and - # attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer - # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example: + # Attributes named in this macro are protected from mass-assignment, + # such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes). + # + # Mass-assignment to these attributes will simply be ignored, to assign + # to them you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. # # class Customer < ActiveRecord::Base # attr_protected :credit_rating @@ -876,7 +882,8 @@ module ActiveRecord #:nodoc: # customer.credit_rating = "Average" # customer.credit_rating # => "Average" # - # To start from an all-closed default and enable attributes as needed, have a look at attr_accessible. + # To start from an all-closed default and enable attributes as needed, + # have a look at +attr_accessible+. def attr_protected(*attributes) write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || [])) end @@ -886,19 +893,18 @@ module ActiveRecord #:nodoc: read_inheritable_attribute("attr_protected") end - # Similar to the attr_protected macro, this protects attributes of your model from mass-assignment, - # such as new(attributes) and attributes=(attributes) - # however, it does it in the opposite way. This locks all attributes and only allows access to the - # attributes specified. Assignment to attributes not in this list will be ignored and need to be set - # using the direct writer methods instead. This is meant to protect sensitive attributes from being - # overwritten by URL/form hackers. If you'd rather start from an all-open default and restrict - # attributes as needed, have a look at attr_protected. - # - # ==== Attributes + # Specifies a white list of model attributes that can be set via + # mass-assignment, such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes) # - # * *attributes A comma separated list of symbols that represent columns _not_ to be protected - # - # ==== Examples + # This is the opposite of the +attr_protected+ macro: Mass-assignment + # will only set attributes in this list, to assign to the rest of + # attributes you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. If you'd rather start from an all-open + # default and restrict attributes as needed, have a look at + # +attr_protected+. # # class Customer < ActiveRecord::Base # attr_accessible :name, :nickname -- cgit v1.2.3 From c1c1d6c2ea72424dfae0b5ee1991d904dcf0f252 Mon Sep 17 00:00:00 2001 From: gbuesing Date: Sun, 18 May 2008 14:13:47 -0500 Subject: Adding documentation for time zone features --- activerecord/lib/active_record/attribute_methods.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index c2604894a8..d753778d52 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -162,6 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end + # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -183,6 +185,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end + # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}=(time) -- cgit v1.2.3 From c9c4f7bababda23f33693bdca35d1bb37fdfcd15 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Sun, 18 May 2008 20:02:37 +0100 Subject: Update documentation on :include. --- activerecord/lib/active_record/associations.rb | 116 ++++++++++++++----------- activerecord/lib/active_record/base.rb | 2 +- 2 files changed, 64 insertions(+), 54 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 95caf68692..902deeb35c 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -441,9 +441,9 @@ module ActiveRecord # # == Eager loading of associations # - # Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is + # Eager loading is a way to find objects of a certain class and a number of named associations. This is # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author - # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example: + # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 2. Example: # # class Post < ActiveRecord::Base # belongs_to :author @@ -462,14 +462,15 @@ module ActiveRecord # # for post in Post.find(:all, :include => :author) # - # This references the name of the +belongs_to+ association that also used the :author symbol, so the find will now weave in a join something - # like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101. + # This references the name of the +belongs_to+ association that also used the :author symbol. After loading the posts, find + # will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102. # # We can improve upon the situation further by referencing both associations in the finder with: # # for post in Post.find(:all, :include => [ :author, :comments ]) # - # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query. + # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries + # will be 1 plus the number of associations named (except if some of the associations are polymorphic belongs_to - see below). # # To include a deep hierarchy of associations, use a hash: # @@ -482,36 +483,46 @@ module ActiveRecord # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. # - # Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So - # :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the +SELECT+ statement too, the - # :select option is ignored. + # Since only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case + # Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example + # + # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions - # as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich - # associations" with +has_and_belongs_to_many+ are not a good fit for eager loading. + # will result in a single sql query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. + # In the above example posts with no approved comments are not returned at all, because the conditions apply to the sql statement as a whole + # and not just to the association. You must disambiguate column references for this fallback to happen, for example + # :order => "author.name DESC" will work but :order => "name DESC" will not. + # + # If you do want eagerload only some members of an association it is usually more natural to :include an association + # which has conditions defined on it: + # + # class Post < ActiveRecord::Base + # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true] + # end + # + # Post.find(:all, :include => :approved_comments) + # + # will load posts and eager load the approved_comments association, which contains only those comments that have been approved. # # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated # before the actual model exists. # - # Eager loading is not supported with polymorphic associations up to (and including) - # version 2.0.2. Given + # Eager loading is supported with polymorphic associations. # # class Address < ActiveRecord::Base # belongs_to :addressable, :polymorphic => true # end # - # a call that tries to eager load the addressable model - # - # Address.find(:all, :include => :addressable) # INVALID - # - # will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent model's type - # is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that early query. + # A call that tries to eager load the addressable model # - # In versions greater than 2.0.2 eager loading in polymorphic associations is supported - # thanks to a change in the overall preloading strategy. + # Address.find(:all, :include => :addressable) # - # It does work the other way around though: if the User model is addressable you can eager load - # their addresses with :include just fine, every piece needed to construct the query is known beforehand. + # will execute one query to load the addresses and load the addressables with one query per addressable type. + # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of + # addressable types to load is determined on the back of the addresses loaded. This is not supported if ActiveRecord has to fallback + # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent + # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # @@ -519,44 +530,44 @@ module ActiveRecord # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended # for any more successive uses of the table name. # - # Post.find :all, :include => :comments - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... - # Post.find :all, :include => :special_comments # STI - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment' - # Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts + # Post.find :all, :joins => :comments + # # => SELECT ... FROM posts INNER JOIN comments ON ... + # Post.find :all, :joins => :special_comments # STI + # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment' + # Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name + # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts # # Acts as tree example: # - # TreeMixin.find :all, :include => :children - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # TreeMixin.find :all, :include => {:children => {:parent => :children}} - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # LEFT OUTER JOIN mixins childrens_mixins_2 + # TreeMixin.find :all, :joins => :children + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # TreeMixin.find :all, :joins => {:children => :parent} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # TreeMixin.find :all, :joins => {:children => {:parent => :children}} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # INNER JOIN mixins childrens_mixins_2 # # Has and Belongs to Many join tables use the same idea, but add a _join suffix: # - # Post.find :all, :include => :categories - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # Post.find :all, :include => {:categories => :posts} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # Post.find :all, :include => {:categories => {:posts => :categories}} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts + # Post.find :all, :joins => :categories + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # Post.find :all, :joins => {:categories => :posts} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # Post.find :all, :joins => {:categories => {:posts => :categories}} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 # # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations: # - # Post.find :all, :include => :comments, :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ... - # Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ... - # LEFT OUTER JOIN comments special_comments_posts ... + # Post.find :all, :joins => :comments, :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... + # Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ... + # INNER JOIN comments special_comments_posts ... # INNER JOIN comments ... # # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database. @@ -840,7 +851,6 @@ module ActiveRecord # this results in a counter with +NULL+ value, which will never increment. # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. - # Not allowed if the association is polymorphic. # * :polymorphic - Specify this association is a polymorphic association by passing +true+. # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 00083a50fd..c51743af16 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -465,7 +465,7 @@ module ActiveRecord #:nodoc: # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer + # * :include: Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not # include the joined columns. -- cgit v1.2.3 From a50e747971a37dbce95e24253063113d252744e7 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 21:44:15 +0200 Subject: minor details in associations.rb --- activerecord/lib/active_record/associations.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 902deeb35c..ce3d273a42 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -452,7 +452,7 @@ module ActiveRecord # # Consider the following loop using the class above: # - # for post in Post.find(:all) + # for post in Post.all # puts "Post: " + post.title # puts "Written by: " + post.author.name # puts "Last comment on: " + post.comments.first.created_on @@ -470,7 +470,7 @@ module ActiveRecord # for post in Post.find(:all, :include => [ :author, :comments ]) # # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries - # will be 1 plus the number of associations named (except if some of the associations are polymorphic belongs_to - see below). + # will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below). # # To include a deep hierarchy of associations, use a hash: # @@ -488,13 +488,13 @@ module ActiveRecord # # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # will result in a single sql query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # will result in a single SQL query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. - # In the above example posts with no approved comments are not returned at all, because the conditions apply to the sql statement as a whole + # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole # and not just to the association. You must disambiguate column references for this fallback to happen, for example # :order => "author.name DESC" will work but :order => "name DESC" will not. # - # If you do want eagerload only some members of an association it is usually more natural to :include an association + # If you do want eagerload only some members of an association it is usually more natural to :include an association # which has conditions defined on it: # # class Post < ActiveRecord::Base @@ -503,7 +503,7 @@ module ActiveRecord # # Post.find(:all, :include => :approved_comments) # - # will load posts and eager load the approved_comments association, which contains only those comments that have been approved. + # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. # # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated # before the actual model exists. -- cgit v1.2.3 From 14bd01b9a9cdd4ec5c9abf8ae595cca880aa6faf Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 21:51:54 +0200 Subject: revised description list convention in AR's find docs, and markup here and there --- activerecord/lib/active_record/base.rb | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c51743af16..c78eb1984a 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -456,23 +456,23 @@ module ActiveRecord #:nodoc: # # All approaches accept an options hash as their last parameter. The options are: # - # * :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. - # * :order: An SQL fragment like "created_at DESC, name". - # * :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :limit: An integer determining the limit on the number of rows that should be returned. - # * :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. - # * :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) - # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). + # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. + # * :order - An SQL fragment like "created_at DESC, name". + # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. + # * :limit - An integer determining the limit on the number of rows that should be returned. + # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. + # * :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) + # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Names associations that should be loaded alongside. The symbols named refer + # * :include - Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. - # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not + # * :select - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not # include the joined columns. - # * :from: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name + # * :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name # of a database view). - # * :readonly: Mark the returned records read-only so they cannot be saved or updated. - # * :lock: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". + # * :readonly - Mark the returned records read-only so they cannot be saved or updated. + # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". # # Examples for find by id: @@ -504,11 +504,12 @@ module ActiveRecord #:nodoc: # Person.find(:all, :include => [ :account, :friends ]) # Person.find(:all, :group => "category") # - # Example for find with a lock. Imagine two concurrent transactions: - # each will read person.visits == 2, add 1 to it, and save, resulting - # in two saves of person.visits = 3. By locking the row, the second + # Example for find with a lock: Imagine two concurrent transactions: + # each will read person.visits == 2, add 1 to it, and save, resulting + # in two saves of person.visits = 3. By locking the row, the second # transaction has to wait until the first is finished; we get the - # expected person.visits == 4. + # expected person.visits == 4. + # # Person.transaction do # person = Person.find(1, :lock => true) # person.visits += 1 -- cgit v1.2.3 From bd57507e7fcbe4c388022f4258c3198d1d614f2b Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 22:02:07 +0200 Subject: added mention to Model.(first|last|all) in AR's find, and assorted tweaks --- activerecord/lib/active_record/base.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c78eb1984a..decc6b9b74 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -446,13 +446,17 @@ module ActiveRecord #:nodoc: class << self # Class methods # Find operates with four different retrieval approaches: # - # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). + # * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). # If no record can be found for all of the listed ids, then RecordNotFound will be raised. - # * Find first: This will return the first record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find last: This will return the last record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. + # * Find first - This will return the first record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use + # Model.find(:first, *args) or its shortcut Model.first(*args). + # * Find last - This will return the last record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, nil is returned. Use + # Model.find(:last, *args) or its shortcut Model.last(*args). + # * Find all - This will return all the records matched by the options used. + # If no records are found, an empty array is returned. Use + # Model.find(:all, *args) or its shortcut Model.all(*args). # # All approaches accept an options hash as their last parameter. The options are: # -- cgit v1.2.3 From c40c17c9864b3225573b682320179fd519184cf0 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 22:04:41 +0200 Subject: fixed-width font for nil --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index decc6b9b74..2bb855488f 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -452,7 +452,7 @@ module ActiveRecord #:nodoc: # conditions or merely an order. If no record can be matched, +nil+ is returned. Use # Model.find(:first, *args) or its shortcut Model.first(*args). # * Find last - This will return the last record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. Use + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use # Model.find(:last, *args) or its shortcut Model.last(*args). # * Find all - This will return all the records matched by the options used. # If no records are found, an empty array is returned. Use -- cgit v1.2.3 From aa4a7a298967f89a5812870962f8c858411eb7ab Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 18 May 2008 22:11:15 +0200 Subject: gsub("sql", "SQL") --- .../associations/has_many_through_association.rb | 2 +- activerecord/lib/active_record/base.rb | 17 ++++++++--------- .../connection_adapters/postgresql_adapter.rb | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index f683669615..ebcf462f2e 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -34,7 +34,7 @@ module ActiveRecord def count(*args) column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args) if @reflection.options[:uniq] - # This is needed because 'SELECT count(DISTINCT *)..' is not valid sql statement. + # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL statement. column_name = "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}" if column_name == :all options.merge!(:distinct => true) end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 2bb855488f..ccb35bd1ba 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -550,8 +550,7 @@ module ActiveRecord #:nodoc: find(:all, *args) end - # - # Executes a custom sql query against your database and returns all the results. The results will + # Executes a custom SQL query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call # this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product # object with the attributes you specified in the SQL query. @@ -560,13 +559,13 @@ module ActiveRecord #:nodoc: # SELECT will be attributes of the model, whether or not they are columns of the corresponding # table. # - # The +sql+ parameter is a full sql query as a string. It will be called as is, there will be + # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be # no database agnostic conversions performed. This should be a last resort because using, for example, # MySQL specific terms will lock you to using that particular database engine or require you to # change your call if you switch engines # # ==== Examples - # # A simple sql query spanning multiple tables + # # A simple SQL query spanning multiple tables # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id" # > [#"Ruby Meetup", "first_name"=>"Quentin"}>, ...] # @@ -1919,7 +1918,7 @@ module ActiveRecord #:nodoc: klass.base_class.name end - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a WHERE clause. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'" @@ -1935,7 +1934,7 @@ module ActiveRecord #:nodoc: end alias_method :sanitize_sql, :sanitize_sql_for_conditions - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a SET clause. # { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'" def sanitize_sql_for_assignment(assignments) @@ -1951,7 +1950,7 @@ module ActiveRecord #:nodoc: mapping.first.is_a?(Array) ? mapping : [mapping] end - # Accepts a hash of sql conditions and replaces those attributes + # Accepts a hash of SQL conditions and replaces those attributes # that correspond to a +composed_of+ relationship with their expanded # aggregate attribute values. # Given: @@ -2024,7 +2023,7 @@ module ActiveRecord #:nodoc: end # Accepts an array of conditions. The array has each value - # sanitized and interpolated into the sql statement. + # sanitized and interpolated into the SQL statement. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" def sanitize_sql_array(ary) statement, *values = ary @@ -2575,7 +2574,7 @@ module ActiveRecord #:nodoc: self.class.connection.quote(value, column) end - # Interpolate custom sql string in instance context. + # Interpolate custom SQL string in instance context. # Optional record argument is meant for custom insert_sql. def interpolate_sql(sql, record = nil) instance_eval("%@#{sql.gsub('@', '\@')}@") diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2ec2d80af4..7dbfbb41f6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -776,7 +776,7 @@ module ActiveRecord # Returns an ORDER BY clause for the passed order option. # # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the sql as a sub-select and ordering in that query. + # by wrapping the +sql+ string as a sub-select and ordering in that query. def add_order_by_for_association_limiting!(sql, options) #:nodoc: return sql if options[:order].blank? -- cgit v1.2.3 From ce63b2e5df22f4d80a90bc5b117c55044917d175 Mon Sep 17 00:00:00 2001 From: Cody Fauser Date: Mon, 19 May 2008 11:01:09 -0400 Subject: Markup inline code in ActiveRecord::Base docs --- activerecord/lib/active_record/base.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index ccb35bd1ba..6f9d5e53f5 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -200,7 +200,7 @@ module ActiveRecord #:nodoc: # # All column values are automatically available through basic accessors on the Active Record object, but sometimes you # want to specialize this behavior. This can be done by overwriting the default accessors (using the same - # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. + # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. # Example: # # class Song < ActiveRecord::Base @@ -215,8 +215,8 @@ module ActiveRecord #:nodoc: # end # end # - # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and - # read_attribute(:attribute) as a shorter form. + # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and + # read_attribute(:attribute) as a shorter form. # # == Attribute query methods # @@ -236,7 +236,7 @@ module ActiveRecord #:nodoc: # # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. # That can be done by using the _before_type_cast accessors that all attributes have. For example, if your Account model - # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. + # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. # # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you @@ -245,8 +245,8 @@ module ActiveRecord #:nodoc: # == Dynamic attribute-based finders # # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by - # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, - # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing + # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, + # Person.find_all_by_last_name, and Payment.find_by_transaction_id. So instead of writing # Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). # And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name). # @@ -255,8 +255,8 @@ module ActiveRecord #:nodoc: # Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do # Person.find_by_user_name_and_password(user_name, password). # - # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount - # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is + # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount + # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is # actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on"). # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with @@ -316,8 +316,8 @@ module ActiveRecord #:nodoc: # class Client < Company; end # class PriorityClient < Client; end # - # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then - # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. + # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then + # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. # # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. @@ -329,8 +329,8 @@ module ActiveRecord #:nodoc: # # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. - # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection - # and Course *and all its subclasses* will use this connection instead. + # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection + # and Course and all of its subclasses will use this connection instead. # # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool. -- cgit v1.2.3 From abc42927052969aa878b6f5f83d821f5771fc8c1 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 19:34:07 +0200 Subject: gsub("yaml", "YAML") --- .../connection_adapters/abstract/connection_specification.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index 34627dfaf9..2a8807fb78 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -193,7 +193,7 @@ module ActiveRecord # :database => "path/to/dbfile" # ) # - # Also accepts keys as strings (for parsing from yaml for example): + # Also accepts keys as strings (for parsing from YAML for example): # # ActiveRecord::Base.establish_connection( # "adapter" => "sqlite", -- cgit v1.2.3 From 78596747bae784196da7a184a33ef5d1b2a94107 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 21:31:18 +0200 Subject: #method vs +method+ in Active Record --- activerecord/lib/active_record/aggregations.rb | 2 +- activerecord/lib/active_record/base.rb | 6 +++--- activerecord/lib/active_record/calculations.rb | 8 ++++---- activerecord/lib/active_record/callbacks.rb | 2 +- .../connection_adapters/abstract/database_statements.rb | 4 ++-- .../connection_adapters/abstract/schema_definitions.rb | 4 ++-- .../connection_adapters/abstract/schema_statements.rb | 2 +- activerecord/lib/active_record/locking/optimistic.rb | 14 +++++++------- activerecord/lib/active_record/migration.rb | 2 +- activerecord/lib/active_record/observer.rb | 2 +- activerecord/lib/active_record/schema.rb | 4 ++-- .../lib/active_record/serializers/xml_serializer.rb | 6 +++--- activerecord/lib/active_record/validations.rb | 4 ++-- 13 files changed, 30 insertions(+), 30 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 61446cde36..a8c8c7f3dc 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -99,7 +99,7 @@ module ActiveRecord # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. # # It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after - # creation. Create a new +Money+ object with the new value instead. This is exemplified by the Money#exchanged_to method that + # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that # returns a new value object instead of changing its own values. Active Record won't persist value objects that have been # changed through means other than the writer method. # diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 6f9d5e53f5..35f18e9fa0 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1277,7 +1277,7 @@ module ActiveRecord #:nodoc: class_of_active_record_descendant(self) end - # Set this to true if this is an abstract class (see #abstract_class?). + # Set this to true if this is an abstract class (see abstract_class?). attr_accessor :abstract_class # Returns whether this class is a base AR class. If A is a base class and @@ -1724,8 +1724,8 @@ module ActiveRecord #:nodoc: end - # Defines an "attribute" method (like #inheritance_column or - # #table_name). A new (class) method will be created with the + # Defines an "attribute" method (like +inheritance_column+ or + # +table_name+). A new (class) method will be created with the # given name. If a value is specified, the new method will # return that value (as a string). Otherwise, the given block # will be used to compute the value of the method. diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 3c5caefe3b..fec9bee38f 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -46,28 +46,28 @@ module ActiveRecord calculate(:count, *construct_count_options_from_args(*args)) end - # Calculates the average value on a given column. The value is returned as a float. See #calculate for examples with options. + # Calculates the average value on a given column. The value is returned as a float. See +calculate+ for examples with options. # # Person.average('age') def average(column_name, options = {}) calculate(:avg, column_name, options) end - # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.minimum('age') def minimum(column_name, options = {}) calculate(:min, column_name, options) end - # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.maximum('age') def maximum(column_name, options = {}) calculate(:max, column_name, options) end - # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.sum('age') def sum(column_name, options = {}) diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index a469af682b..41ec5c5e61 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -161,7 +161,7 @@ module ActiveRecord # == before_validation* returning statements # # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and Base#save will return +false+. - # If Base#save! is called it will raise a +RecordNotSaved+ exception. + # If Base#save! is called it will raise a RecordNotSaved exception. # Nothing will be appended to the errors object. # # == Canceling callbacks diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 589acd3945..16d405d3bd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -29,7 +29,7 @@ module ActiveRecord end # Returns an array of arrays containing the field values. - # Order is the same as that returned by #columns. + # Order is the same as that returned by +columns+. def select_rows(sql, name = nil) raise NotImplementedError, "select_rows is an abstract method" end @@ -93,7 +93,7 @@ module ActiveRecord # done if the transaction block raises an exception or returns false. def rollback_db_transaction() end - # Alias for #add_limit_offset!. + # Alias for add_limit_offset!. def add_limit!(sql, options) add_limit_offset!(sql, options) if options end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index fdb18b234c..18f1175f5f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -270,7 +270,7 @@ module ActiveRecord end # Represents a SQL table in an abstract way. - # Columns are stored as a ColumnDefinition in the #columns attribute. + # Columns are stored as a ColumnDefinition in the +columns+ attribute. class TableDefinition attr_accessor :columns @@ -395,7 +395,7 @@ module ActiveRecord # end # # There's a short-hand method for each of the type values declared at the top. And then there's - # TableDefinition#timestamps that'll add created_at and updated_at as datetimes. + # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type # column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index ac24e920fe..01e128f02f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -32,7 +32,7 @@ module ActiveRecord def columns(table_name, name = nil) end # Creates a new table - # There are two ways to work with #create_table. You can use the block + # There are two ways to work with +create_table+. You can use the block # form or the regular form, like this: # # === Block form diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 65f88cfdc7..c66034d18b 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -107,20 +107,20 @@ module ActiveRecord end # Is optimistic locking enabled for this table? Returns true if the - # #lock_optimistically flag is set to true (which it is, by default) - # and the table includes the #locking_column column (defaults to - # lock_version). + # +lock_optimistically+ flag is set to true (which it is, by default) + # and the table includes the +locking_column+ column (defaults to + # +lock_version+). def locking_enabled? lock_optimistically && columns_hash[locking_column] end - # Set the column to use for optimistic locking. Defaults to lock_version. + # Set the column to use for optimistic locking. Defaults to +lock_version+. def set_locking_column(value = nil, &block) define_attr_method :locking_column, value, &block value end - # The version column used for optimistic locking. Defaults to lock_version. + # The version column used for optimistic locking. Defaults to +lock_version+. def locking_column reset_locking_column end @@ -130,12 +130,12 @@ module ActiveRecord connection.quote_column_name(locking_column) end - # Reset the column used for optimistic locking back to the lock_version default. + # Reset the column used for optimistic locking back to the +lock_version+ default. def reset_locking_column set_locking_column DEFAULT_LOCKING_COLUMN end - # make sure the lock version column gets updated when counters are + # Make sure the lock version column gets updated when counters are # updated. def update_counters_with_lock(id, counters) counters = counters.merge(locking_column => 1) if locking_enabled? diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5cc9f4e197..df512a996a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -208,7 +208,7 @@ module ActiveRecord # # You can quiet them down by setting ActiveRecord::Migration.verbose = false. # - # You can also insert your own messages and benchmarks by using the #say_with_time + # You can also insert your own messages and benchmarks by using the +say_with_time+ # method: # # def self.up diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 2b0728fc25..45e4d5b704 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -19,7 +19,7 @@ module ActiveRecord # # Same as above, just using explicit class references # ActiveRecord::Base.observers = Cacher, GarbageCollector # - # Note: Setting this does not instantiate the observers yet. #instantiate_observers is + # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is # called during startup, and before each development request. def observers=(*observers) @observers = observers.flatten diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index d6b254fcf9..8a32cf1ca2 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -30,8 +30,8 @@ module ActiveRecord # Eval the given block. All methods available to the current connection # adapter are available within the block, so you can easily use the - # database definition DSL to build up your schema (#create_table, - # #add_index, etc.). + # database definition DSL to build up your schema (+create_table+, + # +add_index+, etc.). # # The +info+ hash is optional, and if given is used to define metadata # about the current schema (currently, only the schema's version): diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index 2d0887ecf0..d171b742f5 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -273,14 +273,14 @@ module ActiveRecord #:nodoc: end # There is a significant speed improvement if the value - # does not need to be escaped, as #tag! escapes all values + # does not need to be escaped, as tag! escapes all values # to ensure that valid XML is generated. For known binary # values, it is at least an order of magnitude faster to # Base64 encode binary values and directly put them in the # output XML than to pass the original value or the Base64 - # encoded value to the #tag! method. It definitely makes + # encoded value to the tag! method. It definitely makes # no sense to Base64 encode the value and then give it to - # #tag!, since that just adds additional overhead. + # tag!, since that just adds additional overhead. def needs_encoding? ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type) end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b3a75121ed..0e150bddb2 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,7 +301,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the #validate instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldly and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: @@ -326,7 +326,7 @@ module ActiveRecord # end # end # - # This usage applies to #validate_on_create and #validate_on_update as well. + # This usage applies to +validate_on_create+ and +validate_on_update+ as well. # Validates each attribute against a block. # -- cgit v1.2.3 From ecba27c9701698a70eb7a7af1a995bb1d089949c Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 19 May 2008 22:11:04 +0200 Subject: revised markup in fixtures.rb --- activerecord/lib/active_record/fixtures.rb | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index ac06cdbe43..796ee13d3d 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -33,8 +33,8 @@ end # # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed # by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: -# "/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this: +# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: +# /test/fixtures/web_sites.yml). The format of a YAML fixture file looks like this: # # rubyonrails: # id: 1 @@ -67,7 +67,8 @@ end # = CSV fixtures # # Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored -# in a single file, but instead end with the .csv file extension (Rails example: "/test/fixtures/web_sites.csv") +# in a single file, but instead end with the .csv file extension +# (Rails example: /test/fixtures/web_sites.csv). # # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised @@ -93,11 +94,11 @@ end # 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 # appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures// -- like /test/fixtures/web_sites/ for the WebSite -# model). +# put your files in /test/fixtures// -- +# like /test/fixtures/web_sites/ for the WebSite model). # # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without -# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the +# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the # above example might look like: # # web_sites/google @@ -138,20 +139,20 @@ end # # 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 -# @web_sites. This is where the "fixture name" comes into play. +# @web_sites. This is where the "fixture name" comes into play. # -# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. -# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: +# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. +# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: # # # 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 # end # -# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return -# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded -# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual -# fixtures available as instance variables @web_site_1 and @web_site_2. +# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return +# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded +# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual +# fixtures available as instance variables @web_site_1 and @web_site_2. # # If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options. # @@ -184,7 +185,7 @@ end # # This will create 1000 very simple YAML fixtures. # -# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. +# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell. @@ -307,7 +308,7 @@ end # Pow! All is made clear. ActiveRecord reflects on the fixture's model class, # finds all the +belongs_to+ associations, and allows you to specify # a target *label* for the *association* (monkey: george) rather than -# a target *id* for the *FK* (monkey_id: 1). +# a target *id* for the *FK* (monkey_id: 1). # # ==== Polymorphic belongs_to # -- cgit v1.2.3 From a34cc42a2c29928bcdc75b700343f978a9524e58 Mon Sep 17 00:00:00 2001 From: Nate Wiger Date: Mon, 19 May 2008 11:42:37 -0700 Subject: - Updated tzinfo to use Rational() instead of Rational.new! due to "private method new!" in Ruby 1.9 - Added ^object_id$ as ignore pattern to fixing "redefining object_id" issue in Ruby 1.9 Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/associations/association_proxy.rb | 2 +- activerecord/lib/active_record/named_scope.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 68503a3c40..ec16af3897 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -49,7 +49,7 @@ module ActiveRecord alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend delegate :to_param, :to => :proxy_target - instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ } + instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index d43ebefc3b..06edaed3d5 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,7 @@ module ActiveRecord class Scope attr_reader :proxy_scope, :proxy_options - [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } delegate :scopes, :with_scope, :to => :proxy_scope def initialize(proxy_scope, options, &block) @@ -136,4 +136,4 @@ module ActiveRecord end end end -end \ No newline at end of file +end -- cgit v1.2.3 From 1b0128c5413ace12dee45e9db328cff866a5bb06 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 19:12:25 -0700 Subject: Don't rely on association proxying object_id. [#225 state:resolved] --- activerecord/test/cases/associations/belongs_to_associations_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index b8ec9117af..4382ba17ef 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -54,8 +54,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase original_proxy = citibank.firm citibank.firm = another_firm - assert_equal first_firm.object_id, original_proxy.object_id - assert_equal another_firm.object_id, citibank.firm.object_id + assert_equal first_firm.object_id, original_proxy.target.object_id + assert_equal another_firm.object_id, citibank.firm.target.object_id end def test_creating_the_belonging_object -- cgit v1.2.3 From 089251581137b041828a7e6dcbf75ecbef55b4a3 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 20 May 2008 11:10:38 +0100 Subject: Ensure add_column gives valid error for sqlite. [Gunnar Wolf, Pratik] [#197 state:resolved] SQLite#add_column executes "VACUUM", which fails if inside a live transaction. This patch ensures a valid exception is raised if add_column is executed within a live transaction for sqlite adapter. --- .../connection_adapters/sqlite_adapter.rb | 4 ++++ activerecord/test/cases/transactions_test.rb | 26 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 8abbc6d0a4..51cfd10e5c 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -214,6 +214,10 @@ module ActiveRecord end def add_column(table_name, column_name, type, options = {}) #:nodoc: + if @connection.respond_to?(:transaction_active?) && @connection.transaction_active? + raise StatementInvalid, 'Cannot add columns to a SQLite database while inside a transaction' + end + super(table_name, column_name, type, options) # See last paragraph on http://www.sqlite.org/lang_altertable.html execute "VACUUM" diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 63f04e3014..06a76eacc3 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -179,6 +179,32 @@ class TransactionTest < ActiveRecord::TestCase end end + def test_sqlite_add_column_in_transaction_raises_statement_invalid + return true unless current_adapter?(:SQLite3Adapter, :SQLiteAdapter) + + # Test first if column creation/deletion works correctly when no + # transaction is in place. + # + # We go back to the connection for the column queries because + # Topic.columns is cached and won't report changes to the DB + + assert_nothing_raised do + Topic.reset_column_information + Topic.connection.add_column('topics', 'stuff', :string) + assert Topic.column_names.include?('stuff') + + Topic.reset_column_information + Topic.connection.remove_column('topics', 'stuff') + assert !Topic.column_names.include?('stuff') + end + + # Test now inside a transaction: add_column should raise a StatementInvalid + Topic.transaction do + assert_raises(ActiveRecord::StatementInvalid) { Topic.connection.add_column('topics', 'stuff', :string) } + raise ActiveRecord::Rollback + end + end + private def add_exception_raising_after_save_callback_to_topic Topic.class_eval { def after_save() raise "Make the transaction rollback" end } -- cgit v1.2.3 From 633e9b4c5656a18dc5cb1eff95d47fc1824b2c27 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 20 May 2008 12:37:35 +0200 Subject: revised conventions in time zone related docs --- activerecord/lib/active_record/attribute_methods.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index d753778d52..09346bec5c 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -162,8 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. - # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -176,7 +176,7 @@ module ActiveRecord evaluate_attribute_method attr_name, method_body end - # Define an attribute ? method. + # Defines a predicate method attr_name?. def define_question_method(attr_name) evaluate_attribute_method attr_name, "def #{attr_name}?; query_attribute('#{attr_name}'); end", "#{attr_name}?" end @@ -185,7 +185,7 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV -- cgit v1.2.3 From 73c59638549686fccc749ffd3ac53cb533c5fd61 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Tue, 20 May 2008 12:11:25 +0100 Subject: Add first/last methods to associations/named_scope. [#226 state:resolved] Signed-off-by: Pratik Naik --- activerecord/CHANGELOG | 2 + .../associations/association_collection.rb | 25 +++++++- activerecord/lib/active_record/named_scope.rb | 24 +++++++- .../has_and_belongs_to_many_associations_test.rb | 2 + .../associations/has_many_associations_test.rb | 66 ++++++++++++++++++++++ .../test/cases/associations/join_model_test.rb | 2 + activerecord/test/cases/associations_test.rb | 4 +- activerecord/test/cases/named_scope_test.rb | 28 +++++++++ 8 files changed, 149 insertions(+), 4 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index cd526a52a7..78082665a4 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,3 +1,5 @@ +* Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] + *2.1.0 RC1 (May 11th, 2008)* * Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung] diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 7e47bf7bdf..2d3750e107 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -48,6 +48,26 @@ module ActiveRecord end end + # fetch first using SQL if possible + def first(*args) + if fetch_first_or_last_using_find? args + find(:first, *args) + else + load_target unless loaded? + @target.first(*args) + end + end + + # fetch last using SQL if possible + def last(*args) + if fetch_first_or_last_using_find? args + find(:last, *args) + else + load_target unless loaded? + @target.last(*args) + end + end + def to_ary load_target @target.to_ary @@ -330,7 +350,10 @@ module ActiveRecord raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end end - + + def fetch_first_or_last_using_find?(args) + args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || !@target.blank? || args.first.kind_of?(Integer)) + end end end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 06edaed3d5..c7cf1731c1 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,13 @@ module ActiveRecord class Scope attr_reader :proxy_scope, :proxy_options - [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + + [].methods.each do |m| + unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last)/ + delegate m, :to => :proxy_found + end + end + delegate :scopes, :with_scope, :to => :proxy_scope def initialize(proxy_scope, options, &block) @@ -115,6 +121,22 @@ module ActiveRecord load_found; self end + def first(*args) + if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) + proxy_found.first(*args) + else + find(:first, *args) + end + end + + def last(*args) + if args.first.kind_of?(Integer) || (@found && !args.first.kind_of?(Hash)) + proxy_found.last(*args) + else + find(:last, *args) + end + end + protected def proxy_found @found || load_found diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 64565141f9..294b993c55 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -401,6 +401,8 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase def test_include_uses_array_include_after_loaded project = projects(:active_record) + project.developers.class # force load target + developer = project.developers.first assert_no_queries do diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 9e26e2ad58..53b55022eb 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -818,6 +818,8 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_include_uses_array_include_after_loaded firm = companies(:first_firm) + firm.clients.class # force load target + client = firm.clients.first assert_no_queries do @@ -857,4 +859,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert ! firm.clients.include?(client) end + def test_calling_first_or_last_on_association_should_not_load_association + firm = companies(:first_firm) + firm.clients.first + firm.clients.last + assert !firm.clients.loaded? + end + + def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query + firm = companies(:first_firm) + firm.clients.class # force load target + assert firm.clients.loaded? + + assert_no_queries do + firm.clients.first + assert_equal 2, firm.clients.first(2).size + firm.clients.last + assert_equal 2, firm.clients.last(2).size + end + end + + def test_calling_first_or_last_on_existing_record_with_build_should_load_association + firm = companies(:first_firm) + firm.clients.build(:name => 'Foo') + assert !firm.clients.loaded? + + assert_queries 1 do + firm.clients.first + firm.clients.last + end + + assert firm.clients.loaded? + end + + def test_calling_first_or_last_on_new_record_should_not_run_queries + firm = Firm.new + + assert_no_queries do + firm.clients.first + firm.clients.last + end + end + + def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query + firm = companies(:first_firm) + firm.clients.class # force load target + + assert_queries 2 do + assert firm.clients.loaded? + firm.clients.first(:order => 'name') + firm.clients.last(:order => 'name') + end + end + + def test_calling_first_or_last_with_integer_on_association_should_load_association + firm = companies(:first_firm) + + assert_queries 1 do + firm.clients.first(2) + firm.clients.last(2) + end + + assert firm.clients.loaded? + end + end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 952ea63706..9e79d9c8a1 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -664,6 +664,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_has_many_through_include_uses_array_include_after_loaded david = authors(:david) + david.categories.class # force load target + category = david.categories.first assert_no_queries do diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index d8fe98bf57..3ad8c608e0 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -99,12 +99,12 @@ class AssociationProxyTest < ActiveRecord::TestCase david = authors(:david) assert_equal david, david.posts.proxy_owner assert_equal david.class.reflect_on_association(:posts), david.posts.proxy_reflection - david.posts.first # force load target + david.posts.class # force load target assert_equal david.posts, david.posts.proxy_target assert_equal david, david.posts_with_extension.testing_proxy_owner assert_equal david.class.reflect_on_association(:posts_with_extension), david.posts_with_extension.testing_proxy_reflection - david.posts_with_extension.first # force load target + david.posts_with_extension.class # force load target assert_equal david.posts_with_extension, david.posts_with_extension.testing_proxy_target end diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 9730f93579..8f2fc53d67 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -118,4 +118,32 @@ class NamedScopeTest < ActiveRecord::TestCase assert_equal expected_proxy_options, Topic.approved.proxy_options end + def test_first_and_last_should_support_find_options + assert_equal Topic.base.first(:order => 'title'), Topic.base.find(:first, :order => 'title') + assert_equal Topic.base.last(:order => 'title'), Topic.base.find(:last, :order => 'title') + end + + def test_first_and_last_should_allow_integers_for_limit + assert_equal Topic.base.first(2), Topic.base.to_a.first(2) + assert_equal Topic.base.last(2), Topic.base.to_a.last(2) + end + + def test_first_and_last_should_not_use_query_when_results_are_loaded + topics = Topic.base + topics.reload # force load + assert_no_queries do + topics.first + topics.last + end + end + + def test_first_and_last_find_options_should_use_query_when_results_are_loaded + topics = Topic.base + topics.reload # force load + assert_queries(2) do + topics.first(:order => 'title') + topics.last(:order => 'title') + end + end + end -- cgit v1.2.3 From 964392f57ad6408718458f229270b4082799d233 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 20 May 2008 16:56:22 +0200 Subject: revised docs of first/last in AR base and association collection --- .../lib/active_record/associations/association_collection.rb | 4 ++-- activerecord/lib/active_record/base.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 2d3750e107..83b1fedb28 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -48,7 +48,7 @@ module ActiveRecord end end - # fetch first using SQL if possible + # Fetches the first one using SQL if possible. def first(*args) if fetch_first_or_last_using_find? args find(:first, *args) @@ -58,7 +58,7 @@ module ActiveRecord end end - # fetch last using SQL if possible + # Fetches the last one using SQL if possible. def last(*args) if fetch_first_or_last_using_find? args find(:last, *args) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 35f18e9fa0..ea971a4c07 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -532,14 +532,14 @@ module ActiveRecord #:nodoc: end end - # This is an alias for find(:first). You can pass in all the same arguments to this method as you can - # to find(:first) + # A convenience wrapper for find(:first, *args). You can pass in all the + # same arguments to this method as you can to find(:first). def first(*args) find(:first, *args) end - # This is an alias for find(:last). You can pass in all the same arguments to this method as you can - # to find(:last) + # A convenience wrapper for find(:last, *args). You can pass in all the + # same arguments to this method as you can to find(:last). def last(*args) find(:last, *args) end -- cgit v1.2.3 From 281edce6db8accc7d4a0e9ab01892631d9d0ebc3 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 20 May 2008 20:50:46 +0100 Subject: Ensure nil to '' doesn't get recorded by dirty for nullable integer columns. [#150 state:resolved] [Jason Dew, Pratik] --- activerecord/lib/active_record/dirty.rb | 24 ++++++++++++++++-------- activerecord/test/cases/dirty_test.rb | 10 ++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 6034963811..49f1204fa1 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -117,14 +117,7 @@ module ActiveRecord # The attribute already has an unsaved change. unless changed_attributes.include?(attr) old = clone_attribute_value(:read_attribute, attr) - - # Remember the original value if it's different. - typecasted = if column = column_for_attribute(attr) - column.type_cast(value) - else - value - end - changed_attributes[attr] = old unless old == typecasted + changed_attributes[attr] = old if field_changed?(attr, old, value) end # Carry on. @@ -138,5 +131,20 @@ module ActiveRecord update_without_dirty end end + + def field_changed?(attr, old, value) + if column = column_for_attribute(attr) + if column.type == :integer && column.null && old.nil? + # For nullable integer columns, NULL gets stored in database for blank (i.e. '') values. + # Hence we don't record it as a change if the value changes from nil to ''. + value = nil if value.blank? + else + value = column.type_cast(value) + end + end + + old != value + end + end end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 1266eb5036..62178977f9 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -44,6 +44,16 @@ class DirtyTest < ActiveRecord::TestCase assert_nil pirate.catchphrase_change end + def test_nullable_integer_not_marked_as_changed_if_new_value_is_blank + pirate = Pirate.new + + ["", nil].each do |value| + pirate.parrot_id = value + assert !pirate.parrot_id_changed? + assert_nil pirate.parrot_id_change + end + end + def test_object_should_be_changed_if_any_attribute_is_changed pirate = Pirate.new assert !pirate.changed? -- cgit v1.2.3 From 19d7b1d22bd68af00244ddc3e1f35cec187e9120 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 21 May 2008 10:46:28 +0100 Subject: Verbose ActiveRecord::AssociationTypeMismatch exception message. [#189 state:resolved] --- activerecord/lib/active_record/associations/association_proxy.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index ec16af3897..11c64243a2 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -210,7 +210,8 @@ module ActiveRecord def raise_on_type_mismatch(record) unless record.is_a?(@reflection.klass) - raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.klass} expected, got #{record.class}" + message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})" + raise ActiveRecord::AssociationTypeMismatch, message end end -- cgit v1.2.3 From fb1858d5ecd808f9abdcb2f56ee61702d5076bf6 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 13:53:11 +0200 Subject: revised font of constants in Active Record --- activerecord/lib/active_record/aggregations.rb | 18 +++++++++--------- activerecord/lib/active_record/associations.rb | 2 +- activerecord/lib/active_record/base.rb | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index a8c8c7f3dc..a5d3a50ef1 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -92,19 +92,19 @@ module ActiveRecord # # == Writing value objects # - # Value objects are immutable and interchangeable objects that represent a given value, such as a +Money+ object representing - # $5. Two +Money+ objects both representing $5 should be equal (through methods such as == and <=> from +Comparable+ if ranking - # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as +Customer+ can + # Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing + # $5. Two Money objects both representing $5 should be equal (through methods such as == and <=> from Comparable if ranking + # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can # easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or - # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. + # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. # - # It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after - # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that + # It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after + # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that # returns a new value object instead of changing its own values. Active Record won't persist value objects that have been # changed through means other than the writer method. # # The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to - # change it afterwards will result in a ActiveSupport::FrozenObjectError. + # change it afterwards will result in a ActiveSupport::FrozenObjectError. # # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects # immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable @@ -123,8 +123,8 @@ module ActiveRecord # # Options are: # * :class_name - specify the class name of the association. Use it only if that name can't be inferred - # from the part id. So composed_of :address will by default be linked to the +Address+ class, but - # if the real class name is +CompanyAddress+, you'll have to specify it with this option. + # from the part id. So composed_of :address will by default be linked to the Address class, but + # if the real class name is CompanyAddress, you'll have to specify it with this option. # * :mapping - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name # to a constructor parameter on the value class. # * :allow_nil - specifies that the aggregate object will not be instantiated when all mapped diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index ce3d273a42..31096ccd71 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -950,7 +950,7 @@ module ActiveRecord # # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through # +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as - # +ReadOnly+ (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any + # readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any # associations with attributes to a real join model (see introduction). # # Adds the following methods for retrieval and query: diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index ea971a4c07..457f1e841f 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -70,7 +70,7 @@ module ActiveRecord #:nodoc: # instantiation, for example, when two users edit the same wiki page and one starts editing and saves # the page before the other. # - # Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc. + # Read more about optimistic locking in ActiveRecord::Locking module RDoc. class StaleObjectError < ActiveRecordError end @@ -407,7 +407,7 @@ module ActiveRecord #:nodoc: @@table_name_suffix = "" # Indicates whether table names should be the pluralized versions of the corresponding class names. - # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+. + # If true, the default table name for a Product class will be +products+. If false, it would just be +product+. # See table_name for the full rules on table/class naming. This is true, by default. cattr_accessor :pluralize_table_names, :instance_writer => false @@pluralize_table_names = true @@ -943,7 +943,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or +SerializationTypeMismatch+ will be raised. + # class on retrieval or SerializationTypeMismatch will be raised. # # ==== Attributes # -- cgit v1.2.3 From 262d23d763c05bbe5f433a99cb9f02e48a8cdd4a Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Wed, 21 May 2008 08:27:20 -0700 Subject: ActiveRecord::Base#reload should clear dirty attributes. [#231 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/dirty.rb | 8 ++++++++ activerecord/test/cases/dirty_test.rb | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 49f1204fa1..8fdc763292 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -40,6 +40,7 @@ module ActiveRecord base.alias_method_chain :save, :dirty base.alias_method_chain :save!, :dirty base.alias_method_chain :update, :dirty + base.alias_method_chain :reload, :dirty base.superclass_delegating_accessor :partial_updates base.partial_updates = false @@ -84,6 +85,13 @@ module ActiveRecord status end + # reload the record and clears changed attributes. + def reload_with_dirty(*args) #:nodoc: + record = reload_without_dirty(*args) + changed_attributes.clear + record + end + private # Map of change attr => original value. def changed_attributes diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 62178977f9..c011ffaf57 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -137,6 +137,14 @@ class DirtyTest < ActiveRecord::TestCase check_pirate_after_save_failure(pirate) end + def test_reload_should_clear_changed_attributes + pirate = Pirate.create!(:catchphrase => "shiver me timbers") + pirate.catchphrase = "*hic*" + assert pirate.changed? + pirate.reload + assert !pirate.changed? + end + private def with_partial_updates(klass, on = true) old = klass.partial_updates? -- cgit v1.2.3 From 49738f000b9c7e2902cf17e5e13943e5015f91b8 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 22:34:18 +0200 Subject: gsub("ActiveRecord", "Active Record") --- activerecord/lib/active_record/associations.rb | 6 ++--- .../lib/active_record/attribute_methods.rb | 2 +- activerecord/lib/active_record/base.rb | 30 +++++++++++----------- activerecord/lib/active_record/fixtures.rb | 18 ++++++------- activerecord/lib/active_record/migration.rb | 2 +- activerecord/lib/active_record/named_scope.rb | 2 +- activerecord/lib/active_record/observer.rb | 2 +- activerecord/lib/active_record/schema_dumper.rb | 2 +- activerecord/lib/active_record/transactions.rb | 4 +-- 9 files changed, 34 insertions(+), 34 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 31096ccd71..ec4c497d37 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -155,7 +155,7 @@ module ActiveRecord # # == Cardinality and associations # - # ActiveRecord associations can be used to describe one-to-one, one-to-many and many-to-many + # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many # relationships between models. Each model uses an association to describe its role in # the relation. The +belongs_to+ association is always used in the model that has # the foreign key. @@ -520,13 +520,13 @@ module ActiveRecord # # will execute one query to load the addresses and load the addressables with one query per addressable type. # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of - # addressable types to load is determined on the back of the addresses loaded. This is not supported if ActiveRecord has to fallback + # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # - # ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, + # Active Record uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended # for any more successive uses of the table name. # diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 09346bec5c..fab16a4446 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -94,7 +94,7 @@ module ActiveRecord end # Checks whether the method is defined in the model or any of its subclasses - # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # that also derive from Active Record. Raises DangerousAttributeError if the # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 457f1e841f..dab1fd7ee8 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2,7 +2,7 @@ require 'yaml' require 'set' module ActiveRecord #:nodoc: - # Generic ActiveRecord exception class. + # Generic Active Record exception class. class ActiveRecordError < StandardError end @@ -30,19 +30,19 @@ module ActiveRecord #:nodoc: class SerializationTypeMismatch < ActiveRecordError end - # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). + # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). class AdapterNotSpecified < ActiveRecordError end - # Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically. + # Raised when Active Record cannot find database adapter specified in config/database.yml or programmatically. class AdapterNotFound < ActiveRecordError end - # Raised when connection to the database could not been established (for example when connection= is given a nil object). + # Raised when connection to the database could not been established (for example when connection= is given a nil object). class ConnectionNotEstablished < ActiveRecordError end - # Raised when ActiveRecord cannot find record by given id or set of ids. + # Raised when Active Record cannot find record by given id or set of ids. class RecordNotFound < ActiveRecordError end @@ -83,12 +83,12 @@ module ActiveRecord #:nodoc: class ReadOnlyRecord < ActiveRecordError end - # Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations. + # Used by Active Record transaction mechanism to distinguish rollback from other exceptional situations. # You can use it to roll your transaction back explicitly in the block passed to +transaction+ method. class Rollback < ActiveRecordError end - # Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods). + # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). class DangerousAttributeError < ActiveRecordError end @@ -966,7 +966,7 @@ module ActiveRecord #:nodoc: # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending - # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used + # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. # @@ -985,8 +985,8 @@ module ActiveRecord #:nodoc: # file class table_name # invoice/lineitem.rb Invoice::Lineitem lineitems # - # Additionally, the class-level table_name_prefix is prepended and the - # table_name_suffix is appended. So if you have "myapp_" as a prefix, + # Additionally, the class-level +table_name_prefix+ is prepended and the + # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix, # the table name guess for an Invoice class becomes "myapp_invoices". # Invoice::Lineitem becomes "myapp_invoice_lineitems". # @@ -1902,7 +1902,7 @@ module ActiveRecord #:nodoc: end end - # Returns the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the class descending directly from Active Record in the inheritance hierarchy. def class_of_active_record_descendant(klass) if klass.superclass == Base || klass.superclass.abstract_class? klass @@ -1913,7 +1913,7 @@ module ActiveRecord #:nodoc: end end - # Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the name of the class descending directly from Active Record in the inheritance hierarchy. def class_name_of_active_record_descendant(klass) #:nodoc: klass.base_class.name end @@ -2500,9 +2500,9 @@ module ActiveRecord #:nodoc: id end - # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord descendent. - # Considering the hierarchy Reply < Message < ActiveRecord, this makes it possible to do Reply.new without having to - # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the + # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendent. + # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to + # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 796ee13d3d..c4cbe5d52f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -258,7 +258,7 @@ end # reginald: # generated id: 324201669 # name: Reginald the Pirate # -# ActiveRecord looks at the fixture's model class, discovers the correct +# Active Record looks at the fixture's model class, discovers the correct # primary key, and generates it right before inserting the fixture # into the database. # @@ -268,7 +268,7 @@ end # == Label references for associations (belongs_to, has_one, has_many) # # Specifying foreign keys in fixtures can be very fragile, not to -# mention difficult to read. Since ActiveRecord can figure out the ID of +# mention difficult to read. Since Active Record can figure out the ID of # any fixture from its label, you can specify FK's by label instead of ID. # # === belongs_to @@ -305,7 +305,7 @@ end # name: George the Monkey # pirate: reginald # -# Pow! All is made clear. ActiveRecord reflects on the fixture's model class, +# Pow! All is made clear. Active Record reflects on the fixture's model class, # finds all the +belongs_to+ associations, and allows you to specify # a target *label* for the *association* (monkey: george) rather than # a target *id* for the *FK* (monkey_id: 1). @@ -313,7 +313,7 @@ end # ==== Polymorphic belongs_to # # Supporting polymorphic relationships is a little bit more complicated, since -# ActiveRecord needs to know what type your association is pointing at. Something +# Active Record needs to know what type your association is pointing at. Something # like this should look familiar: # # ### in fruit.rb @@ -333,7 +333,7 @@ end # apple: # eater: george (Monkey) # -# Just provide the polymorphic target type and ActiveRecord will take care of the rest. +# Just provide the polymorphic target type and Active Record will take care of the rest. # # === has_and_belongs_to_many # @@ -396,15 +396,15 @@ end # # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits # on George's fixture, but we could've just as easily specified a list -# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on +# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on # the fixture's model class and discovers the +has_and_belongs_to_many+ # associations. # # == Autofilled timestamp columns # -# If your table/model specifies any of ActiveRecord's -# standard timestamp columns (created_at, created_on, updated_at, updated_on), -# they will automatically be set to Time.now. +# If your table/model specifies any of Active Record's +# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+), +# they will automatically be set to Time.now. # # If you've set specific values, they'll be left alone. # diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index df512a996a..b47b01e99a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -377,7 +377,7 @@ module ActiveRecord end def proper_table_name(name) - # Use the ActiveRecord objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string + # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index c7cf1731c1..62eecbf9be 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -41,7 +41,7 @@ module ActiveRecord # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). # - # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to + # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to # has_many associations. If, # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 45e4d5b704..6e55e36b7d 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -30,7 +30,7 @@ module ActiveRecord @observers ||= [] end - # Instantiate the global ActiveRecord observers + # Instantiate the global Active Record observers. def instantiate_observers return if @observers.blank? @observers.each do |observer| diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 826662d3ee..b90ed88c6b 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -38,7 +38,7 @@ module ActiveRecord stream.puts <
Balance record is transactionally saved even -- cgit v1.2.3 From 066b56149c56b2ea0ebec4c92c9d825edbfb6607 Mon Sep 17 00:00:00 2001 From: Joshua French Date: Wed, 21 May 2008 15:38:58 -0500 Subject: Revised example conventions in active_record/base --- activerecord/lib/active_record/base.rb | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 457f1e841f..0eb55391be 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -458,7 +458,9 @@ module ActiveRecord #:nodoc: # If no records are found, an empty array is returned. Use # Model.find(:all, *args) or its shortcut Model.all(*args). # - # All approaches accept an options hash as their last parameter. The options are: + # All approaches accept an options hash as their last parameter. + # + # ==== Attributes # # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. # * :order - An SQL fragment like "created_at DESC, name". @@ -479,7 +481,9 @@ module ActiveRecord #:nodoc: # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". # - # Examples for find by id: + # ==== Examples + # + # # find by id # Person.find(1) # returns the object for ID = 1 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) @@ -490,17 +494,19 @@ module ActiveRecord #:nodoc: # provide since database rows are unordered. Give an explicit :order # to ensure the results are sorted. # - # Examples for find first: + # ==== Examples + # + # # find first # Person.find(:first) # returns the first object fetched by SELECT * FROM people # Person.find(:first, :conditions => [ "user_name = ?", user_name]) # Person.find(:first, :order => "created_on DESC", :offset => 5) # - # Examples for find last: + # # find last # Person.find(:last) # returns the last object fetched by SELECT * FROM people # Person.find(:last, :conditions => [ "user_name = ?", user_name]) # Person.find(:last, :order => "created_on DESC", :offset => 5) # - # Examples for find all: + # # find all # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) # Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] } @@ -943,7 +949,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or SerializationTypeMismatch will be raised. + # class on retrieval or +SerializationTypeMismatch+ will be raised. # # ==== Attributes # @@ -971,7 +977,9 @@ module ActiveRecord #:nodoc: # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. # # Nested classes are given table names prefixed by the singular form of - # the parent's table name. Enclosing modules are not considered. Examples: + # the parent's table name. Enclosing modules are not considered. + # + # ==== Examples # # class Invoice < ActiveRecord::Base; end; # file class table_name @@ -1065,8 +1073,6 @@ module ActiveRecord #:nodoc: # Sets the table name to use to the given value, or (if the value # is nil or false) to the value returned by the given block. # - # Example: - # # class Project < ActiveRecord::Base # set_table_name "project" # end @@ -1079,8 +1085,6 @@ module ActiveRecord #:nodoc: # or (if the value is nil or false) to the value returned by the given # block. # - # Example: - # # class Project < ActiveRecord::Base # set_primary_key "sysid" # end @@ -1093,8 +1097,6 @@ module ActiveRecord #:nodoc: # or (if the value # is nil or false) to the value returned by the # given block. # - # Example: - # # class Project < ActiveRecord::Base # set_inheritance_column do # original_inheritance_column + "_id" @@ -1116,8 +1118,6 @@ module ActiveRecord #:nodoc: # If a sequence name is not explicitly set when using PostgreSQL, it # will discover the sequence corresponding to your primary key for you. # - # Example: - # # class Project < ActiveRecord::Base # set_sequence_name "projectseq" # default would have been "project_seq" # end @@ -2144,7 +2144,9 @@ module ActiveRecord #:nodoc: (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes end - # Returns a cache key that can be used to identify this record. Examples: + # Returns a cache key that can be used to identify this record. + # + # ==== Examples # # Product.new.cache_key # => "products/new" # Product.find(5).cache_key # => "products/5" (updated_at not available) -- cgit v1.2.3 From 4617139bcc21ccb875d25baf06c3124692061cf2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 21 May 2008 23:47:57 +0200 Subject: regular font for a constant --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 55fc803e3c..c393128621 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -949,7 +949,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or +SerializationTypeMismatch+ will be raised. + # class on retrieval or SerializationTypeMismatch will be raised. # # ==== Attributes # -- cgit v1.2.3 From dd9938a44ee3a7bb6c42527a1be6fcec70bf4772 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Wed, 21 May 2008 21:03:38 +0100 Subject: Fix mysql 4.1 incompatibility in the active record schema tests. Signed-off-by: Michael Koziarski [#233 state:resolved ] --- .../test/cases/active_schema_test_mysql.rb | 73 ++++++++++++---------- 1 file changed, 41 insertions(+), 32 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb index ddf3e82162..2a42dc3517 100644 --- a/activerecord/test/cases/active_schema_test_mysql.rb +++ b/activerecord/test/cases/active_schema_test_mysql.rb @@ -40,47 +40,56 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_add_timestamps - #we need to actually modify some data, so we make execute to point to the original method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute_with_stub, :execute - alias_method :execute, :execute_without_stub - end - ActiveRecord::Base.connection.create_table :delete_me do |t| - end - ActiveRecord::Base.connection.add_timestamps :delete_me - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='updated_at' AND TYPE='datetime'").num_rows, 1 - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='created_at' AND TYPE='datetime'").num_rows, 1 - ensure - ActiveRecord::Base.connection.drop_table :delete_me rescue nil - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute, :execute_with_stub + with_real_execute do + begin + ActiveRecord::Base.connection.create_table :delete_me do |t| + end + ActiveRecord::Base.connection.add_timestamps :delete_me + assert column_present?('delete_me', 'updated_at', 'datetime') + assert column_present?('delete_me', 'created_at', 'datetime') + ensure + ActiveRecord::Base.connection.drop_table :delete_me rescue nil + end end end def test_remove_timestamps - #we need to actually modify some data, so we make execute to point to the original method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute_with_stub, :execute - alias_method :execute, :execute_without_stub - end - ActiveRecord::Base.connection.create_table :delete_me do |t| - t.timestamps - end - ActiveRecord::Base.connection.remove_timestamps :delete_me - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='updated_at' AND TYPE='datetime'").num_rows, 0 - assert_equal ActiveRecord::Base.connection.execute("SHOW FIELDS FROM delete_me where FIELD='created_at' AND TYPE='datetime'").num_rows, 0 - ensure - ActiveRecord::Base.connection.drop_table :delete_me rescue nil - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do - alias_method :execute, :execute_with_stub + with_real_execute do + begin + ActiveRecord::Base.connection.create_table :delete_me do |t| + t.timestamps + end + ActiveRecord::Base.connection.remove_timestamps :delete_me + assert !column_present?('delete_me', 'updated_at', 'datetime') + assert !column_present?('delete_me', 'created_at', 'datetime') + ensure + ActiveRecord::Base.connection.drop_table :delete_me rescue nil + end end end - private + def with_real_execute + #we need to actually modify some data, so we make execute point to the original method + ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + alias_method :execute_with_stub, :execute + alias_method :execute, :execute_without_stub + end + yield + ensure + #before finishing, we restore the alias to the mock-up method + ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + alias_method :execute, :execute_with_stub + end + end + + def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) end + + def column_present?(table_name, column_name, type) + results = ActiveRecord::Base.connection.select_all("SHOW FIELDS FROM #{table_name} LIKE '#{column_name}'") + results.first && results.first['Type'] == type + end end -- cgit v1.2.3 From cff2291df5d1df106ae8cf116655f0703f53f8c3 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Thu, 22 May 2008 11:19:10 +0100 Subject: Fix failing tests on mysql 4.1 & ruby 1.8.4. [#237 state:resolved] Signed-off-by: Pratik Naik --- activerecord/test/cases/migration_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 527856b4c0..f36255e209 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -281,7 +281,7 @@ if ActiveRecord::Base.connection.supports_migrations? # Do a manual insertion if current_adapter?(:OracleAdapter) Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)" - elsif current_adapter?(:OpenBaseAdapter) + elsif current_adapter?(:OpenBaseAdapter) || (current_adapter?(:MysqlAdapter) && Mysql.client_version < 50003) #before mysql 5.0.3 decimals stored as strings Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')" else Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)" @@ -384,7 +384,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_not_equal "Z", bob.moment_of_truth.zone # US/Eastern is -5 hours from GMT assert_equal Rational(-5, 24), bob.moment_of_truth.offset - assert_equal "-05:00", bob.moment_of_truth.zone + assert_match /\A-05:?00\Z/, bob.moment_of_truth.zone #ruby 1.8.6 uses HH:MM, prior versions use HHMM assert_equal DateTime::ITALY, bob.moment_of_truth.start end end -- cgit v1.2.3 From 63946cfb0ecb1a30b254920df7daee57b36ce7ec Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 23 May 2008 01:03:00 +0200 Subject: overall cleanup of "#=>" and other minor details --- activerecord/lib/active_record/calculations.rb | 14 ++++++++------ .../abstract/schema_definitions.rb | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 17 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index fec9bee38f..10e8330d1c 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -245,12 +245,14 @@ module ActiveRecord options.assert_valid_keys(CALCULATIONS_OPTIONS) end - # Converts a given key to the value that the database adapter returns as - # a usable column name. - # users.id #=> users_id - # sum(id) #=> sum_id - # count(distinct users.id) #=> count_distinct_users_id - # count(*) #=> count_all + # Converts the given keys to the value that the database adapter returns as + # a usable column name: + # + # column_alias_for("users.id") # => "users_id" + # column_alias_for("sum(id)") # => "sum_id" + # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id" + # column_alias_for("count(*)") # => "count_all" + # column_alias_for("count", "id") # => "count_id" def column_alias_for(*keys) connection.table_alias_for(keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_')) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 18f1175f5f..e4e950d481 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -92,7 +92,7 @@ module ActiveRecord # Returns the human name of the column name. # # ===== Examples - # Column.new('sales_stage', ...).human_name #=> 'Sales stage' + # Column.new('sales_stage', ...).human_name # => 'Sales stage' def human_name Base.human_attribute_name(@name) end @@ -350,28 +350,28 @@ module ActiveRecord # == Examples # # Assuming td is an instance of TableDefinition # td.column(:granted, :boolean) - # #=> granted BOOLEAN + # # granted BOOLEAN # # td.column(:picture, :binary, :limit => 2.megabytes) - # #=> picture BLOB(2097152) + # # => picture BLOB(2097152) # # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) - # #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL + # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL # - # def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) - # #=> bill_gates_money DECIMAL(15,2) + # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) + # # => bill_gates_money DECIMAL(15,2) # - # def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) - # #=> sensor_reading DECIMAL(30,20) + # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) + # # => sensor_reading DECIMAL(30,20) # # # While :scale defaults to zero on most databases, it # # probably wouldn't hurt to include it. - # def.column(:huge_integer, :decimal, :precision => 30) - # #=> huge_integer DECIMAL(30) + # td.column(:huge_integer, :decimal, :precision => 30) + # # => huge_integer DECIMAL(30) # # == Short-hand examples # - # Instead of calling column directly, you can also work with the short-hand definitions for the default types. + # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types. # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined # in a single statement. # -- cgit v1.2.3 From 11ea3e947a1b5a59a5f77ba392a32f57e157903e Mon Sep 17 00:00:00 2001 From: Cody Fauser Date: Fri, 23 May 2008 16:38:40 -0400 Subject: Fixup weird RDoc markup that does not render correctly --- .../connection_adapters/abstract/schema_definitions.rb | 6 +++--- activerecord/lib/active_record/named_scope.rb | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index e4e950d481..f968b9b173 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -16,9 +16,9 @@ module ActiveRecord # Instantiates a new column in the table. # - # +name+ is the column's name, as in supplier_id int(11). - # +default+ is the type-casted default value, such as sales_stage varchar(20) default 'new'. - # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). + # +name+ is the column's name, such as supplier_id in supplier_id int(11). + # +default+ is the type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. + # +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @name, @sql_type, @null = name, sql_type, null diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 62eecbf9be..69b7da7700 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -2,9 +2,7 @@ module ActiveRecord module NamedScope # All subclasses of ActiveRecord::Base have two named_scopes: # * all, which is similar to a find(:all) query, and - # * scoped, which allows for the creation of anonymous scopes, on the fly: - # - # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) + # * scoped, which allows for the creation of anonymous scopes, on the fly: Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) # # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing # intermediate values (scopes) around as first-class objects is convenient. -- cgit v1.2.3 From 8d0b4fa39fab6e5d1e3382b4b137cc47e559b0be Mon Sep 17 00:00:00 2001 From: josevalim Date: Fri, 23 May 2008 11:20:13 +0200 Subject: Added :select option to has_one and belongs_to, remove unused :order option on belongs_to. Signed-off-by: Michael Koziarski [#241 state:resolved] --- activerecord/lib/active_record/associations.rb | 16 +++++++++------- .../active_record/associations/belongs_to_association.rb | 5 +++-- .../associations/belongs_to_polymorphic_association.rb | 5 +++-- .../active_record/associations/has_one_association.rb | 5 +++-- .../cases/associations/belongs_to_associations_test.rb | 5 +++++ .../test/cases/associations/has_one_associations_test.rb | 5 +++++ activerecord/test/models/company.rb | 2 ++ 7 files changed, 30 insertions(+), 13 deletions(-) mode change 100644 => 100755 activerecord/lib/active_record/associations.rb mode change 100644 => 100755 activerecord/lib/active_record/associations/belongs_to_association.rb mode change 100644 => 100755 activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb mode change 100644 => 100755 activerecord/lib/active_record/associations/has_one_association.rb mode change 100644 => 100755 activerecord/test/cases/associations/belongs_to_associations_test.rb mode change 100644 => 100755 activerecord/test/cases/associations/has_one_associations_test.rb (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb old mode 100644 new mode 100755 index 95caf68692..6c21fed8ea --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -667,7 +667,7 @@ module ActiveRecord # * :limit - An integer determining the limit on the number of rows that should be returned. # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. # * :select - By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join - # but not include the joined columns. + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will rise an error. # * :as - Specifies a polymorphic interface (See belongs_to). # * :through - Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to @@ -747,6 +747,8 @@ module ActiveRecord # as the default :foreign_key. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. # * :as - Specifies a polymorphic interface (See belongs_to). + # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :through: Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a # has_one or belongs_to association on the join model. @@ -821,8 +823,8 @@ module ActiveRecord # if the real class name is Person, you'll have to specify it with this option. # * :conditions - Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # SQL fragment, such as authorized = 1. - # * :order - Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, - # such as last_name, first_name DESC. + # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name # of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use # "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" @@ -1011,7 +1013,7 @@ module ActiveRecord # * :limit - An integer determining the limit on the number of rows that should be returned. # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join - # but not include the joined columns. + # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :readonly - If true, all the associated objects are readonly through the association. # # Option examples: @@ -1341,7 +1343,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly ) create_reflection(:has_one, association_id, options, self) @@ -1349,14 +1351,14 @@ module ActiveRecord def create_has_one_through_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type ) create_reflection(:has_one, association_id, options, self) end def create_belongs_to_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent, + :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, :counter_cache, :extend, :polymorphic, :readonly ) diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb old mode 100644 new mode 100755 index 9ff3f13592..7c28cbdd07 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -42,10 +42,11 @@ module ActiveRecord private def find_target @reflection.klass.find( - @owner[@reflection.primary_key_name], + @owner[@reflection.primary_key_name], + :select => @reflection.options[:select], :conditions => conditions, :include => @reflection.options[:include], - :readonly => @reflection.options[:readonly] + :readonly => @reflection.options[:readonly] ) end diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb old mode 100644 new mode 100755 index 9549b959fc..df4ae38f38 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -29,12 +29,13 @@ module ActiveRecord if @reflection.options[:conditions] association_class.find( - @owner[@reflection.primary_key_name], + @owner[@reflection.primary_key_name], + :select => @reflection.options[:select], :conditions => conditions, :include => @reflection.options[:include] ) else - association_class.find(@owner[@reflection.primary_key_name], :include => @reflection.options[:include]) + association_class.find(@owner[@reflection.primary_key_name], :select => @reflection.options[:select], :include => @reflection.options[:include]) end end diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb old mode 100644 new mode 100755 index 3ff9fe3b9f..c2b3503e0d --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -51,10 +51,11 @@ module ActiveRecord private def find_target @reflection.klass.find(:first, - :conditions => @finder_sql, + :conditions => @finder_sql, + :select => @reflection.options[:select], :order => @reflection.options[:order], :include => @reflection.options[:include], - :readonly => @reflection.options[:readonly] + :readonly => @reflection.options[:readonly] ) end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb old mode 100644 new mode 100755 index 4382ba17ef..3073eae355 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -92,6 +92,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm" end + def test_with_select + assert_equal Company.find(2).firm_with_select.attributes.size, 1 + assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1 + end + def test_belongs_to_counter debate = Topic.create("title" => "debate") assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet" diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb old mode 100644 new mode 100755 index 9e99caa7b7..e7d4de8246 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -24,6 +24,11 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_queries(0) { firms.each(&:account) } end + def test_with_select + assert_equal Firm.find(1).account_with_select.attributes.size, 2 + assert_equal Firm.find(1, :include => :account_with_select).attributes.size, 2 + end + def test_can_marshal_has_one_association_with_nil_target firm = Firm.new assert_nothing_raised do diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index f637490c59..cc521d2a02 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -47,6 +47,7 @@ class Firm < Company has_many :readonly_clients, :class_name => 'Client', :readonly => true has_one :account, :foreign_key => "firm_id", :dependent => :destroy + has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id" has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true end @@ -64,6 +65,7 @@ end class Client < Company belongs_to :firm, :foreign_key => "client_of" belongs_to :firm_with_basic_id, :class_name => "Firm", :foreign_key => "firm_id" + belongs_to :firm_with_select, :class_name => "Firm", :foreign_key => "firm_id", :select => "id" belongs_to :firm_with_other_name, :class_name => "Firm", :foreign_key => "client_of" belongs_to :firm_with_condition, :class_name => "Firm", :foreign_key => "client_of", :conditions => ["1 = ?", 1] belongs_to :readonly_firm, :class_name => "Firm", :foreign_key => "firm_id", :readonly => true -- cgit v1.2.3 From b88ceb7dc8d31bdbea95ab4242bbdee17178cda9 Mon Sep 17 00:00:00 2001 From: Trevor Turk Date: Fri, 23 May 2008 15:51:56 -0500 Subject: add failing test case for block-setting of attributes via association Signed-off-by: Michael Koziarski --- activerecord/test/cases/associations_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'activerecord') diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 3ad8c608e0..034fe14996 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -160,6 +160,15 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_equal 1, developer.reload.audit_logs.size end + def test_create_via_association_with_block + post1 = Post.create(:title => "setting body with a block") {|p| p.body = "will work"} + assert_equal post1.body, "will work" + assert_nothing_raised do + post2 = authors(:david).posts.create(:title => "setting body with a block") {|p| p.body = "won't work"} + end + assert_equal post2.body, "won't work" + end + def test_failed_reload_returns_nil p = setup_dangling_association assert_nil p.author.reload -- cgit v1.2.3 From 6cba97d2a449faf21aec9fe9d4434067e414226f Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Fri, 23 May 2008 14:57:11 -0700 Subject: Create through associations can now work with blocks. Signed-off-by: Michael Koziarski [#248 state:resolved] --- .../active_record/associations/association_collection.rb | 10 ++++++++-- activerecord/test/cases/associations_test.rb | 15 +++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 2d3750e107..2f03197012 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -166,12 +166,18 @@ module ActiveRecord if attrs.is_a?(Array) attrs.collect { |attr| create(attr) } else - create_record(attrs) { |record| record.save } + create_record(attrs) do |record| + yield(record) if block_given? + record.save + end end end def create!(attrs = {}) - create_record(attrs) { |record| record.save! } + create_record(attrs) do |record| + yield(record) if block_given? + record.save! + end end # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 034fe14996..59349dd7cf 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -161,12 +161,15 @@ class AssociationProxyTest < ActiveRecord::TestCase end def test_create_via_association_with_block - post1 = Post.create(:title => "setting body with a block") {|p| p.body = "will work"} - assert_equal post1.body, "will work" - assert_nothing_raised do - post2 = authors(:david).posts.create(:title => "setting body with a block") {|p| p.body = "won't work"} - end - assert_equal post2.body, "won't work" + post = authors(:david).posts.create(:title => "New on Edge") {|p| p.body = "More cool stuff!"} + assert_equal post.title, "New on Edge" + assert_equal post.body, "More cool stuff!" + end + + def test_create_with_bang_via_association_with_block + post = authors(:david).posts.create!(:title => "New on Edge") {|p| p.body = "More cool stuff!"} + assert_equal post.title, "New on Edge" + assert_equal post.body, "More cool stuff!" end def test_failed_reload_returns_nil -- cgit v1.2.3 From 6277fd91133a3566333612857510d74de60d67f4 Mon Sep 17 00:00:00 2001 From: Michael Koziarski Date: Sat, 24 May 2008 18:34:59 +1200 Subject: Fix faulty tests introduced in 8d0b4fa39 --- activerecord/test/cases/associations/has_one_associations_test.rb | 2 +- activerecord/test/cases/reflection_test.rb | 5 +++-- activerecord/test/models/company.rb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index e7d4de8246..abc7ee7e9d 100755 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -26,7 +26,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_with_select assert_equal Firm.find(1).account_with_select.attributes.size, 2 - assert_equal Firm.find(1, :include => :account_with_select).attributes.size, 2 + assert_equal Firm.find(1, :include => :account_with_select).account_with_select.attributes.size, 2 end def test_can_marshal_has_one_association_with_nil_target diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index c8ee40ea09..8b4d232554 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -159,9 +159,10 @@ class ReflectionTest < ActiveRecord::TestCase end def test_reflection_of_all_associations - assert_equal 19, Firm.reflect_on_all_associations.size + # FIXME these assertions bust a lot + assert_equal 20, Firm.reflect_on_all_associations.size assert_equal 16, Firm.reflect_on_all_associations(:has_many).size - assert_equal 3, Firm.reflect_on_all_associations(:has_one).size + assert_equal 4, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index cc521d2a02..70f83fa8e6 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -47,7 +47,7 @@ class Firm < Company has_many :readonly_clients, :class_name => 'Client', :readonly => true has_one :account, :foreign_key => "firm_id", :dependent => :destroy - has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id" + has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account' has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true end -- cgit v1.2.3 From 98dc582742779081e71e697fcdf8d9ae2b421b16 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sun, 25 May 2008 12:29:00 +0100 Subject: Merge docrails. Signed-off-by: Pratik Naik --- activerecord/lib/active_record/aggregations.rb | 18 +- activerecord/lib/active_record/associations.rb | 124 ++++++------ .../associations/association_collection.rb | 4 +- .../associations/has_many_through_association.rb | 2 +- .../lib/active_record/attribute_methods.rb | 10 +- activerecord/lib/active_record/base.rb | 214 +++++++++++---------- activerecord/lib/active_record/calculations.rb | 22 ++- activerecord/lib/active_record/callbacks.rb | 2 +- .../abstract/connection_specification.rb | 2 +- .../abstract/database_statements.rb | 4 +- .../abstract/schema_definitions.rb | 32 +-- .../abstract/schema_statements.rb | 2 +- .../connection_adapters/postgresql_adapter.rb | 2 +- activerecord/lib/active_record/fixtures.rb | 49 ++--- .../lib/active_record/locking/optimistic.rb | 14 +- activerecord/lib/active_record/migration.rb | 4 +- activerecord/lib/active_record/named_scope.rb | 6 +- activerecord/lib/active_record/observer.rb | 4 +- activerecord/lib/active_record/schema.rb | 4 +- activerecord/lib/active_record/schema_dumper.rb | 2 +- .../active_record/serializers/xml_serializer.rb | 6 +- activerecord/lib/active_record/transactions.rb | 4 +- activerecord/lib/active_record/validations.rb | 4 +- 23 files changed, 279 insertions(+), 256 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 61446cde36..a5d3a50ef1 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -92,19 +92,19 @@ module ActiveRecord # # == Writing value objects # - # Value objects are immutable and interchangeable objects that represent a given value, such as a +Money+ object representing - # $5. Two +Money+ objects both representing $5 should be equal (through methods such as == and <=> from +Comparable+ if ranking - # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as +Customer+ can + # Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing + # $5. Two Money objects both representing $5 should be equal (through methods such as == and <=> from Comparable if ranking + # makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can # easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or - # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. + # relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects. # - # It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after - # creation. Create a new +Money+ object with the new value instead. This is exemplified by the Money#exchanged_to method that + # It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after + # creation. Create a new Money object with the new value instead. This is exemplified by the Money#exchanged_to method that # returns a new value object instead of changing its own values. Active Record won't persist value objects that have been # changed through means other than the writer method. # # The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to - # change it afterwards will result in a ActiveSupport::FrozenObjectError. + # change it afterwards will result in a ActiveSupport::FrozenObjectError. # # Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects # immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable @@ -123,8 +123,8 @@ module ActiveRecord # # Options are: # * :class_name - specify the class name of the association. Use it only if that name can't be inferred - # from the part id. So composed_of :address will by default be linked to the +Address+ class, but - # if the real class name is +CompanyAddress+, you'll have to specify it with this option. + # from the part id. So composed_of :address will by default be linked to the Address class, but + # if the real class name is CompanyAddress, you'll have to specify it with this option. # * :mapping - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name # to a constructor parameter on the value class. # * :allow_nil - specifies that the aggregate object will not be instantiated when all mapped diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 6c21fed8ea..a3d1bbbada 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -155,7 +155,7 @@ module ActiveRecord # # == Cardinality and associations # - # ActiveRecord associations can be used to describe one-to-one, one-to-many and many-to-many + # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many # relationships between models. Each model uses an association to describe its role in # the relation. The +belongs_to+ association is always used in the model that has # the foreign key. @@ -441,9 +441,9 @@ module ActiveRecord # # == Eager loading of associations # - # Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is + # Eager loading is a way to find objects of a certain class and a number of named associations. This is # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author - # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example: + # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 2. Example: # # class Post < ActiveRecord::Base # belongs_to :author @@ -452,7 +452,7 @@ module ActiveRecord # # Consider the following loop using the class above: # - # for post in Post.find(:all) + # for post in Post.all # puts "Post: " + post.title # puts "Written by: " + post.author.name # puts "Last comment on: " + post.comments.first.created_on @@ -462,14 +462,15 @@ module ActiveRecord # # for post in Post.find(:all, :include => :author) # - # This references the name of the +belongs_to+ association that also used the :author symbol, so the find will now weave in a join something - # like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101. + # This references the name of the +belongs_to+ association that also used the :author symbol. After loading the posts, find + # will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102. # # We can improve upon the situation further by referencing both associations in the finder with: # # for post in Post.find(:all, :include => [ :author, :comments ]) # - # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query. + # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries + # will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below). # # To include a deep hierarchy of associations, use a hash: # @@ -482,81 +483,91 @@ module ActiveRecord # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. # - # Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So - # :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the +SELECT+ statement too, the - # :select option is ignored. + # Since only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case + # Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example + # + # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions - # as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich - # associations" with +has_and_belongs_to_many+ are not a good fit for eager loading. + # will result in a single SQL query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. + # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole + # and not just to the association. You must disambiguate column references for this fallback to happen, for example + # :order => "author.name DESC" will work but :order => "name DESC" will not. + # + # If you do want eagerload only some members of an association it is usually more natural to :include an association + # which has conditions defined on it: + # + # class Post < ActiveRecord::Base + # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true] + # end + # + # Post.find(:all, :include => :approved_comments) + # + # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. # # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated # before the actual model exists. # - # Eager loading is not supported with polymorphic associations up to (and including) - # version 2.0.2. Given + # Eager loading is supported with polymorphic associations. # # class Address < ActiveRecord::Base # belongs_to :addressable, :polymorphic => true # end # - # a call that tries to eager load the addressable model - # - # Address.find(:all, :include => :addressable) # INVALID - # - # will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent model's type - # is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that early query. + # A call that tries to eager load the addressable model # - # In versions greater than 2.0.2 eager loading in polymorphic associations is supported - # thanks to a change in the overall preloading strategy. + # Address.find(:all, :include => :addressable) # - # It does work the other way around though: if the User model is addressable you can eager load - # their addresses with :include just fine, every piece needed to construct the query is known beforehand. + # will execute one query to load the addresses and load the addressables with one query per addressable type. + # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of + # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback + # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent + # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # - # ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, + # Active Record uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended # for any more successive uses of the table name. # - # Post.find :all, :include => :comments - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... - # Post.find :all, :include => :special_comments # STI - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment' - # Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name - # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts + # Post.find :all, :joins => :comments + # # => SELECT ... FROM posts INNER JOIN comments ON ... + # Post.find :all, :joins => :special_comments # STI + # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment' + # Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name + # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts # # Acts as tree example: # - # TreeMixin.find :all, :include => :children - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # TreeMixin.find :all, :include => {:children => {:parent => :children}} - # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... - # LEFT OUTER JOIN parents_mixins ... - # LEFT OUTER JOIN mixins childrens_mixins_2 + # TreeMixin.find :all, :joins => :children + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # TreeMixin.find :all, :joins => {:children => :parent} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # TreeMixin.find :all, :joins => {:children => {:parent => :children}} + # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ... + # INNER JOIN parents_mixins ... + # INNER JOIN mixins childrens_mixins_2 # # Has and Belongs to Many join tables use the same idea, but add a _join suffix: # - # Post.find :all, :include => :categories - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # Post.find :all, :include => {:categories => :posts} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # Post.find :all, :include => {:categories => {:posts => :categories}} - # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... - # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories - # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts + # Post.find :all, :joins => :categories + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # Post.find :all, :joins => {:categories => :posts} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # Post.find :all, :joins => {:categories => {:posts => :categories}} + # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ... + # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories + # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 # # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations: # - # Post.find :all, :include => :comments, :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ... - # Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..." - # # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ... - # LEFT OUTER JOIN comments special_comments_posts ... + # Post.find :all, :joins => :comments, :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... + # Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..." + # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ... + # INNER JOIN comments special_comments_posts ... # INNER JOIN comments ... # # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database. @@ -842,7 +853,6 @@ module ActiveRecord # this results in a counter with +NULL+ value, which will never increment. # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. # * :include - Specify second-order associations that should be eager loaded when this object is loaded. - # Not allowed if the association is polymorphic. # * :polymorphic - Specify this association is a polymorphic association by passing +true+. # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). @@ -942,7 +952,7 @@ module ActiveRecord # # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through # +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as - # +ReadOnly+ (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any + # readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any # associations with attributes to a real join model (see introduction). # # Adds the following methods for retrieval and query: diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 2f03197012..52d2a9864e 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -48,7 +48,7 @@ module ActiveRecord end end - # fetch first using SQL if possible + # Fetches the first one using SQL if possible. def first(*args) if fetch_first_or_last_using_find? args find(:first, *args) @@ -58,7 +58,7 @@ module ActiveRecord end end - # fetch last using SQL if possible + # Fetches the last one using SQL if possible. def last(*args) if fetch_first_or_last_using_find? args find(:last, *args) diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index f683669615..ebcf462f2e 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -34,7 +34,7 @@ module ActiveRecord def count(*args) column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args) if @reflection.options[:uniq] - # This is needed because 'SELECT count(DISTINCT *)..' is not valid sql statement. + # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL statement. column_name = "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}" if column_name == :all options.merge!(:distinct => true) end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index d753778d52..fab16a4446 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -94,7 +94,7 @@ module ActiveRecord end # Checks whether the method is defined in the model or any of its subclasses - # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # that also derive from Active Record. Raises DangerousAttributeError if the # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s @@ -162,8 +162,8 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}; unserialize_attribute('#{attr_name}'); end" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. - # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. def define_read_method_for_time_zone_conversion(attr_name) method_body = <<-EOV def #{attr_name}(reload = false) @@ -176,7 +176,7 @@ module ActiveRecord evaluate_attribute_method attr_name, method_body end - # Define an attribute ? method. + # Defines a predicate method attr_name?. def define_question_method(attr_name) evaluate_attribute_method attr_name, "def #{attr_name}?; query_attribute('#{attr_name}'); end", "#{attr_name}?" end @@ -185,7 +185,7 @@ module ActiveRecord evaluate_attribute_method attr_name, "def #{attr_name}=(new_value);write_attribute('#{attr_name}', new_value);end", "#{attr_name}=" end - # Defined for all datetime and timestamp attributes when time_zone_aware_attributes are enabled. + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_write_method_for_time_zone_conversion(attr_name) method_body = <<-EOV diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5351f55200..c393128621 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2,7 +2,7 @@ require 'yaml' require 'set' module ActiveRecord #:nodoc: - # Generic ActiveRecord exception class. + # Generic Active Record exception class. class ActiveRecordError < StandardError end @@ -30,19 +30,19 @@ module ActiveRecord #:nodoc: class SerializationTypeMismatch < ActiveRecordError end - # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). + # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). class AdapterNotSpecified < ActiveRecordError end - # Raised when ActiveRecord cannot find database adapter specified in config/database.yml or programmatically. + # Raised when Active Record cannot find database adapter specified in config/database.yml or programmatically. class AdapterNotFound < ActiveRecordError end - # Raised when connection to the database could not been established (for example when connection= is given a nil object). + # Raised when connection to the database could not been established (for example when connection= is given a nil object). class ConnectionNotEstablished < ActiveRecordError end - # Raised when ActiveRecord cannot find record by given id or set of ids. + # Raised when Active Record cannot find record by given id or set of ids. class RecordNotFound < ActiveRecordError end @@ -70,7 +70,7 @@ module ActiveRecord #:nodoc: # instantiation, for example, when two users edit the same wiki page and one starts editing and saves # the page before the other. # - # Read more about optimistic locking in +ActiveRecord::Locking+ module RDoc. + # Read more about optimistic locking in ActiveRecord::Locking module RDoc. class StaleObjectError < ActiveRecordError end @@ -83,12 +83,12 @@ module ActiveRecord #:nodoc: class ReadOnlyRecord < ActiveRecordError end - # Used by ActiveRecord transaction mechanism to distinguish rollback from other exceptional situations. + # Used by Active Record transaction mechanism to distinguish rollback from other exceptional situations. # You can use it to roll your transaction back explicitly in the block passed to +transaction+ method. class Rollback < ActiveRecordError end - # Raised when attribute has a name reserved by ActiveRecord (when attribute has name of one of ActiveRecord instance methods). + # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). class DangerousAttributeError < ActiveRecordError end @@ -200,7 +200,7 @@ module ActiveRecord #:nodoc: # # All column values are automatically available through basic accessors on the Active Record object, but sometimes you # want to specialize this behavior. This can be done by overwriting the default accessors (using the same - # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. + # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. # Example: # # class Song < ActiveRecord::Base @@ -215,8 +215,8 @@ module ActiveRecord #:nodoc: # end # end # - # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and - # read_attribute(:attribute) as a shorter form. + # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and + # read_attribute(:attribute) as a shorter form. # # == Attribute query methods # @@ -236,7 +236,7 @@ module ActiveRecord #:nodoc: # # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. # That can be done by using the _before_type_cast accessors that all attributes have. For example, if your Account model - # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. + # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. # # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you @@ -245,8 +245,8 @@ module ActiveRecord #:nodoc: # == Dynamic attribute-based finders # # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by - # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, - # Person.find_all_by_last_name, Payment.find_by_transaction_id. So instead of writing + # appending the name of an attribute to find_by_ or find_all_by_, so you get finders like Person.find_by_user_name, + # Person.find_all_by_last_name, and Payment.find_by_transaction_id. So instead of writing # Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name). # And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name). # @@ -255,8 +255,8 @@ module ActiveRecord #:nodoc: # Person.find(:first, :conditions => ["user_name = ? AND password = ?", user_name, password]), you just do # Person.find_by_user_name_and_password(user_name, password). # - # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount - # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is + # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount + # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is # actually Person.find_by_user_name(user_name, options). So you could call Payment.find_all_by_amount(50, :order => "created_on"). # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with @@ -316,8 +316,8 @@ module ActiveRecord #:nodoc: # class Client < Company; end # class PriorityClient < Client; end # - # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then - # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. + # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then + # fetch this row again using Company.find(:first, "name = '37signals'") and it will return a Firm object. # # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. @@ -329,8 +329,8 @@ module ActiveRecord #:nodoc: # # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. - # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection - # and Course *and all its subclasses* will use this connection instead. + # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection + # and Course and all of its subclasses will use this connection instead. # # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool. @@ -407,7 +407,7 @@ module ActiveRecord #:nodoc: @@table_name_suffix = "" # Indicates whether table names should be the pluralized versions of the corresponding class names. - # If true, the default table name for a +Product+ class will be +products+. If false, it would just be +product+. + # If true, the default table name for a Product class will be +products+. If false, it would just be +product+. # See table_name for the full rules on table/class naming. This is true, by default. cattr_accessor :pluralize_table_names, :instance_writer => false @@pluralize_table_names = true @@ -446,36 +446,44 @@ module ActiveRecord #:nodoc: class << self # Class methods # Find operates with four different retrieval approaches: # - # * Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). + # * Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). # If no record can be found for all of the listed ids, then RecordNotFound will be raised. - # * Find first: This will return the first record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find last: This will return the last record matched by the options used. These options can either be specific - # conditions or merely an order. If no record can be matched, nil is returned. - # * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. - # - # All approaches accept an options hash as their last parameter. The options are: - # - # * :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. - # * :order: An SQL fragment like "created_at DESC, name". - # * :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :limit: An integer determining the limit on the number of rows that should be returned. - # * :offset: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. - # * :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) - # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). + # * Find first - This will return the first record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use + # Model.find(:first, *args) or its shortcut Model.first(*args). + # * Find last - This will return the last record matched by the options used. These options can either be specific + # conditions or merely an order. If no record can be matched, +nil+ is returned. Use + # Model.find(:last, *args) or its shortcut Model.last(*args). + # * Find all - This will return all the records matched by the options used. + # If no records are found, an empty array is returned. Use + # Model.find(:all, *args) or its shortcut Model.all(*args). + # + # All approaches accept an options hash as their last parameter. + # + # ==== Attributes + # + # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. + # * :order - An SQL fragment like "created_at DESC, name". + # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. + # * :limit - An integer determining the limit on the number of rows that should be returned. + # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. + # * :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) + # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer + # * :include - Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. - # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not + # * :select - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not # include the joined columns. - # * :from: By default, this is the table name of the class, but can be changed to an alternate table name (or even the name + # * :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name # of a database view). - # * :readonly: Mark the returned records read-only so they cannot be saved or updated. - # * :lock: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". + # * :readonly - Mark the returned records read-only so they cannot be saved or updated. + # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". # - # Examples for find by id: + # ==== Examples + # + # # find by id # Person.find(1) # returns the object for ID = 1 # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6) # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17) @@ -486,17 +494,19 @@ module ActiveRecord #:nodoc: # provide since database rows are unordered. Give an explicit :order # to ensure the results are sorted. # - # Examples for find first: + # ==== Examples + # + # # find first # Person.find(:first) # returns the first object fetched by SELECT * FROM people # Person.find(:first, :conditions => [ "user_name = ?", user_name]) # Person.find(:first, :order => "created_on DESC", :offset => 5) # - # Examples for find last: + # # find last # Person.find(:last) # returns the last object fetched by SELECT * FROM people # Person.find(:last, :conditions => [ "user_name = ?", user_name]) # Person.find(:last, :order => "created_on DESC", :offset => 5) # - # Examples for find all: + # # find all # Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people # Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50) # Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] } @@ -504,11 +514,12 @@ module ActiveRecord #:nodoc: # Person.find(:all, :include => [ :account, :friends ]) # Person.find(:all, :group => "category") # - # Example for find with a lock. Imagine two concurrent transactions: - # each will read person.visits == 2, add 1 to it, and save, resulting - # in two saves of person.visits = 3. By locking the row, the second + # Example for find with a lock: Imagine two concurrent transactions: + # each will read person.visits == 2, add 1 to it, and save, resulting + # in two saves of person.visits = 3. By locking the row, the second # transaction has to wait until the first is finished; we get the - # expected person.visits == 4. + # expected person.visits == 4. + # # Person.transaction do # person = Person.find(1, :lock => true) # person.visits += 1 @@ -527,14 +538,14 @@ module ActiveRecord #:nodoc: end end - # This is an alias for find(:first). You can pass in all the same arguments to this method as you can - # to find(:first) + # A convenience wrapper for find(:first, *args). You can pass in all the + # same arguments to this method as you can to find(:first). def first(*args) find(:first, *args) end - # This is an alias for find(:last). You can pass in all the same arguments to this method as you can - # to find(:last) + # A convenience wrapper for find(:last, *args). You can pass in all the + # same arguments to this method as you can to find(:last). def last(*args) find(:last, *args) end @@ -545,8 +556,7 @@ module ActiveRecord #:nodoc: find(:all, *args) end - # - # Executes a custom sql query against your database and returns all the results. The results will + # Executes a custom SQL query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call # this method from. If you call +Product.find_by_sql+ then the results will be returned in a Product # object with the attributes you specified in the SQL query. @@ -555,13 +565,13 @@ module ActiveRecord #:nodoc: # SELECT will be attributes of the model, whether or not they are columns of the corresponding # table. # - # The +sql+ parameter is a full sql query as a string. It will be called as is, there will be + # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be # no database agnostic conversions performed. This should be a last resort because using, for example, # MySQL specific terms will lock you to using that particular database engine or require you to # change your call if you switch engines # # ==== Examples - # # A simple sql query spanning multiple tables + # # A simple SQL query spanning multiple tables # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id" # > [#"Ruby Meetup", "first_name"=>"Quentin"}>, ...] # @@ -860,9 +870,15 @@ module ActiveRecord #:nodoc: end - # Attributes named in this macro are protected from mass-assignment, such as new(attributes) and - # attributes=(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer - # methods to do assignment. This is meant to protect sensitive attributes from being overwritten by URL/form hackers. Example: + # Attributes named in this macro are protected from mass-assignment, + # such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes). + # + # Mass-assignment to these attributes will simply be ignored, to assign + # to them you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. # # class Customer < ActiveRecord::Base # attr_protected :credit_rating @@ -876,7 +892,8 @@ module ActiveRecord #:nodoc: # customer.credit_rating = "Average" # customer.credit_rating # => "Average" # - # To start from an all-closed default and enable attributes as needed, have a look at attr_accessible. + # To start from an all-closed default and enable attributes as needed, + # have a look at +attr_accessible+. def attr_protected(*attributes) write_inheritable_attribute("attr_protected", Set.new(attributes.map(&:to_s)) + (protected_attributes || [])) end @@ -886,19 +903,18 @@ module ActiveRecord #:nodoc: read_inheritable_attribute("attr_protected") end - # Similar to the attr_protected macro, this protects attributes of your model from mass-assignment, - # such as new(attributes) and attributes=(attributes) - # however, it does it in the opposite way. This locks all attributes and only allows access to the - # attributes specified. Assignment to attributes not in this list will be ignored and need to be set - # using the direct writer methods instead. This is meant to protect sensitive attributes from being - # overwritten by URL/form hackers. If you'd rather start from an all-open default and restrict - # attributes as needed, have a look at attr_protected. - # - # ==== Attributes - # - # * *attributes A comma separated list of symbols that represent columns _not_ to be protected + # Specifies a white list of model attributes that can be set via + # mass-assignment, such as new(attributes), + # update_attributes(attributes), or + # attributes=(attributes) # - # ==== Examples + # This is the opposite of the +attr_protected+ macro: Mass-assignment + # will only set attributes in this list, to assign to the rest of + # attributes you can use direct writer methods. This is meant to protect + # sensitive attributes from being overwritten by malicious users + # tampering with URLs or forms. If you'd rather start from an all-open + # default and restrict attributes as needed, have a look at + # +attr_protected+. # # class Customer < ActiveRecord::Base # attr_accessible :name, :nickname @@ -933,7 +949,7 @@ module ActiveRecord #:nodoc: # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or +SerializationTypeMismatch+ will be raised. + # class on retrieval or SerializationTypeMismatch will be raised. # # ==== Attributes # @@ -956,12 +972,14 @@ module ActiveRecord #:nodoc: # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending - # directly from ActiveRecord. So if the hierarchy looks like: Reply < Message < ActiveRecord, then Message is used + # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. # # Nested classes are given table names prefixed by the singular form of - # the parent's table name. Enclosing modules are not considered. Examples: + # the parent's table name. Enclosing modules are not considered. + # + # ==== Examples # # class Invoice < ActiveRecord::Base; end; # file class table_name @@ -975,8 +993,8 @@ module ActiveRecord #:nodoc: # file class table_name # invoice/lineitem.rb Invoice::Lineitem lineitems # - # Additionally, the class-level table_name_prefix is prepended and the - # table_name_suffix is appended. So if you have "myapp_" as a prefix, + # Additionally, the class-level +table_name_prefix+ is prepended and the + # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix, # the table name guess for an Invoice class becomes "myapp_invoices". # Invoice::Lineitem becomes "myapp_invoice_lineitems". # @@ -1055,8 +1073,6 @@ module ActiveRecord #:nodoc: # Sets the table name to use to the given value, or (if the value # is nil or false) to the value returned by the given block. # - # Example: - # # class Project < ActiveRecord::Base # set_table_name "project" # end @@ -1069,8 +1085,6 @@ module ActiveRecord #:nodoc: # or (if the value is nil or false) to the value returned by the given # block. # - # Example: - # # class Project < ActiveRecord::Base # set_primary_key "sysid" # end @@ -1083,8 +1097,6 @@ module ActiveRecord #:nodoc: # or (if the value # is nil or false) to the value returned by the # given block. # - # Example: - # # class Project < ActiveRecord::Base # set_inheritance_column do # original_inheritance_column + "_id" @@ -1106,8 +1118,6 @@ module ActiveRecord #:nodoc: # If a sequence name is not explicitly set when using PostgreSQL, it # will discover the sequence corresponding to your primary key for you. # - # Example: - # # class Project < ActiveRecord::Base # set_sequence_name "projectseq" # default would have been "project_seq" # end @@ -1267,7 +1277,7 @@ module ActiveRecord #:nodoc: class_of_active_record_descendant(self) end - # Set this to true if this is an abstract class (see #abstract_class?). + # Set this to true if this is an abstract class (see abstract_class?). attr_accessor :abstract_class # Returns whether this class is a base AR class. If A is a base class and @@ -1714,8 +1724,8 @@ module ActiveRecord #:nodoc: end - # Defines an "attribute" method (like #inheritance_column or - # #table_name). A new (class) method will be created with the + # Defines an "attribute" method (like +inheritance_column+ or + # +table_name+). A new (class) method will be created with the # given name. If a value is specified, the new method will # return that value (as a string). Otherwise, the given block # will be used to compute the value of the method. @@ -1892,7 +1902,7 @@ module ActiveRecord #:nodoc: end end - # Returns the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the class descending directly from Active Record in the inheritance hierarchy. def class_of_active_record_descendant(klass) if klass.superclass == Base || klass.superclass.abstract_class? klass @@ -1903,12 +1913,12 @@ module ActiveRecord #:nodoc: end end - # Returns the name of the class descending directly from ActiveRecord in the inheritance hierarchy. + # Returns the name of the class descending directly from Active Record in the inheritance hierarchy. def class_name_of_active_record_descendant(klass) #:nodoc: klass.base_class.name end - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a WHERE clause. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'" @@ -1924,7 +1934,7 @@ module ActiveRecord #:nodoc: end alias_method :sanitize_sql, :sanitize_sql_for_conditions - # Accepts an array, hash, or string of sql conditions and sanitizes + # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a SET clause. # { :name => nil, :group_id => 4 } returns "name = NULL , group_id='4'" def sanitize_sql_for_assignment(assignments) @@ -1940,7 +1950,7 @@ module ActiveRecord #:nodoc: mapping.first.is_a?(Array) ? mapping : [mapping] end - # Accepts a hash of sql conditions and replaces those attributes + # Accepts a hash of SQL conditions and replaces those attributes # that correspond to a +composed_of+ relationship with their expanded # aggregate attribute values. # Given: @@ -2013,7 +2023,7 @@ module ActiveRecord #:nodoc: end # Accepts an array of conditions. The array has each value - # sanitized and interpolated into the sql statement. + # sanitized and interpolated into the SQL statement. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" def sanitize_sql_array(ary) statement, *values = ary @@ -2134,7 +2144,9 @@ module ActiveRecord #:nodoc: (id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes end - # Returns a cache key that can be used to identify this record. Examples: + # Returns a cache key that can be used to identify this record. + # + # ==== Examples # # Product.new.cache_key # => "products/new" # Product.find(5).cache_key # => "products/5" (updated_at not available) @@ -2490,9 +2502,9 @@ module ActiveRecord #:nodoc: id end - # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord descendent. - # Considering the hierarchy Reply < Message < ActiveRecord, this makes it possible to do Reply.new without having to - # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the + # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendent. + # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to + # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? @@ -2564,7 +2576,7 @@ module ActiveRecord #:nodoc: self.class.connection.quote(value, column) end - # Interpolate custom sql string in instance context. + # Interpolate custom SQL string in instance context. # Optional record argument is meant for custom insert_sql. def interpolate_sql(sql, record = nil) instance_eval("%@#{sql.gsub('@', '\@')}@") diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 3c5caefe3b..10e8330d1c 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -46,28 +46,28 @@ module ActiveRecord calculate(:count, *construct_count_options_from_args(*args)) end - # Calculates the average value on a given column. The value is returned as a float. See #calculate for examples with options. + # Calculates the average value on a given column. The value is returned as a float. See +calculate+ for examples with options. # # Person.average('age') def average(column_name, options = {}) calculate(:avg, column_name, options) end - # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the minimum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.minimum('age') def minimum(column_name, options = {}) calculate(:min, column_name, options) end - # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the maximum value on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.maximum('age') def maximum(column_name, options = {}) calculate(:max, column_name, options) end - # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See #calculate for examples with options. + # Calculates the sum of values on a given column. The value is returned with the same data type of the column. See +calculate+ for examples with options. # # Person.sum('age') def sum(column_name, options = {}) @@ -245,12 +245,14 @@ module ActiveRecord options.assert_valid_keys(CALCULATIONS_OPTIONS) end - # Converts a given key to the value that the database adapter returns as - # a usable column name. - # users.id #=> users_id - # sum(id) #=> sum_id - # count(distinct users.id) #=> count_distinct_users_id - # count(*) #=> count_all + # Converts the given keys to the value that the database adapter returns as + # a usable column name: + # + # column_alias_for("users.id") # => "users_id" + # column_alias_for("sum(id)") # => "sum_id" + # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id" + # column_alias_for("count(*)") # => "count_all" + # column_alias_for("count", "id") # => "count_id" def column_alias_for(*keys) connection.table_alias_for(keys.join(' ').downcase.gsub(/\*/, 'all').gsub(/\W+/, ' ').strip.gsub(/ +/, '_')) end diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index a469af682b..41ec5c5e61 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -161,7 +161,7 @@ module ActiveRecord # == before_validation* returning statements # # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and Base#save will return +false+. - # If Base#save! is called it will raise a +RecordNotSaved+ exception. + # If Base#save! is called it will raise a RecordNotSaved exception. # Nothing will be appended to the errors object. # # == Canceling callbacks diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index 34627dfaf9..2a8807fb78 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -193,7 +193,7 @@ module ActiveRecord # :database => "path/to/dbfile" # ) # - # Also accepts keys as strings (for parsing from yaml for example): + # Also accepts keys as strings (for parsing from YAML for example): # # ActiveRecord::Base.establish_connection( # "adapter" => "sqlite", diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 589acd3945..16d405d3bd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -29,7 +29,7 @@ module ActiveRecord end # Returns an array of arrays containing the field values. - # Order is the same as that returned by #columns. + # Order is the same as that returned by +columns+. def select_rows(sql, name = nil) raise NotImplementedError, "select_rows is an abstract method" end @@ -93,7 +93,7 @@ module ActiveRecord # done if the transaction block raises an exception or returns false. def rollback_db_transaction() end - # Alias for #add_limit_offset!. + # Alias for add_limit_offset!. def add_limit!(sql, options) add_limit_offset!(sql, options) if options end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index fdb18b234c..f968b9b173 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -16,9 +16,9 @@ module ActiveRecord # Instantiates a new column in the table. # - # +name+ is the column's name, as in supplier_id int(11). - # +default+ is the type-casted default value, such as sales_stage varchar(20) default 'new'. - # +sql_type+ is only used to extract the column's length, if necessary. For example, company_name varchar(60). + # +name+ is the column's name, such as supplier_id in supplier_id int(11). + # +default+ is the type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. + # +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @name, @sql_type, @null = name, sql_type, null @@ -92,7 +92,7 @@ module ActiveRecord # Returns the human name of the column name. # # ===== Examples - # Column.new('sales_stage', ...).human_name #=> 'Sales stage' + # Column.new('sales_stage', ...).human_name # => 'Sales stage' def human_name Base.human_attribute_name(@name) end @@ -270,7 +270,7 @@ module ActiveRecord end # Represents a SQL table in an abstract way. - # Columns are stored as a ColumnDefinition in the #columns attribute. + # Columns are stored as a ColumnDefinition in the +columns+ attribute. class TableDefinition attr_accessor :columns @@ -350,28 +350,28 @@ module ActiveRecord # == Examples # # Assuming td is an instance of TableDefinition # td.column(:granted, :boolean) - # #=> granted BOOLEAN + # # granted BOOLEAN # # td.column(:picture, :binary, :limit => 2.megabytes) - # #=> picture BLOB(2097152) + # # => picture BLOB(2097152) # # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false) - # #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL + # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL # - # def.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) - # #=> bill_gates_money DECIMAL(15,2) + # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2) + # # => bill_gates_money DECIMAL(15,2) # - # def.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) - # #=> sensor_reading DECIMAL(30,20) + # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20) + # # => sensor_reading DECIMAL(30,20) # # # While :scale defaults to zero on most databases, it # # probably wouldn't hurt to include it. - # def.column(:huge_integer, :decimal, :precision => 30) - # #=> huge_integer DECIMAL(30) + # td.column(:huge_integer, :decimal, :precision => 30) + # # => huge_integer DECIMAL(30) # # == Short-hand examples # - # Instead of calling column directly, you can also work with the short-hand definitions for the default types. + # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types. # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined # in a single statement. # @@ -395,7 +395,7 @@ module ActiveRecord # end # # There's a short-hand method for each of the type values declared at the top. And then there's - # TableDefinition#timestamps that'll add created_at and updated_at as datetimes. + # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type # column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index b57d0a3ef7..67d70b3886 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -32,7 +32,7 @@ module ActiveRecord def columns(table_name, name = nil) end # Creates a new table - # There are two ways to work with #create_table. You can use the block + # There are two ways to work with +create_table+. You can use the block # form or the regular form, like this: # # === Block form diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2ec2d80af4..7dbfbb41f6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -776,7 +776,7 @@ module ActiveRecord # Returns an ORDER BY clause for the passed order option. # # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the sql as a sub-select and ordering in that query. + # by wrapping the +sql+ string as a sub-select and ordering in that query. def add_order_by_for_association_limiting!(sql, options) #:nodoc: return sql if options[:order].blank? diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index ac06cdbe43..c4cbe5d52f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -33,8 +33,8 @@ end # # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed # by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: -# "/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this: +# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: +# /test/fixtures/web_sites.yml). The format of a YAML fixture file looks like this: # # rubyonrails: # id: 1 @@ -67,7 +67,8 @@ end # = CSV fixtures # # Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored -# in a single file, but instead end with the .csv file extension (Rails example: "/test/fixtures/web_sites.csv") +# in a single file, but instead end with the .csv file extension +# (Rails example: /test/fixtures/web_sites.csv). # # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised @@ -93,11 +94,11 @@ end # 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 # appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures// -- like /test/fixtures/web_sites/ for the WebSite -# model). +# put your files in /test/fixtures// -- +# like /test/fixtures/web_sites/ for the WebSite model). # # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without -# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the +# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the # above example might look like: # # web_sites/google @@ -138,20 +139,20 @@ end # # 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 -# @web_sites. This is where the "fixture name" comes into play. +# @web_sites. This is where the "fixture name" comes into play. # -# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. -# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: +# On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name. +# So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics: # # # 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 # end # -# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return -# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded -# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual -# fixtures available as instance variables @web_site_1 and @web_site_2. +# As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return +# "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded +# from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual +# fixtures available as instance variables @web_site_1 and @web_site_2. # # If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options. # @@ -184,7 +185,7 @@ end # # This will create 1000 very simple YAML fixtures. # -# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. +# Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell. @@ -257,7 +258,7 @@ end # reginald: # generated id: 324201669 # name: Reginald the Pirate # -# ActiveRecord looks at the fixture's model class, discovers the correct +# Active Record looks at the fixture's model class, discovers the correct # primary key, and generates it right before inserting the fixture # into the database. # @@ -267,7 +268,7 @@ end # == Label references for associations (belongs_to, has_one, has_many) # # Specifying foreign keys in fixtures can be very fragile, not to -# mention difficult to read. Since ActiveRecord can figure out the ID of +# mention difficult to read. Since Active Record can figure out the ID of # any fixture from its label, you can specify FK's by label instead of ID. # # === belongs_to @@ -304,15 +305,15 @@ end # name: George the Monkey # pirate: reginald # -# Pow! All is made clear. ActiveRecord reflects on the fixture's model class, +# Pow! All is made clear. Active Record reflects on the fixture's model class, # finds all the +belongs_to+ associations, and allows you to specify # a target *label* for the *association* (monkey: george) rather than -# a target *id* for the *FK* (monkey_id: 1). +# a target *id* for the *FK* (monkey_id: 1). # # ==== Polymorphic belongs_to # # Supporting polymorphic relationships is a little bit more complicated, since -# ActiveRecord needs to know what type your association is pointing at. Something +# Active Record needs to know what type your association is pointing at. Something # like this should look familiar: # # ### in fruit.rb @@ -332,7 +333,7 @@ end # apple: # eater: george (Monkey) # -# Just provide the polymorphic target type and ActiveRecord will take care of the rest. +# Just provide the polymorphic target type and Active Record will take care of the rest. # # === has_and_belongs_to_many # @@ -395,15 +396,15 @@ end # # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits # on George's fixture, but we could've just as easily specified a list -# of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on +# of monkeys on each fruit. As with +belongs_to+, Active Record reflects on # the fixture's model class and discovers the +has_and_belongs_to_many+ # associations. # # == Autofilled timestamp columns # -# If your table/model specifies any of ActiveRecord's -# standard timestamp columns (created_at, created_on, updated_at, updated_on), -# they will automatically be set to Time.now. +# If your table/model specifies any of Active Record's +# standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+), +# they will automatically be set to Time.now. # # If you've set specific values, they'll be left alone. # diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 65f88cfdc7..c66034d18b 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -107,20 +107,20 @@ module ActiveRecord end # Is optimistic locking enabled for this table? Returns true if the - # #lock_optimistically flag is set to true (which it is, by default) - # and the table includes the #locking_column column (defaults to - # lock_version). + # +lock_optimistically+ flag is set to true (which it is, by default) + # and the table includes the +locking_column+ column (defaults to + # +lock_version+). def locking_enabled? lock_optimistically && columns_hash[locking_column] end - # Set the column to use for optimistic locking. Defaults to lock_version. + # Set the column to use for optimistic locking. Defaults to +lock_version+. def set_locking_column(value = nil, &block) define_attr_method :locking_column, value, &block value end - # The version column used for optimistic locking. Defaults to lock_version. + # The version column used for optimistic locking. Defaults to +lock_version+. def locking_column reset_locking_column end @@ -130,12 +130,12 @@ module ActiveRecord connection.quote_column_name(locking_column) end - # Reset the column used for optimistic locking back to the lock_version default. + # Reset the column used for optimistic locking back to the +lock_version+ default. def reset_locking_column set_locking_column DEFAULT_LOCKING_COLUMN end - # make sure the lock version column gets updated when counters are + # Make sure the lock version column gets updated when counters are # updated. def update_counters_with_lock(id, counters) counters = counters.merge(locking_column => 1) if locking_enabled? diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 5cc9f4e197..b47b01e99a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -208,7 +208,7 @@ module ActiveRecord # # You can quiet them down by setting ActiveRecord::Migration.verbose = false. # - # You can also insert your own messages and benchmarks by using the #say_with_time + # You can also insert your own messages and benchmarks by using the +say_with_time+ # method: # # def self.up @@ -377,7 +377,7 @@ module ActiveRecord end def proper_table_name(name) - # Use the ActiveRecord objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string + # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index c7cf1731c1..69b7da7700 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -2,9 +2,7 @@ module ActiveRecord module NamedScope # All subclasses of ActiveRecord::Base have two named_scopes: # * all, which is similar to a find(:all) query, and - # * scoped, which allows for the creation of anonymous scopes, on the fly: - # - # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) + # * scoped, which allows for the creation of anonymous scopes, on the fly: Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) # # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing # intermediate values (scopes) around as first-class objects is convenient. @@ -41,7 +39,7 @@ module ActiveRecord # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). # - # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to + # All scopes are available as class methods on the ActiveRecord::Base descendent upon which the scopes were defined. But they are also available to # has_many associations. If, # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 2b0728fc25..6e55e36b7d 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -19,7 +19,7 @@ module ActiveRecord # # Same as above, just using explicit class references # ActiveRecord::Base.observers = Cacher, GarbageCollector # - # Note: Setting this does not instantiate the observers yet. #instantiate_observers is + # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is # called during startup, and before each development request. def observers=(*observers) @observers = observers.flatten @@ -30,7 +30,7 @@ module ActiveRecord @observers ||= [] end - # Instantiate the global ActiveRecord observers + # Instantiate the global Active Record observers. def instantiate_observers return if @observers.blank? @observers.each do |observer| diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index d6b254fcf9..8a32cf1ca2 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -30,8 +30,8 @@ module ActiveRecord # Eval the given block. All methods available to the current connection # adapter are available within the block, so you can easily use the - # database definition DSL to build up your schema (#create_table, - # #add_index, etc.). + # database definition DSL to build up your schema (+create_table+, + # +add_index+, etc.). # # The +info+ hash is optional, and if given is used to define metadata # about the current schema (currently, only the schema's version): diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 826662d3ee..b90ed88c6b 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -38,7 +38,7 @@ module ActiveRecord stream.puts <
tag! escapes all values # to ensure that valid XML is generated. For known binary # values, it is at least an order of magnitude faster to # Base64 encode binary values and directly put them in the # output XML than to pass the original value or the Base64 - # encoded value to the #tag! method. It definitely makes + # encoded value to the tag! method. It definitely makes # no sense to Base64 encode the value and then give it to - # #tag!, since that just adds additional overhead. + # tag!, since that just adds additional overhead. def needs_encoding? ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type) end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 13cb5f3f48..3b6835762c 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -30,9 +30,9 @@ module ActiveRecord # Exceptions will force a ROLLBACK that returns the database to the state before the transaction was begun. Be aware, though, # that the objects will _not_ have their instance data returned to their pre-transactional state. # - # == Different ActiveRecord classes in a single transaction + # == Different Active Record classes in a single transaction # - # Though the transaction class method is called on some ActiveRecord class, + # Though the transaction class method is called on some Active Record class, # the objects within the transaction block need not all be instances of # that class. # In this example a Balance record is transactionally saved even diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b3a75121ed..0e150bddb2 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,7 +301,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the #validate instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldly and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: @@ -326,7 +326,7 @@ module ActiveRecord # end # end # - # This usage applies to #validate_on_create and #validate_on_update as well. + # This usage applies to +validate_on_create+ and +validate_on_update+ as well. # Validates each attribute against a block. # -- cgit v1.2.3 From 80bc36d808ba24ee7957aa5149336756824671c9 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 25 May 2008 20:39:45 +0200 Subject: revised markup in dirty.rb docs --- activerecord/lib/active_record/dirty.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 8fdc763292..d8355d2143 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -62,7 +62,7 @@ module ActiveRecord changed_attributes.keys end - # Map of changed attrs => [original value, new value] + # Map of changed attrs => [original value, new value]. # person.changes # => {} # person.name = 'bob' # person.changes # => { 'name' => ['bill', 'bob'] } @@ -93,27 +93,27 @@ module ActiveRecord end private - # Map of change attr => original value. + # Map of change attr => original value. def changed_attributes @changed_attributes ||= {} end - # Handle *_changed? for method_missing. + # Handle *_changed? for +method_missing+. def attribute_changed?(attr) changed_attributes.include?(attr) end - # Handle *_change for method_missing. + # Handle *_change for +method_missing+. def attribute_change(attr) [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) end - # Handle *_was for method_missing. + # Handle *_was for +method_missing+. def attribute_was(attr) attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) end - # Handle *_will_change! for method_missing. + # Handle *_will_change! for +method_missing+. def attribute_will_change!(attr) changed_attributes[attr] = clone_attribute_value(:read_attribute, attr) end -- cgit v1.2.3 From 9d9c96af56986b84a732aa609569b5035825f5f8 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 25 May 2008 20:51:18 +0200 Subject: revised some conventions in validations docs --- activerecord/lib/active_record/validations.rb | 46 +++++++++++++-------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 0e150bddb2..7f04dc4c1a 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -1,5 +1,5 @@ module ActiveRecord - # Raised by save! and create! when the record is invalid. Use the + # Raised by save! and create! when the record is invalid. Use the # +record+ method to retrieve the record which did not validate. # begin # complex_operation_that_calls_save!_internally @@ -52,7 +52,7 @@ module ActiveRecord # Adds an error to the base object instead of any particular attribute. This is used # to report errors that don't tie to any specific attribute, but rather to the object # as a whole. These error messages don't get prepended with any field name when iterating - # with each_full, so they should be complete sentences. + # with +each_full+, so they should be complete sentences. def add_to_base(msg) add(:base, msg) end @@ -97,7 +97,7 @@ module ActiveRecord !@errors[attribute.to_s].nil? end - # Returns nil, if no errors are associated with the specified +attribute+. + # Returns +nil+, if no errors are associated with the specified +attribute+. # Returns the error message, if one error is associated with the specified +attribute+. # Returns an array of error messages, if more than one error is associated with the specified +attribute+. # @@ -118,7 +118,7 @@ module ActiveRecord alias :[] :on - # Returns errors assigned to the base object through add_to_base according to the normal rules of on(attribute). + # Returns errors assigned to the base object through +add_to_base+ according to the normal rules of on(attribute). def on_base on(:base) end @@ -131,15 +131,15 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } # => - # name - is too short (minimum is 5 characters) - # name - can't be blank - # address - can't be blank + # company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } + # # => name - is too short (minimum is 5 characters) + # # name - can't be blank + # # address - can't be blank def each @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } } end - # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned + # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned # through iteration as "First name can't be empty". # # class Company < ActiveRecord::Base @@ -148,10 +148,10 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.each_full{|msg| puts msg } # => - # Name is too short (minimum is 5 characters) - # Name can't be blank - # Address can't be blank + # company.errors.each_full{|msg| puts msg } + # # => Name is too short (minimum is 5 characters) + # # Name can't be blank + # # Address can't be blank def each_full full_messages.each { |msg| yield msg } end @@ -164,8 +164,8 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.full_messages # => - # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] + # company.errors.full_messages + # # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] def full_messages full_messages = [] @@ -209,13 +209,13 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.to_xml # => - # - # - # Name is too short (minimum is 5 characters) - # Name can't be blank - # Address can't be blank - # + # company.errors.to_xml + # # => + # # + # # Name is too short (minimum is 5 characters) + # # Name can't be blank + # # Address can't be blank + # # def to_xml(options={}) options[:root] ||= "errors" options[:indent] ||= 2 @@ -261,7 +261,7 @@ module ActiveRecord # person.errors.on "phone_number" # => "has invalid format" # person.errors.each_full { |msg| puts msg } # # => "Last name can't be empty\n" + - # "Phone number has invalid format" + # # "Phone number has invalid format" # # person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" } # person.save # => true (and person is now saved in the database) -- cgit v1.2.3 From c5d37c0662a65ce9723d668f57b59457e79ee5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Mon, 26 May 2008 01:28:56 +0300 Subject: Fix tests for postgres 8.3.x Made test_with_limiting_with_custom_select not dependent on database default order. Fixed tests with non-US monetary locale. The monetary type is fixed precision so it should not expect the database to return a float. Signed-off-by: Pratik Naik --- activerecord/test/cases/datatype_test_postgresql.rb | 8 ++++---- activerecord/test/cases/finder_test.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/datatype_test_postgresql.rb b/activerecord/test/cases/datatype_test_postgresql.rb index 41726ce518..bff092b5d7 100644 --- a/activerecord/test/cases/datatype_test_postgresql.rb +++ b/activerecord/test/cases/datatype_test_postgresql.rb @@ -30,8 +30,8 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase @connection.execute("INSERT INTO postgresql_arrays (commission_by_quarter, nicknames) VALUES ( '{35000,21000,18000,17000}', '{foo,bar,baz}' )") @first_array = PostgresqlArray.find(1) - @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('$567.89')") - @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('-$567.89')") + @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('567.89'::money)") + @connection.execute("INSERT INTO postgresql_moneys (wealth) VALUES ('-567.89'::money)") @first_money = PostgresqlMoney.find(1) @second_money = PostgresqlMoney.find(2) @@ -143,11 +143,11 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase end def test_update_money - new_value = 123.45 + new_value = BigDecimal.new('123.45') assert @first_money.wealth = new_value assert @first_money.save assert @first_money.reload - assert_equal @first_money.wealth, new_value + assert_equal new_value, @first_money.wealth end def test_update_number diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 5c0f0e2ef1..80936d51f3 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -867,7 +867,7 @@ class FinderTest < ActiveRecord::TestCase end def test_with_limiting_with_custom_select - posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3) + posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3, :order => 'posts.id') assert_equal 3, posts.size assert_equal [0, 1, 1], posts.map(&:author_id).sort end -- cgit v1.2.3 From c2fbcba16d2349285368c86b849db946dc0e7d57 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Tue, 27 May 2008 07:31:53 -0700 Subject: Ensure named_scope#empty? uses count query. [#262 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/named_scope.rb | 6 +++++- activerecord/test/cases/named_scope_test.rb | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 69b7da7700..b0c8a8b815 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -102,7 +102,7 @@ module ActiveRecord attr_reader :proxy_scope, :proxy_options [].methods.each do |m| - unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last)/ + unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?)/ delegate m, :to => :proxy_found end end @@ -135,6 +135,10 @@ module ActiveRecord end end + def empty? + @found ? @found.empty? : count.zero? + end + protected def proxy_found @found || load_found diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 8f2fc53d67..d890cf7936 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -146,4 +146,12 @@ class NamedScopeTest < ActiveRecord::TestCase end end + def test_empty_should_not_load_results + topics = Topic.base + assert_queries(2) do + topics.empty? # use count query + topics.collect # force load + topics.empty? # use loaded (no query) + end + end end -- cgit v1.2.3 From 4d248543429918bc5a63e109e6f2327ffab9848b Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 28 May 2008 22:58:45 +0100 Subject: Ensure correct db time is reported in production logs. --- .../active_record/connection_adapters/abstract_adapter.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 8c286f64db..f48b107a2a 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -128,15 +128,11 @@ module ActiveRecord protected def log(sql, name) if block_given? - if @logger and @logger.debug? - result = nil - seconds = Benchmark.realtime { result = yield } - @runtime += seconds - log_info(sql, name, seconds) - result - else - yield - end + result = nil + seconds = Benchmark.realtime { result = yield } + @runtime += seconds + log_info(sql, name, seconds) + result else log_info(sql, name, 0) nil -- cgit v1.2.3 From abb1bd2efa43b8efbb3faf4ccfb9246704a9044c Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 29 May 2008 10:20:39 +0100 Subject: Ensure AssociationCollection#count works with empty condition. [#271 state:resolved] [Jan De Poorter] --- activerecord/lib/active_record/associations/has_many_association.rb | 2 +- activerecord/test/cases/associations/has_many_associations_test.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 963a938485..f584a97cbb 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -9,7 +9,7 @@ module ActiveRecord @reflection.klass.count_by_sql(@finder_sql) else column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args) - options[:conditions] = options[:conditions].nil? ? + options[:conditions] = options[:conditions].blank? ? @finder_sql : @finder_sql + " AND (#{sanitize_sql(options[:conditions])})" options[:include] ||= @reflection.options[:include] diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 53b55022eb..cbc621b411 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -32,6 +32,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, Firm.find(:first).plain_clients.count end + def test_counting_with_empty_hash_conditions + assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => {}) + end + def test_counting_with_single_conditions assert_equal 2, Firm.find(:first).plain_clients.count(:conditions => '1=1') end -- cgit v1.2.3 From 235d635708dd72bee0828457af5397c79750483a Mon Sep 17 00:00:00 2001 From: Andrew White Date: Thu, 29 May 2008 12:59:29 +0100 Subject: Ensure :select passed in options overrides the one from the scope. [#239 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/base.rb | 2 +- activerecord/test/cases/method_scoping_test.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c393128621..d2d9bda6ba 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1457,7 +1457,7 @@ module ActiveRecord #:nodoc: def construct_finder_sql(options) scope = scope(:find) - sql = "SELECT #{(scope && scope[:select]) || options[:select] || (options[:joins] && quoted_table_name + '.*') || '*'} " + sql = "SELECT #{options[:select] || (scope && scope[:select]) || (options[:joins] && quoted_table_name + '.*') || '*'} " sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} " add_joins!(sql, options, scope) diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 4b5bd6c951..1a9a875730 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -50,6 +50,22 @@ class MethodScopingTest < ActiveRecord::TestCase end end + def test_scoped_find_select + Developer.with_scope(:find => { :select => "id, name" }) do + developer = Developer.find(:first, :conditions => "name = 'David'") + assert_equal "David", developer.name + assert !developer.has_attribute?(:salary) + end + end + + def test_options_select_replaces_scope_select + Developer.with_scope(:find => { :select => "id, name" }) do + developer = Developer.find(:first, :select => 'id, salary', :conditions => "name = 'David'") + assert_equal 80000, developer.salary + assert !developer.has_attribute?(:name) + end + end + def test_scoped_count Developer.with_scope(:find => { :conditions => "name = 'David'" }) do assert_equal 1, Developer.count -- cgit v1.2.3 From 2ce1be3ac4823ccdfbe36ff5548a562aa5106d2e Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 30 May 2008 04:16:57 -0700 Subject: Enable partial updates by default --- activerecord/lib/active_record/dirty.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 8fdc763292..b32e17e990 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -43,7 +43,7 @@ module ActiveRecord base.alias_method_chain :reload, :dirty base.superclass_delegating_accessor :partial_updates - base.partial_updates = false + base.partial_updates = true end # Do any attributes have unsaved changes? -- cgit v1.2.3 From 03ba5d7b5183e7cb199a21aa6e06d646f7a5cbfe Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Fri, 30 May 2008 04:36:00 -0700 Subject: Ensure query assertion counts are the same when partial updates are enabled --- activerecord/test/cases/associations/has_many_associations_test.rb | 2 ++ .../test/cases/associations/has_many_through_associations_test.rb | 1 + 2 files changed, 3 insertions(+) (limited to 'activerecord') diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index cbc621b411..dbfa025efb 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -350,6 +350,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal "Another Client", new_client.name assert new_client.new_record? assert_equal new_client, company.clients_of_firm.last + company.name += '-changed' assert_queries(2) { assert company.save } assert !new_client.new_record? assert_equal 2, company.clients_of_firm(true).size @@ -360,6 +361,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } assert_equal 2, new_clients.size + company.name += '-changed' assert_queries(3) { assert company.save } assert_equal 3, company.clients_of_firm(true).size end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 5561361bca..05155f6303 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -59,6 +59,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase # * 2 new records = 4 # + 1 query to save the actual post = 5 assert_queries(5) do + posts(:thinking).body += '-changed' posts(:thinking).save end -- cgit v1.2.3 From f7015336f66d284cff8ecb89df9f430791ac57ea Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Sat, 31 May 2008 12:36:07 -0700 Subject: Fix default nil tests for MySQL 5.0.51 [#192 state:resolved] Signed-off-by: Joshua Peek --- activerecord/test/cases/defaults_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index bd19ffcc29..2ea85417da 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -5,7 +5,7 @@ require 'models/entrant' class DefaultTest < ActiveRecord::TestCase def test_nil_defaults_for_not_null_columns column_defaults = - if current_adapter?(:MysqlAdapter) + if current_adapter?(:MysqlAdapter) && Mysql.client_version < 50051 { 'id' => nil, 'name' => '', 'course_id' => nil } else { 'id' => nil, 'name' => nil, 'course_id' => nil } -- cgit v1.2.3 From 0580b31b36c0f7dd1a0f8bdd1b1806e3bd65b22d Mon Sep 17 00:00:00 2001 From: Tim Harper Date: Tue, 13 May 2008 19:17:40 -0600 Subject: belongs_to polymorphic association assignments update the foreign_id and foreign_type fields regardless of whether the record being assigned is new or not. fixes the following scenarios: * I have validates_inclusion_of on the type field for a polymorphic belongs_to association. I assign a new record to the model's polymorphic relationship of the proper type. validation fails because the type field has not been updated. * I replace the value for a ppolymorphic association to a new record of another class. The type field still says its the previous class, and the id field points to the previous record as well. [#191 state:closed] --- .../belongs_to_polymorphic_association.rb | 6 ++--- .../associations/belongs_to_associations_test.rb | 29 +++++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index df4ae38f38..d8146daa54 100755 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,10 +7,8 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - unless record.new_record? - @owner[@reflection.primary_key_name] = record.id - @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s - end + @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 3073eae355..e0da8bfb7a 100755 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -12,6 +12,8 @@ require 'models/author' require 'models/tag' require 'models/tagging' require 'models/comment' +require 'models/sponsor' +require 'models/member' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -381,5 +383,30 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! } assert companies(:first_client).readonly_firm.readonly? end - + + def test_polymorphic_assignment_foreign_type_field_updating + # should update when assigning a saved record + sponsor = Sponsor.new + member = Member.create + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + + # should update when assigning a new record + sponsor = Sponsor.new + member = Member.new + sponsor.sponsorable = member + assert_equal "Member", sponsor.sponsorable_type + end + + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records + sponsor = Sponsor.new + saved_member = Member.create + new_member = Member.new + + sponsor.sponsorable = saved_member + assert_equal saved_member.id, sponsor.sponsorable_id + + sponsor.sponsorable = new_member + assert_equal nil, sponsor.sponsorable_id + end end -- cgit v1.2.3 From ef0ea782b1f5cf7b08e74ea3002a16c708f66645 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 31 May 2008 16:57:46 -0700 Subject: Added SQL escaping for :limit and :offset [#288 state:closed] (Aaron Bedra, Steven Bristol, Jonathan Wiess) --- .../abstract/database_statements.rb | 9 +++++++-- activerecord/test/cases/adapter_test.rb | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 16d405d3bd..5358491cde 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -106,11 +106,16 @@ module ActiveRecord # SELECT * FROM suppliers LIMIT 10 OFFSET 50 def add_limit_offset!(sql, options) if limit = options[:limit] - sql << " LIMIT #{limit}" + sql << " LIMIT #{sanitize_limit(limit)}" if offset = options[:offset] - sql << " OFFSET #{offset}" + sql << " OFFSET #{offset.to_i}" end end + sql + end + + def sanitize_limit(limit) + limit.to_s[/,/] ? limit.split(',').map{ |i| i.to_i }.join(',') : limit.to_i end # Appends a locking clause to an SQL statement. diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 91504af901..c77446f880 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -104,4 +104,24 @@ class AdapterTest < ActiveRecord::TestCase end end + def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas + sql_inject = "1 select * from schema" + assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit=>sql_inject) + if current_adapter?(:MysqlAdapter) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + else + assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + end + end + + def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas + sql_inject = "1, 7 procedure help()" + if current_adapter?(:MysqlAdapter) + assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + else + assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) + assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + end + end end -- cgit v1.2.3 From f6e921f9568d7f2e4807edf8728e6b0df8991816 Mon Sep 17 00:00:00 2001 From: "John D. Hume" Date: Wed, 28 May 2008 23:35:56 -0400 Subject: Substitute value into validates_format_of message Signed-off-by: Michael Koziarski --- activerecord/lib/active_record/validations.rb | 2 +- activerecord/test/cases/validations_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 0e150bddb2..c97aafb126 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -692,7 +692,7 @@ module ActiveRecord raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless value.to_s =~ configuration[:with] + record.errors.add(attr_name, configuration[:message] % value) unless value.to_s =~ configuration[:with] end end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index a4d9da4806..7b71647d25 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -583,6 +583,12 @@ class ValidationsTest < ActiveRecord::TestCase assert_nil t.errors.on(:title) end + def test_validate_format_with_formatted_message + Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %s") + t = Topic.create(:title => 'Invalid title') + assert_equal "can't be Invalid title", t.errors.on(:title) + end + def test_validates_inclusion_of Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) ) -- cgit v1.2.3 From f9db7695fe3c148c8d1077f1564e5b94d126b83b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 31 May 2008 17:03:03 -0700 Subject: Making ready for release of 2.1 --- activerecord/CHANGELOG | 6 ++++-- activerecord/Rakefile | 2 +- activerecord/lib/active_record/version.rb | 4 ++-- activerecord/test/connections/native_mysql/connection.rb | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 78082665a4..f901e432d5 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,6 +1,8 @@ -* Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] +*2.1.0 (May 31st, 2008)* -*2.1.0 RC1 (May 11th, 2008)* +* Added SQL escaping for :limit and :offset #288 [Aaron Bedra, Steven Bristol, Jonathan Wiess] + +* Added first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] * Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung] diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 043ab6d551..fc068b16c3 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -171,7 +171,7 @@ spec = Gem::Specification.new do |s| s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) } end - s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD) + s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD) s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite" s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite" diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index 1463e84764..aaadef9979 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -1,8 +1,8 @@ module ActiveRecord module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 - TINY = 991 + MINOR = 1 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end diff --git a/activerecord/test/connections/native_mysql/connection.rb b/activerecord/test/connections/native_mysql/connection.rb index 1fab444e58..3ee031f384 100644 --- a/activerecord/test/connections/native_mysql/connection.rb +++ b/activerecord/test/connections/native_mysql/connection.rb @@ -12,13 +12,13 @@ ActiveRecord::Base.logger = RAILS_DEFAULT_LOGGER ActiveRecord::Base.configurations = { 'arunit' => { :adapter => 'mysql', - :username => 'rails', + :username => 'root', :encoding => 'utf8', :database => 'activerecord_unittest', }, 'arunit2' => { :adapter => 'mysql', - :username => 'rails', + :username => 'root', :database => 'activerecord_unittest2' } } -- cgit v1.2.3 From ea03b0885c110003496c1f99dc7d9d2f1534955b Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 31 May 2008 17:07:44 -0700 Subject: revert mysql test credential change --- activerecord/test/connections/native_mysql/connection.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/connections/native_mysql/connection.rb b/activerecord/test/connections/native_mysql/connection.rb index 3ee031f384..1fab444e58 100644 --- a/activerecord/test/connections/native_mysql/connection.rb +++ b/activerecord/test/connections/native_mysql/connection.rb @@ -12,13 +12,13 @@ ActiveRecord::Base.logger = RAILS_DEFAULT_LOGGER ActiveRecord::Base.configurations = { 'arunit' => { :adapter => 'mysql', - :username => 'root', + :username => 'rails', :encoding => 'utf8', :database => 'activerecord_unittest', }, 'arunit2' => { :adapter => 'mysql', - :username => 'root', + :username => 'rails', :database => 'activerecord_unittest2' } } -- cgit v1.2.3 From 72483c0d4c1e4ea794919974100acc2f255f6fd2 Mon Sep 17 00:00:00 2001 From: rick Date: Sat, 31 May 2008 17:13:11 -0700 Subject: Add ActiveRecord::Base.sti_name that checks ActiveRecord::Base#store_full_sti_class? and returns either the full or demodulized name. [rick] [#114 state:resolved] --- activerecord/CHANGELOG | 2 ++ .../associations/has_many_through_association.rb | 2 +- activerecord/lib/active_record/base.rb | 16 ++++++++++++---- activerecord/test/cases/inheritance_test.rb | 18 +++++++++++++++++- 4 files changed, 32 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 78082665a4..31e1c22f0d 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,3 +1,5 @@ +* Add ActiveRecord::Base.sti_name that checks ActiveRecord::Base#store_full_sti_class? and returns either the full or demodulized name. [rick] + * Add first/last methods to associations/named_scope. Resolved #226. [Ryan Bates] *2.1.0 RC1 (May 11th, 2008)* diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index ebcf462f2e..52ced36d16 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -237,7 +237,7 @@ module ActiveRecord end def build_sti_condition - "#{@reflection.through_reflection.quoted_table_name}.#{@reflection.through_reflection.klass.inheritance_column} = #{@reflection.klass.quote_value(@reflection.through_reflection.klass.name.demodulize)}" + "#{@reflection.through_reflection.quoted_table_name}.#{@reflection.through_reflection.klass.inheritance_column} = #{@reflection.klass.quote_value(@reflection.through_reflection.klass.sti_name)}" end alias_method :sql_conditions, :conditions diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index d2d9bda6ba..92a24ecc5f 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1293,6 +1293,10 @@ module ActiveRecord #:nodoc: super end + def sti_name + store_full_sti_class ? name : name.demodulize + end + private def find_initial(options) options.update(:limit => 1) @@ -1452,7 +1456,11 @@ module ActiveRecord #:nodoc: # Nest the type name in the same module as this class. # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo def type_name_with_module(type_name) - (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}" + if store_full_sti_class + type_name + else + (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}" + end end def construct_finder_sql(options) @@ -1571,8 +1579,8 @@ module ActiveRecord #:nodoc: def type_condition quoted_inheritance_column = connection.quote_column_name(inheritance_column) - type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? name : name.demodulize}' ") do |condition, subclass| - condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? subclass.name : subclass.name.demodulize}' " + type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{sti_name}' ") do |condition, subclass| + condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.sti_name}' " end " (#{type_condition}) " @@ -2508,7 +2516,7 @@ module ActiveRecord #:nodoc: # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? - write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : self.class.name.demodulize) + write_attribute(self.class.inheritance_column, self.class.sti_name) end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 27394924a1..f09b617e6d 100755 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -5,7 +5,23 @@ require 'models/subscriber' class InheritanceTest < ActiveRecord::TestCase fixtures :companies, :projects, :subscribers, :accounts - + + def test_class_with_store_full_sti_class_returns_full_name + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = true + assert_equal 'Namespaced::Company', Namespaced::Company.sti_name + ensure + ActiveRecord::Base.store_full_sti_class = old + end + + def test_class_without_store_full_sti_class_returns_demodulized_name + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = false + assert_equal 'Company', Namespaced::Company.sti_name + ensure + ActiveRecord::Base.store_full_sti_class = old + end + def test_should_store_demodulized_class_name_with_store_full_sti_class_option_disabled old = ActiveRecord::Base.store_full_sti_class ActiveRecord::Base.store_full_sti_class = false -- cgit v1.2.3 From 3282bf3b5016f0c9028cfff1012e8c31a13b40b7 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 1 Jun 2008 09:15:11 -0700 Subject: Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] --- activerecord/CHANGELOG | 5 +++++ activerecord/lib/active_record/connection_adapters/mysql_adapter.rb | 3 ++- activerecord/test/cases/adapter_test.rb | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 1c7c977141..a65771648e 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,3 +1,8 @@ +*Edge* + +* Added SQL escaping for :limit and :offset in MySQL [Jonathan Wiess] + + *2.1.0 (May 31st, 2008)* * Add ActiveRecord::Base.sti_name that checks ActiveRecord::Base#store_full_sti_class? and returns either the full or demodulized name. [rick] diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index f00a2c8950..653b45021d 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -336,10 +336,11 @@ module ActiveRecord def add_limit_offset!(sql, options) #:nodoc: if limit = options[:limit] + limit = sanitize_limit(limit) unless offset = options[:offset] sql << " LIMIT #{limit}" else - sql << " LIMIT #{offset}, #{limit}" + sql << " LIMIT #{offset.to_i}, #{limit}" end end end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index c77446f880..11f9870534 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -118,7 +118,7 @@ class AdapterTest < ActiveRecord::TestCase sql_inject = "1, 7 procedure help()" if current_adapter?(:MysqlAdapter) assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) - assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) + assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=> '1 ; DROP TABLE USERS', :offset=>7) else assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject) assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7) -- cgit v1.2.3 From d4b7cd99e8e7051c9d3ed6722f9627d5d4dea4e9 Mon Sep 17 00:00:00 2001 From: Evan Farrar Date: Wed, 4 Jun 2008 22:58:28 -0500 Subject: Mass typo and misspelling fix. --- activerecord/lib/active_record/association_preload.rb | 2 +- activerecord/lib/active_record/base.rb | 6 +++--- activerecord/lib/active_record/callbacks.rb | 2 +- .../active_record/connection_adapters/abstract/schema_statements.rb | 2 +- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 2 +- activerecord/lib/active_record/validations.rb | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index a3d1f12b03..087ed2a587 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -34,7 +34,7 @@ module ActiveRecord class_to_reflection = {} # Not all records have the same class, so group then preload # group on the reflection itself so that if various subclass share the same association then we do not split them - # unncessarily + # unnecessarily records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records| raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection send("preload_#{reflection.macro}_association", records, reflection, preload_options) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 92a24ecc5f..23318517fe 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -6,7 +6,7 @@ module ActiveRecord #:nodoc: class ActiveRecordError < StandardError end - # Raised when the single-table inheritance mechanism failes to locate the subclass + # Raised when the single-table inheritance mechanism fails to locate the subclass # (for example due to improper usage of column that +inheritance_column+ points to). class SubclassNotFound < ActiveRecordError #:nodoc: end @@ -97,7 +97,7 @@ module ActiveRecord #:nodoc: class MissingAttributeError < NoMethodError end - # Raised when an error occured while doing a mass assignment to an attribute through the + # Raised when an error occurred while doing a mass assignment to an attribute through the # attributes= method. The exception has an +attribute+ property that is the name of the # offending attribute. class AttributeAssignmentError < ActiveRecordError @@ -271,7 +271,7 @@ module ActiveRecord #:nodoc: # # Now 'Bob' exist and is an 'admin' # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true } # - # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be setted unless they are given in a block. For example: + # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be set unless they are given in a block. For example: # # # No 'Winter' tag exists # winter = Tag.find_or_initialize_by_name("Winter") diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 41ec5c5e61..6c2f65df05 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -50,7 +50,7 @@ module ActiveRecord # # == Inheritable callback queues # - # Besides the overwriteable callback methods, it's also possible to register callbacks through the use of the callback macros. + # Besides the overwritable callback methods, it's also possible to register callbacks through the use of the callback macros. # Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance # hierarchy. Example: # diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 67d70b3886..a2a1bb8c82 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -372,7 +372,7 @@ module ActiveRecord def add_column_options!(sql, options) #:nodoc: sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options) - # must explcitly check for :null to allow change_column to work on migrations + # must explicitly check for :null to allow change_column to work on migrations if options.has_key? :null if options[:null] == false sql << " NOT NULL" diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 7dbfbb41f6..7dc7398b0a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -805,7 +805,7 @@ module ActiveRecord end private - # The internal PostgreSQL identifer of the money data type. + # The internal PostgreSQL identifier of the money data type. MONEY_COLUMN_TYPE_OID = 790 #:nodoc: # Connects to a PostgreSQL server and sets up the adapter depending on the diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b9339c2924..52805ea851 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,7 +301,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the +validate+ instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldy and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: -- cgit v1.2.3