From 04775a41cbbddceeffa9cf8590566b9990fd4070 Mon Sep 17 00:00:00 2001 From: eparreno Date: Mon, 15 Nov 2010 19:21:40 +0100 Subject: remove old school validations and replaced with new validates method. Pending: fix active_record guide --- .../active_record_validations_callbacks.textile | 18 ++++---- railties/guides/source/i18n.textile | 48 +++++++++++----------- railties/guides/source/migrations.textile | 2 +- railties/guides/source/security.textile | 2 +- railties/guides/source/testing.textile | 2 +- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index e9ff6197ec..374c0f84a5 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -96,7 +96,7 @@ To verify whether or not an object is valid, Rails uses the +valid?+ method. You class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end Person.create(:name => "John Doe").valid? # => true @@ -109,7 +109,7 @@ Note that an object instantiated with +new+ will not report errors even if it's class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end >> p = Person.new @@ -147,7 +147,7 @@ This method is only useful _after_ validations have been run, because it only in class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end >> Person.new.errors[:name].any? # => false @@ -355,7 +355,7 @@ This helper validates that the specified attributes are not empty. It uses the + class Person < ActiveRecord::Base - validates_presence_of :name, :login, :email + validates :name, :presence => true, :login, :email end @@ -505,7 +505,7 @@ class Person < ActiveRecord::Base validates_numericality_of :age, :on => :update # the default (validates on both create and update) - validates_presence_of :name, :on => :save + validates :name, :presence => true, :on => :save end @@ -603,7 +603,7 @@ Returns an OrderedHash with all errors. Each key is the attribute name and the v class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 end @@ -623,7 +623,7 @@ h4(#working_with_validation_errors-errors-2). +errors[]+ class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 end @@ -699,7 +699,7 @@ The +clear+ method is used when you intentionally want to clear all the messages class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 end @@ -723,7 +723,7 @@ The +size+ method returns the total number of error messages for the object. class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 validates_presence_of :email end diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 8a7e9fcae6..4803264c97 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -672,11 +672,11 @@ Active Record validation error messages can also be translated easily. Active Re This gives you quite powerful means to flexibly adjust your messages to your application's needs. -Consider a User model with a +validates_presence_of+ validation for the name attribute like this: +Consider a User model with a validation for the name attribute like this: class User < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end @@ -706,7 +706,7 @@ For example, you might have an Admin model inheriting from User: class Admin < User - validates_presence_of :name + validates :name, :presence => true end @@ -733,27 +733,27 @@ So, for example, instead of the default error message +"can not be blank"+ you c * +count+, where available, can be used for pluralization if present: |_. validation |_.with option |_.message |_.interpolation| -| validates_confirmation_of | - | :confirmation | -| -| validates_acceptance_of | - | :accepted | -| -| validates_presence_of | - | :blank | -| -| validates_length_of | :within, :in | :too_short | count| -| validates_length_of | :within, :in | :too_long | count| -| validates_length_of | :is | :wrong_length | count| -| validates_length_of | :minimum | :too_short | count| -| validates_length_of | :maximum | :too_long | count| -| validates_uniqueness_of | - | :taken | -| -| validates_format_of | - | :invalid | -| -| validates_inclusion_of | - | :inclusion | -| -| validates_exclusion_of | - | :exclusion | -| -| validates_associated | - | :invalid | -| -| validates_numericality_of | - | :not_a_number | -| -| validates_numericality_of | :greater_than | :greater_than | count| -| validates_numericality_of | :greater_than_or_equal_to | :greater_than_or_equal_to | count| -| validates_numericality_of | :equal_to | :equal_to | count| -| validates_numericality_of | :less_than | :less_than | count| -| validates_numericality_of | :less_than_or_equal_to | :less_than_or_equal_to | count| -| validates_numericality_of | :odd | :odd | -| -| validates_numericality_of | :even | :even | -| +| confirmation | - | :confirmation | -| +| acceptance | - | :accepted | -| +| presence | - | :blank | -| +| length | :within, :in | :too_short | count| +| length | :within, :in | :too_long | count| +| length | :is | :wrong_length | count| +| length | :minimum | :too_short | count| +| length | :maximum | :too_long | count| +| uniqueness | - | :taken | -| +| format | - | :invalid | -| +| inclusion | - | :inclusion | -| +| exclusion | - | :exclusion | -| +| associated | - | :invalid | -| +| numericality | - | :not_a_number | -| +| numericality | :greater_than | :greater_than | count| +| numericality | :greater_than_or_equal_to | :greater_than_or_equal_to | count| +| numericality | :equal_to | :equal_to | count| +| numericality | :less_than | :less_than | count| +| numericality | :less_than_or_equal_to | :less_than_or_equal_to | count| +| numericality | :odd | :odd | -| +| numericality | :even | :even | -| h5. Translations for the Active Record +error_messages_for+ Helper diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 4c49a4ccbc..61d457e351 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -584,7 +584,7 @@ h3. Active Record and Referential Integrity The Active Record way claims that intelligence belongs in your models, not in the database. As such, features such as triggers or foreign key constraints, which push some of that intelligence back into the database, are not heavily used. -Validations such as +validates_uniqueness_of+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints. +Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints. Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. There are also a number of plugins such as "foreign_key_migrations":http://github.com/harukizaemon/redhillonrails/tree/master/foreign_key_migrations/ which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+). diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index 4656cf4e40..bc6e6e3390 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -550,7 +550,7 @@ Ruby uses a slightly different approach than many other languages to match the e class File < ActiveRecord::Base - validates_format_of :name, :with => /^[\w\.\-\+]+$/ + validates :name, format => /^[\w\.\-\+]+$/ end diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index 043a2462b4..aae849c369 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -315,7 +315,7 @@ Now to get this test to pass we can add a model level validation for the _title_ class Post < ActiveRecord::Base - validates_presence_of :title + validates :title, :presence => true end -- cgit v1.2.3 From 45e3827eb22b243c6bc4358fcbee7feed3de3873 Mon Sep 17 00:00:00 2001 From: zhengjia Date: Tue, 16 Nov 2010 09:26:21 -0600 Subject: Minor fix on Rails:Railtie documentation --- railties/lib/rails/railtie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index c76bc83377..030a838dc1 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -97,7 +97,7 @@ module Rails # If your railtie has rake tasks, you can tell Rails to load them through the method # rake tasks: # - # class MyRailtie < Railtie + # class MyRailtie < Rails::Railtie # rake_tasks do # load "path/to/my_railtie.tasks" # end @@ -107,7 +107,7 @@ module Rails # your generators at a different location, you can specify in your Railtie a block which # will load them during normal generators lookup: # - # class MyRailtie < Railtie + # class MyRailtie < Rails::Railtie # generators do # require "path/to/my_railtie_generator" # end -- cgit v1.2.3 From 0545d0eb993eff74143092b7ace2f85e9e809790 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Tue, 16 Nov 2010 22:25:20 +0100 Subject: i18n guide: it's activerecord.errors.messages.record_invalid (instead of 'invalid'), and messagges typo --- railties/guides/source/i18n.textile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 4803264c97..6bf52f1ac2 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -464,24 +464,24 @@ I18n.t 'message' The +translate+ method also takes a +:scope+ option which can contain one or more additional keys that will be used to specify a “namespace” or scope for a translation key: -I18n.t :invalid, :scope => [:activerecord, :errors, :messages] +I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages] -This looks up the +:invalid+ message in the Active Record error messages. +This looks up the +:record_invalid+ message in the Active Record error messages. Additionally, both the key and scopes can be specified as dot-separated keys as in: -I18n.translate :"activerecord.errors.messages.invalid" +I18n.translate "activerecord.errors.messages.record_invalid" Thus the following calls are equivalent: -I18n.t 'activerecord.errors.messages.invalid' -I18n.t 'errors.messages.invalid', :scope => :active_record -I18n.t :invalid, :scope => 'activerecord.errors.messages' -I18n.t :invalid, :scope => [:activerecord, :errors, :messages] +I18n.t 'activerecord.errors.messages.record_invalid' +I18n.t 'errors.messages.record_invalid', :scope => :active_record +I18n.t :record_invalid, :scope => 'activerecord.errors.messages' +I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages] h5. Defaults @@ -697,7 +697,7 @@ activerecord.errors.models.user.attributes.name.blank activerecord.errors.models.user.blank activerecord.errors.messages.blank errors.attributes.name.blank -errors.messagges.blank +errors.messages.blank When your models are additionally using inheritance then the messages are looked up in the inheritance chain. @@ -719,7 +719,7 @@ activerecord.errors.models.user.attributes.title.blank activerecord.errors.models.user.blank activerecord.errors.messages.blank errors.attributes.title.blank -errors.messagges.blank +errors.messages.blank This way you can provide special translations for various error messages at different points in your models inheritance chain and in the attributes, models, or default scopes. -- cgit v1.2.3 From 8f8abbbf7ae21f5bb88c2d43388532bcfe33ca94 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Tue, 16 Nov 2010 22:35:11 +0100 Subject: i18n guide: remove link to external page about 'How to encode the current locale in the URL' as it no longer exists --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 6bf52f1ac2..3e344c32b3 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -253,7 +253,7 @@ match '/:locale' => 'dashboard#index' Do take special care about the *order of your routes*, so this route declaration does not "eat" other ones. (You may want to add it directly before the +root :to+ declaration.) -IMPORTANT: This solution has currently one rather big *downside*. Due to the _default_url_options_ implementation, you have to pass the +:id+ option explicitly, like this: +link_to 'Show', book_url(:id => book)+ and not depend on Rails' magic in code like +link_to 'Show', book+. If this should be a problem, have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. See also the page "How to encode the current locale in the URL":http://rails-i18n.org/wiki/wikipages/how-to-encode-the-current-locale-in-the-url in the Rails i18n Wiki. +IMPORTANT: This solution has currently one rather big *downside*. Due to the _default_url_options_ implementation, you have to pass the +:id+ option explicitly, like this: +link_to 'Show', book_url(:id => book)+ and not depend on Rails' magic in code like +link_to 'Show', book+. If this should be a problem, have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. h4. Setting the Locale from the Client Supplied Information -- cgit v1.2.3 From 648568df1a61cf335d8b235487617777dcdea117 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Wed, 17 Nov 2010 09:24:47 +0100 Subject: i18n guide: this is not longer a problem --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 3e344c32b3..b42942bb63 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -253,7 +253,7 @@ match '/:locale' => 'dashboard#index' Do take special care about the *order of your routes*, so this route declaration does not "eat" other ones. (You may want to add it directly before the +root :to+ declaration.) -IMPORTANT: This solution has currently one rather big *downside*. Due to the _default_url_options_ implementation, you have to pass the +:id+ option explicitly, like this: +link_to 'Show', book_url(:id => book)+ and not depend on Rails' magic in code like +link_to 'Show', book+. If this should be a problem, have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. +NOTE: Have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. h4. Setting the Locale from the Client Supplied Information -- cgit v1.2.3 From 646e5202e001a7c12247ce66dc85b4edde50f25c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 17 Nov 2010 10:27:44 -0200 Subject: Typo fixed --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 7dc884f27b..8c72312f28 100644 --- a/Rakefile +++ b/Rakefile @@ -172,7 +172,7 @@ end # # Everything is automated and you do NOT need to run this task normally. # -# We publish a new verion by tagging, and pushing a tag does not trigger +# We publish a new version by tagging, and pushing a tag does not trigger # that webhook. Stable docs would be updated by any subsequent regular # push, but if you want that to happen right away just run this. # -- cgit v1.2.3 From 77440ec51ad28a7e63651f0976053584a7f58768 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 13:02:03 -0800 Subject: fixing assertions so error messages will be more helpful --- activerecord/test/cases/migration_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index ab9b35172b..f8eabd884a 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -1312,20 +1312,20 @@ if ActiveRecord::Base.connection.supports_migrations? def test_migrator_verbosity ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1) - assert PeopleHaveLastNames.message_count > 0 + assert_operator PeopleHaveLastNames.message_count, :>, 0 PeopleHaveLastNames.message_count = 0 ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0) - assert PeopleHaveLastNames.message_count > 0 + assert_operator PeopleHaveLastNames.message_count, :>, 0 PeopleHaveLastNames.message_count = 0 end def test_migrator_verbosity_off PeopleHaveLastNames.verbose = false ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1) - assert PeopleHaveLastNames.message_count.zero? + assert_equal 0, PeopleHaveLastNames.message_count ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0) - assert PeopleHaveLastNames.message_count.zero? + assert_equal 0, PeopleHaveLastNames.message_count end def test_migrator_going_down_due_to_version_target -- cgit v1.2.3 From 884e3506d2985d330badcb87ce070ee2b5de0d78 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 17 Nov 2010 19:35:58 -0200 Subject: Bump builder to 3.0.0 --- Rakefile | 1 + actionpack/actionpack.gemspec | 2 +- activemodel/activemodel.gemspec | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 8c72312f28..134dcb79bf 100644 --- a/Rakefile +++ b/Rakefile @@ -51,6 +51,7 @@ task :default => %w(test test:isolated) PROJECTS.each do |project| system(%(cd #{project} && #{$0} #{task_name})) || errors << project end + system(%(#{$0} #{task_name})) || errors << 'rails' if task_name == 'gem' fail("Errors in #{errors.join(', ')}") unless errors.empty? end end diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index c2af3dfaf5..44967631ff 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) s.add_dependency('rack-cache', '~> 0.5.3') - s.add_dependency('builder', '~> 2.1.2') + s.add_dependency('builder', '~> 3.0.0') s.add_dependency('i18n', '~> 0.4.2') s.add_dependency('rack', '~> 1.2.1') s.add_dependency('rack-test', '~> 0.5.6') diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec index 2d1263407f..318d71a610 100644 --- a/activemodel/activemodel.gemspec +++ b/activemodel/activemodel.gemspec @@ -20,6 +20,6 @@ Gem::Specification.new do |s| s.has_rdoc = true s.add_dependency('activesupport', version) - s.add_dependency('builder', '~> 2.1.2') + s.add_dependency('builder', '~> 3.0.0') s.add_dependency('i18n', '~> 0.4.2') end -- cgit v1.2.3 From 08eee5ce203a151798660d1aea26fa136d96a304 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 17 Nov 2010 20:06:19 -0200 Subject: Fix stupid error --- Rakefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Rakefile b/Rakefile index 134dcb79bf..8c72312f28 100644 --- a/Rakefile +++ b/Rakefile @@ -51,7 +51,6 @@ task :default => %w(test test:isolated) PROJECTS.each do |project| system(%(cd #{project} && #{$0} #{task_name})) || errors << project end - system(%(#{$0} #{task_name})) || errors << 'rails' if task_name == 'gem' fail("Errors in #{errors.join(', ')}") unless errors.empty? end end -- cgit v1.2.3 From fe2f168d40385a0412f41c1a2a44a5536cada8df Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 17 Nov 2010 16:36:51 -0500 Subject: fix warning during test execution [#5997 state:resolved] Signed-off-by: Santiago Pastorino --- actionpack/test/controller/action_pack_assertions_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 22ccd2e6b3..7f3d943bba 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -173,7 +173,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_string_constraint with_routing do |set| - set.draw do |map| + set.draw do match "photos", :to => 'action_pack_assertions#nothing', :constraints => {:subdomain => "admin"} end end -- cgit v1.2.3 From 8b2f801ed8690dcbc61d62e6b3518efaac70a4a4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 12:53:38 -0800 Subject: converted migrations to support instance methods --- activerecord/lib/active_record/migration.rb | 40 ++++++++++++++++++++++++----- activerecord/lib/active_record/schema.rb | 6 ++--- activerecord/test/cases/migration_test.rb | 8 +++--- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 2c306d233a..4a1a84b74b 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -287,10 +287,30 @@ module ActiveRecord # In application.rb. # class Migration - @@verbose = true - cattr_accessor :verbose - class << self + attr_accessor :verbose + attr_accessor :delegate # :nodoc: + def method_missing(name, *args, &block) # :nodoc: + (delegate || superclass.delegate).send(name, *args, &block) + end + end + self.delegate = new + self.verbose = true + + def name + self.class.name + end + + def up + self.class.delegate = self + self.class.up + end + + def down + self.class.delegate = self + self.class.down + end + def up_with_benchmarks #:nodoc: migrate(:up) end @@ -309,7 +329,7 @@ module ActiveRecord end result = nil - time = Benchmark.measure { result = send("#{direction}_without_benchmarks") } + time = Benchmark.measure { result = send("#{direction}") } case direction when :up then announce "migrated (%.4fs)" % time.real; write @@ -380,10 +400,19 @@ module ActiveRecord unless arguments.empty? || method == :execute arguments[0] = Migrator.proper_table_name(arguments.first) end + return super unless connection.respond_to?(method) connection.send(method, *arguments, &block) end end + def verbose + self.class.verbose + end + + def verbose= verbosity + self.class.verbose = verbosity + end + def copy(destination, sources, options = {}) copied = [] @@ -425,7 +454,6 @@ module ActiveRecord "%.3d" % number end end - end end # MigrationProxy is used to defer loading of the actual migration classes @@ -451,7 +479,7 @@ module ActiveRecord def load_migration require(File.expand_path(filename)) - name.constantize + name.constantize.new end end diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index c1bc3214ea..a621248cc3 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -30,9 +30,7 @@ module ActiveRecord # ActiveRecord::Schema is only supported by database adapters that also # support migrations, the two features being very similar. class Schema < Migration - private_class_method :new - - def self.migrations_path + def migrations_path ActiveRecord::Migrator.migrations_path end @@ -48,7 +46,7 @@ module ActiveRecord # ... # end def self.define(info={}, &block) - instance_eval(&block) + new.instance_eval(&block) unless info[:version].blank? initialize_schema_migrations_table diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index f8eabd884a..acb63d0031 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -18,10 +18,10 @@ if ActiveRecord::Base.connection.supports_migrations? class ActiveRecord::Migration class < Date: Wed, 17 Nov 2010 13:31:43 -0800 Subject: schema migrations work as instances --- activerecord/lib/active_record/migration.rb | 11 +++++++---- activerecord/lib/active_record/schema.rb | 5 +++-- activerecord/test/cases/migration_test.rb | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 4a1a84b74b..390c24c2f2 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -288,12 +288,15 @@ module ActiveRecord # class Migration class << self - attr_accessor :verbose attr_accessor :delegate # :nodoc: - def method_missing(name, *args, &block) # :nodoc: - (delegate || superclass.delegate).send(name, *args, &block) - end end + + def self.method_missing(name, *args, &block) # :nodoc: + (delegate || superclass.delegate).send(name, *args, &block) + end + + cattr_accessor :verbose + self.delegate = new self.verbose = true diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index a621248cc3..c6bb5c1961 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -46,11 +46,12 @@ module ActiveRecord # ... # end def self.define(info={}, &block) - new.instance_eval(&block) + schema = new + schema.instance_eval(&block) unless info[:version].blank? initialize_schema_migrations_table - assume_migrated_upto_version(info[:version], migrations_path) + assume_migrated_upto_version(info[:version], schema.migrations_path) end end end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index acb63d0031..5cd6c735af 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -19,6 +19,7 @@ if ActiveRecord::Base.connection.supports_migrations? class < Date: Wed, 17 Nov 2010 13:44:26 -0800 Subject: singleton method added is no longer needed --- activerecord/lib/active_record/migration.rb | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 390c24c2f2..936e9a19a2 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -332,7 +332,7 @@ module ActiveRecord end result = nil - time = Benchmark.measure { result = send("#{direction}") } + time = Benchmark.measure { result = send(direction) } case direction when :up then announce "migrated (%.4fs)" % time.real; write @@ -342,24 +342,6 @@ module ActiveRecord result end - # Because the method added may do an alias_method, it can be invoked - # recursively. We use @ignore_new_methods as a guard to indicate whether - # it is safe for the call to proceed. - def singleton_method_added(sym) #:nodoc: - return if defined?(@ignore_new_methods) && @ignore_new_methods - - begin - @ignore_new_methods = true - - case sym - when :up, :down - singleton_class.send(:alias_method_chain, sym, "benchmarks") - end - ensure - @ignore_new_methods = false - end - end - def write(text="") puts(text) if verbose end -- cgit v1.2.3 From 68b66ef3082b5d6ca47f621ea51cad9321847caf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 13:55:03 -0800 Subject: testing instance based migrations --- activerecord/lib/active_record/migration.rb | 2 ++ activerecord/test/cases/migration_test.rb | 38 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 936e9a19a2..470f63e8f7 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -306,11 +306,13 @@ module ActiveRecord def up self.class.delegate = self + return unless self.class.respond_to?(:up) self.class.up end def down self.class.delegate = self + return unless self.class.respond_to?(:down) self.class.down end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 5cd6c735af..3037d73a1b 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -1166,6 +1166,44 @@ if ActiveRecord::Base.connection.supports_migrations? assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) } end + class MockMigration < ActiveRecord::Migration + attr_reader :went_up, :went_down + def initialize + @went_up = false + @went_down = false + end + + def up + @went_up = true + super + end + + def down + @went_down = true + super + end + end + + def test_instance_based_migration_up + migration = MockMigration.new + assert !migration.went_up, 'have not gone up' + assert !migration.went_down, 'have not gone down' + + migration.migrate :up + assert migration.went_up, 'have gone up' + assert !migration.went_down, 'have not gone down' + end + + def test_instance_based_migration_down + migration = MockMigration.new + assert !migration.went_up, 'have not gone up' + assert !migration.went_down, 'have not gone down' + + migration.migrate :down + assert !migration.went_up, 'have gone up' + assert migration.went_down, 'have not gone down' + end + def test_migrator_one_up assert !Person.column_methods_hash.include?(:last_name) assert !Reminder.table_exists? -- cgit v1.2.3 From b0a6f58068394d11841b57d94b3a6ecb42c3b8b0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:10:51 -0800 Subject: do not need these accessors --- activerecord/lib/active_record/migration.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 470f63e8f7..6acb8382e7 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -392,14 +392,6 @@ module ActiveRecord end end - def verbose - self.class.verbose - end - - def verbose= verbosity - self.class.verbose = verbosity - end - def copy(destination, sources, options = {}) copied = [] -- cgit v1.2.3 From 17c7723451eba00eddbacf65e47d151e3ccafa5b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:26:14 -0800 Subject: updating CHANGELOG --- activerecord/CHANGELOG | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 11eb47917d..7f54c0fa30 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,14 @@ *Rails 3.1.0 (unreleased)* +* Migrations should use instance methods rather than class methods: + class FooMigration < ActiveRecord::Migration + def up + ... + end + end + + [Aaron Patterson] + * has_one maintains the association with separate after_create/after_update instead of a single after_save. [fxn] -- cgit v1.2.3 From aafac200be0691aa97daf67b4a12ff8199dd7fe3 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 17 Nov 2010 22:46:28 +0100 Subject: Fix generators tests on ruby 1.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/generators_test.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index 3a3e28179a..3c52a07bdb 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -26,15 +26,17 @@ module ApplicationTests end test "allow running plugin new generator inside Rails app directory" do - FileUtils.cd rails_root - `./script/rails plugin new vendor/plugins/bukkits` - assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb")) + FileUtils.cd rails_root do + `ruby script/rails plugin new vendor/plugins/bukkits` + assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb")) + end end test "don't allow running plugin_new generator as a generator" do - FileUtils.cd rails_root - output = `./script/rails g plugin_new vendor/plugins/bukkits` - assert_match /This generator should not be used directly as a generator. You should use `rails plugin new` command instead/, output + FileUtils.cd rails_root do + output = `ruby script/rails g plugin_new vendor/plugins/bukkits` + assert_match /This generator should not be used directly as a generator. You should use `rails plugin new` command instead/, output + end end test "generators default values" do -- cgit v1.2.3 From 7b2f2c8b477adae9bc7243fb9c895f8a823188a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 17 Nov 2010 23:31:29 +0100 Subject: Tidy up generators commits. --- railties/lib/rails/commands.rb | 5 +---- railties/lib/rails/generators.rb | 1 + railties/test/application/generators_test.rb | 13 ++----------- railties/test/generators_test.rb | 6 ++++++ 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index de5d876c18..338565247f 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -12,11 +12,8 @@ command = aliases[command] || command case command when 'generate', 'destroy', 'plugin' - if command == "plugin" && ARGV.first == "new" + if command == 'plugin' && ARGV.first == 'new' require "rails/commands/plugin_new" - elsif command == 'generate' && ARGV.first == "plugin_new" - puts "This generator should not be used directly as a generator. You should use `rails plugin new` command instead" - exit(1) else require APP_PATH Rails.application.require_environment! diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 240810b8bd..27a4007c20 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -228,6 +228,7 @@ module Rails rails = groups.delete("rails") rails.map! { |n| n.sub(/^rails:/, '') } rails.delete("app") + rails.delete("plugin_new") print_list("rails", rails) hidden_namespaces.each {|n| groups.delete(n.to_s) } diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index 3c52a07bdb..8b840fffd0 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -26,17 +26,8 @@ module ApplicationTests end test "allow running plugin new generator inside Rails app directory" do - FileUtils.cd rails_root do - `ruby script/rails plugin new vendor/plugins/bukkits` - assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb")) - end - end - - test "don't allow running plugin_new generator as a generator" do - FileUtils.cd rails_root do - output = `ruby script/rails g plugin_new vendor/plugins/bukkits` - assert_match /This generator should not be used directly as a generator. You should use `rails plugin new` command instead/, output - end + FileUtils.cd(rails_root){ `ruby script/rails plugin new vendor/plugins/bukkits` } + assert File.exist?(File.join(rails_root, "vendor/plugins/bukkits/test/dummy/config/application.rb")) end test "generators default values" do diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index f93800a5ae..346c9ceb9d 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -102,6 +102,12 @@ class GeneratorsTest < Rails::Generators::TestCase assert_no_match /^ app$/, output end + def test_rails_generators_help_does_not_include_app_nor_plugin_new + output = capture(:stdout){ Rails::Generators.help } + assert_no_match /app/, output + assert_no_match /plugin_new/, output + end + def test_rails_generators_with_others_information output = capture(:stdout){ Rails::Generators.help } assert_match /Fixjour:/, output -- cgit v1.2.3 From f14c2bf58204f488cbe589e077a124865ea595f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 17 Nov 2010 23:50:45 +0100 Subject: Pass the view object as parameter to the handler. Useful if you need to access the lookup context or other information when compiling the template. --- actionpack/lib/action_view/template.rb | 3 ++- actionpack/test/template/render_test.rb | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index dbb1532cd4..6c6d659246 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -269,7 +269,8 @@ module ActionView end end - code = @handler.call(self) + arity = @handler.respond_to?(:arity) ? @handler.arity : @handler.method(:call).arity + code = arity == 1 ? @handler.call(self) : @handler.call(self, view) # Make sure that the resulting String to be evalled is in the # encoding of the code diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index d2bf45a63a..8087429d62 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -221,6 +221,15 @@ module RenderTestCases "@output_buffer << 'source: #{template.source.inspect}'\n" end + WithViewHandler = lambda do |template, view| + %'"#{template.class} #{view.class}"' + end + + def test_render_inline_with_template_handler_with_view + ActionView::Template.register_template_handler :with_view, WithViewHandler + assert_equal 'ActionView::Template ActionView::Base', @view.render(:inline => "Hello, World!", :type => :with_view) + end + def test_render_inline_with_compilable_custom_type ActionView::Template.register_template_handler :foo, CustomHandler assert_equal 'source: "Hello, World!"', @view.render(:inline => "Hello, World!", :type => :foo) -- cgit v1.2.3 From 606e41a4dd67fd0af2166b9b74836c2fd11c189e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:48:12 -0800 Subject: these methods are no longer needed --- activerecord/lib/active_record/migration.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 6acb8382e7..222fb4d83c 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -316,14 +316,6 @@ module ActiveRecord self.class.down end - def up_with_benchmarks #:nodoc: - migrate(:up) - end - - def down_with_benchmarks #:nodoc: - migrate(:down) - end - # Execute this migration in the named direction def migrate(direction) return unless respond_to?(direction) -- cgit v1.2.3 From 7906e08bbacc2f7d96227e8a739c6762cd45a6ca Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:49:47 -0800 Subject: fixing indentation since these methods are not class methods --- activerecord/lib/active_record/migration.rb | 166 ++++++++++++++-------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 222fb4d83c..ca3ca54fa0 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -316,115 +316,115 @@ module ActiveRecord self.class.down end - # Execute this migration in the named direction - def migrate(direction) - return unless respond_to?(direction) + # Execute this migration in the named direction + def migrate(direction) + return unless respond_to?(direction) - case direction - when :up then announce "migrating" - when :down then announce "reverting" - end - - result = nil - time = Benchmark.measure { result = send(direction) } + case direction + when :up then announce "migrating" + when :down then announce "reverting" + end - case direction - when :up then announce "migrated (%.4fs)" % time.real; write - when :down then announce "reverted (%.4fs)" % time.real; write - end + result = nil + time = Benchmark.measure { result = send(direction) } - result + case direction + when :up then announce "migrated (%.4fs)" % time.real; write + when :down then announce "reverted (%.4fs)" % time.real; write end - def write(text="") - puts(text) if verbose - end + result + end - def announce(message) - version = defined?(@version) ? @version : nil + def write(text="") + puts(text) if verbose + end - text = "#{version} #{name}: #{message}" - length = [0, 75 - text.length].max - write "== %s %s" % [text, "=" * length] - end + def announce(message) + version = defined?(@version) ? @version : nil - def say(message, subitem=false) - write "#{subitem ? " ->" : "--"} #{message}" - end + text = "#{version} #{name}: #{message}" + length = [0, 75 - text.length].max + write "== %s %s" % [text, "=" * length] + end - def say_with_time(message) - say(message) - result = nil - time = Benchmark.measure { result = yield } - say "%.4fs" % time.real, :subitem - say("#{result} rows", :subitem) if result.is_a?(Integer) - result - end + def say(message, subitem=false) + write "#{subitem ? " ->" : "--"} #{message}" + end - def suppress_messages - save, self.verbose = verbose, false - yield - ensure - self.verbose = save - end + def say_with_time(message) + say(message) + result = nil + time = Benchmark.measure { result = yield } + say "%.4fs" % time.real, :subitem + say("#{result} rows", :subitem) if result.is_a?(Integer) + result + end - def connection - ActiveRecord::Base.connection - end + def suppress_messages + save, self.verbose = verbose, false + yield + ensure + self.verbose = save + end - def method_missing(method, *arguments, &block) - arg_list = arguments.map{ |a| a.inspect } * ', ' + def connection + ActiveRecord::Base.connection + end - say_with_time "#{method}(#{arg_list})" do - unless arguments.empty? || method == :execute - arguments[0] = Migrator.proper_table_name(arguments.first) - end - return super unless connection.respond_to?(method) - connection.send(method, *arguments, &block) + def method_missing(method, *arguments, &block) + arg_list = arguments.map{ |a| a.inspect } * ', ' + + say_with_time "#{method}(#{arg_list})" do + unless arguments.empty? || method == :execute + arguments[0] = Migrator.proper_table_name(arguments.first) end + return super unless connection.respond_to?(method) + connection.send(method, *arguments, &block) end + end - def copy(destination, sources, options = {}) - copied = [] + def copy(destination, sources, options = {}) + copied = [] - FileUtils.mkdir_p(destination) unless File.exists?(destination) + FileUtils.mkdir_p(destination) unless File.exists?(destination) - destination_migrations = ActiveRecord::Migrator.migrations(destination) - last = destination_migrations.last - sources.each do |name, path| - source_migrations = ActiveRecord::Migrator.migrations(path) + destination_migrations = ActiveRecord::Migrator.migrations(destination) + last = destination_migrations.last + sources.each do |name, path| + source_migrations = ActiveRecord::Migrator.migrations(path) - source_migrations.each do |migration| - source = File.read(migration.filename) - source = "# This migration comes from #{name} (originally #{migration.version})\n#{source}" + source_migrations.each do |migration| + source = File.read(migration.filename) + source = "# This migration comes from #{name} (originally #{migration.version})\n#{source}" - if duplicate = destination_migrations.detect { |m| m.name == migration.name } - options[:on_skip].call(name, migration) if File.read(duplicate.filename) != source && options[:on_skip] - next - end + if duplicate = destination_migrations.detect { |m| m.name == migration.name } + options[:on_skip].call(name, migration) if File.read(duplicate.filename) != source && options[:on_skip] + next + end - migration.version = next_migration_number(last ? last.version + 1 : 0).to_i - new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.rb") - old_path, migration.filename = migration.filename, new_path - last = migration + migration.version = next_migration_number(last ? last.version + 1 : 0).to_i + new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.rb") + old_path, migration.filename = migration.filename, new_path + last = migration - FileUtils.cp(old_path, migration.filename) - copied << migration - options[:on_copy].call(name, migration, old_path) if options[:on_copy] - destination_migrations << migration - end + FileUtils.cp(old_path, migration.filename) + copied << migration + options[:on_copy].call(name, migration, old_path) if options[:on_copy] + destination_migrations << migration end - - copied end - def next_migration_number(number) - if ActiveRecord::Base.timestamped_migrations - [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max - else - "%.3d" % number - end + copied + end + + def next_migration_number(number) + if ActiveRecord::Base.timestamped_migrations + [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max + else + "%.3d" % number end + end end # MigrationProxy is used to defer loading of the actual migration classes -- cgit v1.2.3 From d1fcba81188fafae2a65cc4c2ebca67df3f36f75 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:52:52 -0800 Subject: fixing documentation, removing unused AS files --- activerecord/lib/active_record/migration.rb | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index ca3ca54fa0..80aa123fdd 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1,6 +1,3 @@ -require 'active_support/core_ext/kernel/singleton_class' -require 'active_support/core_ext/module/aliasing' - module ActiveRecord # Exception that can be raised to stop migrations from going backwards. class IrreversibleMigration < ActiveRecordError @@ -43,11 +40,11 @@ module ActiveRecord # Example of a simple migration: # # class AddSsl < ActiveRecord::Migration - # def self.up + # def up # add_column :accounts, :ssl_enabled, :boolean, :default => 1 # end # - # def self.down + # def down # remove_column :accounts, :ssl_enabled # end # end @@ -63,7 +60,7 @@ module ActiveRecord # Example of a more complex migration that also needs to initialize data: # # class AddSystemSettings < ActiveRecord::Migration - # def self.up + # def up # create_table :system_settings do |t| # t.string :name # t.string :label @@ -77,7 +74,7 @@ module ActiveRecord # :value => 1 # end # - # def self.down + # def down # drop_table :system_settings # end # end @@ -147,11 +144,11 @@ module ActiveRecord # # This will generate the file timestamp_add_fieldname_to_tablename, which will look like this: # class AddFieldnameToTablename < ActiveRecord::Migration - # def self.up + # def up # add_column :tablenames, :fieldname, :string # end # - # def self.down + # def down # remove_column :tablenames, :fieldname # end # end @@ -179,11 +176,11 @@ module ActiveRecord # Not all migrations change the schema. Some just fix the data: # # class RemoveEmptyTags < ActiveRecord::Migration - # def self.up + # def up # Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? } # end # - # def self.down + # def down # # not much we can do to restore deleted data # raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags" # end @@ -192,12 +189,12 @@ module ActiveRecord # Others remove columns when they migrate up instead of down: # # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration - # def self.up + # def up # remove_column :items, :incomplete_items_count # remove_column :items, :completed_items_count # end # - # def self.down + # def down # add_column :items, :incomplete_items_count # add_column :items, :completed_items_count # end @@ -206,11 +203,11 @@ module ActiveRecord # And sometimes you need to do something in SQL not abstracted directly by migrations: # # class MakeJoinUnique < ActiveRecord::Migration - # def self.up + # def up # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)" # end # - # def self.down + # def down # execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`" # end # end -- cgit v1.2.3 From c1a63c8dba00b9f6ed81b3a46ecf595273cd876d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:54:08 -0800 Subject: fixing more documentation --- activerecord/lib/active_record/migration.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 80aa123fdd..65befa7473 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -135,7 +135,7 @@ module ActiveRecord # in the db/migrate/ directory where timestamp is the # UTC formatted date and time that the migration was generated. # - # You may then edit the self.up and self.down methods of + # You may then edit the up and down methods of # MyNewMigration. # # There is a special syntactic shortcut to generate migrations that add fields to a table. @@ -220,7 +220,7 @@ module ActiveRecord # latest column data from after the new column was added. Example: # # class AddPeopleSalary < ActiveRecord::Migration - # def self.up + # def up # add_column :people, :salary, :integer # Person.reset_column_information # Person.find(:all).each do |p| @@ -240,7 +240,7 @@ module ActiveRecord # You can also insert your own messages and benchmarks by using the +say_with_time+ # method: # - # def self.up + # def up # ... # say_with_time "Updating salaries..." do # Person.find(:all).each do |p| -- cgit v1.2.3 From 4d35f8b6615d31fbed4806ee3c260e24447f435b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 14:57:46 -0800 Subject: updating generators --- .../rails/generators/active_record/migration/templates/migration.rb | 4 ++-- .../lib/rails/generators/active_record/model/templates/migration.rb | 4 ++-- .../generators/active_record/session_migration/templates/migration.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb index 8ac21c1410..126b6f434b 100644 --- a/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb +++ b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb @@ -1,5 +1,5 @@ class <%= migration_class_name %> < ActiveRecord::Migration - def self.up + def up <% attributes.each do |attribute| -%> <%- if migration_action -%> <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end %> @@ -7,7 +7,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration <%- end -%> end - def self.down + def down <% attributes.reverse.each do |attribute| -%> <%- if migration_action -%> <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end %> diff --git a/activerecord/lib/rails/generators/active_record/model/templates/migration.rb b/activerecord/lib/rails/generators/active_record/model/templates/migration.rb index 1f68487304..70e064be21 100644 --- a/activerecord/lib/rails/generators/active_record/model/templates/migration.rb +++ b/activerecord/lib/rails/generators/active_record/model/templates/migration.rb @@ -1,5 +1,5 @@ class <%= migration_class_name %> < ActiveRecord::Migration - def self.up + def up create_table :<%= table_name %> do |t| <% for attribute in attributes -%> t.<%= attribute.type %> :<%= attribute.name %> @@ -10,7 +10,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration end end - def self.down + def down drop_table :<%= table_name %> end end diff --git a/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb b/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb index 919822af7b..8f0bf1ef0d 100644 --- a/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb +++ b/activerecord/lib/rails/generators/active_record/session_migration/templates/migration.rb @@ -1,5 +1,5 @@ class <%= migration_class_name %> < ActiveRecord::Migration - def self.up + def up create_table :<%= session_table_name %> do |t| t.string :session_id, :null => false t.text :data @@ -10,7 +10,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration add_index :<%= session_table_name %>, :updated_at end - def self.down + def down drop_table :<%= session_table_name %> end end -- cgit v1.2.3 From 250fb3f6c297e1f0bdc80a44ae6ac77c04cd9c85 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 18 Nov 2010 00:06:03 +0100 Subject: Add config.action_controller.include_all_helpers, by default it is set to true. In older rails versions there was a way to use only helpers from helper file corresponding to current controller and you could also include all helpers by saying 'helper :all' in controller. This config allows to return to older behavior by setting it to false. --- actionpack/lib/action_controller/metal/helpers.rb | 3 +- actionpack/lib/action_controller/railties/paths.rb | 4 +- .../application/initializers/frameworks_test.rb | 60 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index d14831b763..91a88ab68a 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -53,8 +53,9 @@ module ActionController include AbstractController::Helpers included do - config_accessor :helpers_path + config_accessor :helpers_path, :include_all_helpers self.helpers_path ||= [] + self.include_all_helpers = true end module ClassMethods diff --git a/actionpack/lib/action_controller/railties/paths.rb b/actionpack/lib/action_controller/railties/paths.rb index 7a59d4f2f3..699c44c62c 100644 --- a/actionpack/lib/action_controller/railties/paths.rb +++ b/actionpack/lib/action_controller/railties/paths.rb @@ -13,7 +13,9 @@ module ActionController end klass.helpers_path = paths - klass.helper :all if klass.superclass == ActionController::Base + if klass.superclass == ActionController::Base && ActionController::Base.include_all_helpers + klass.helper :all + end end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 6970ea7b7a..475091f789 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -65,6 +65,66 @@ module ApplicationTests assert_equal ["notify"], Foo.action_methods end + test "allows to not load all helpers for controllers" do + add_to_config "config.action_controller.include_all_helpers = false" + + app_file "app/controllers/application_controller.rb", <<-RUBY + class ApplicationController < ActionController::Base + end + RUBY + + app_file "app/controllers/foo_controller.rb", <<-RUBY + class FooController < ApplicationController + def included_helpers + render :inline => "<%= from_app_helper -%> <%= from_foo_helper %>" + end + + def not_included_helper + render :inline => "<%= respond_to?(:from_bar_helper) -%>" + end + end + RUBY + + app_file "app/helpers/application_helper.rb", <<-RUBY + module ApplicationHelper + def from_app_helper + "from_app_helper" + end + end + RUBY + + app_file "app/helpers/foo_helper.rb", <<-RUBY + module FooHelper + def from_foo_helper + "from_foo_helper" + end + end + RUBY + + app_file "app/helpers/bar_helper.rb", <<-RUBY + module BarHelper + def from_bar_helper + "from_bar_helper" + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match "/:controller(/:action)" + end + RUBY + + require 'rack/test' + extend Rack::Test::Methods + + get "/foo/included_helpers" + assert_equal "from_app_helper from_foo_helper", last_response.body + + get "/foo/not_included_helper" + assert_equal "false", last_response.body + end + # AD test "action_dispatch extensions are applied to ActionDispatch" do add_to_config "config.action_dispatch.tld_length = 2" -- cgit v1.2.3 From ae56c82e2b9f16bf754320a541bf37362661d68f Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 18 Nov 2010 00:24:39 +0100 Subject: Added config.action_controller.include_all_helpers to CHANGELOG. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index db02beee35..74d017cc3d 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* Added config.action_controller.include_all_helpers. By default 'helper :all' is done in ActionController::Base, which includes all the helpers by default. Setting include_all_helpers to false will result in including only application_helper and helper corresponding to controller (like foo_helper for foo_controller). [Piotr Sarnacki] + * Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options: tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) -- cgit v1.2.3 From 43e2e10f4fd1111e485d4d1b1e509c00dc13c58c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 15:30:01 -0800 Subject: adding an initialize with name and version defaults --- activerecord/lib/active_record/migration.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 65befa7473..0eabc4a4aa 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -297,8 +297,11 @@ module ActiveRecord self.delegate = new self.verbose = true - def name - self.class.name + attr_accessor :name, :version + + def initialize + @name = self.class.name + @version = nil end def up @@ -338,8 +341,6 @@ module ActiveRecord end def announce(message) - version = defined?(@version) ? @version : nil - text = "#{version} #{name}: #{message}" length = [0, 75 - text.length].max write "== %s %s" % [text, "=" * length] -- cgit v1.2.3 From ae44bf7c7ebb39d9a12d5253016f92617bee79c7 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 18 Nov 2010 00:32:43 +0100 Subject: bye bye extlib_inheritable_*, AS callbacks now using class_attribute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activesupport/lib/active_support/callbacks.rb | 22 +++--- .../core_ext/class/inheritable_attributes.rb | 83 ---------------------- 2 files changed, 13 insertions(+), 92 deletions(-) diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 8f8def5922..905dfb040b 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,6 +1,6 @@ require 'active_support/descendants_tracker' require 'active_support/core_ext/array/wrap' -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/kernel/singleton_class' @@ -437,7 +437,7 @@ module ActiveSupport ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target| chain = target.send("_#{name}_callbacks") - yield chain, type, filters, options + yield target, chain.dup, type, filters, options target.__define_runner(name) end end @@ -473,7 +473,7 @@ module ActiveSupport def set_callback(name, *filter_list, &block) mapped = nil - __update_callbacks(name, filter_list, block) do |chain, type, filters, options| + __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options| mapped ||= filters.map do |filter| Callback.new(chain, filter, type, options.dup, self) end @@ -483,6 +483,8 @@ module ActiveSupport end options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped) + + target.send("_#{name}_callbacks=", chain) end end @@ -493,7 +495,7 @@ module ActiveSupport # end # def skip_callback(name, *filter_list, &block) - __update_callbacks(name, filter_list, block) do |chain, type, filters, options| + __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options| filters.each do |filter| filter = chain.find {|c| c.matches?(type, filter) } @@ -505,6 +507,7 @@ module ActiveSupport chain.delete(filter) end + target.send("_#{name}_callbacks=", chain) end end @@ -514,12 +517,14 @@ module ActiveSupport callbacks = send("_#{symbol}_callbacks") ActiveSupport::DescendantsTracker.descendants(self).each do |target| - chain = target.send("_#{symbol}_callbacks") + chain = target.send("_#{symbol}_callbacks").dup callbacks.each { |c| chain.delete(c) } + target.send("_#{symbol}_callbacks=", chain) target.__define_runner(symbol) end - callbacks.clear + self.send("_#{symbol}_callbacks=", callbacks.dup.clear) + __define_runner(symbol) end @@ -589,9 +594,8 @@ module ActiveSupport def define_callbacks(*callbacks) config = callbacks.last.is_a?(Hash) ? callbacks.pop : {} callbacks.each do |callback| - extlib_inheritable_reader("_#{callback}_callbacks") do - CallbackChain.new(callback, config) - end + class_attribute "_#{callback}_callbacks" + send("_#{callback}_callbacks=", CallbackChain.new(callback, config)) __define_runner(callback) end end diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb index af30bfc13a..043a650ea0 100644 --- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb @@ -169,86 +169,3 @@ class Class # :nodoc: alias inherited_without_inheritable_attributes inherited alias inherited inherited_with_inheritable_attributes end - -class Class - # Defines class-level inheritable attribute reader. Attributes are available to subclasses, - # each subclass has a copy of parent's attribute. - # - # @param *syms Array of attributes to define inheritable reader for. - # @return Array of attributes converted into inheritable_readers. - # - # @api public - # - # @todo Do we want to block instance_reader via :instance_reader => false - # @todo It would be preferable that we do something with a Hash passed in - # (error out or do the same as other methods above) instead of silently - # moving on). In particular, this makes the return value of this function - # less useful. - def extlib_inheritable_reader(*ivars, &block) - options = ivars.extract_options! - - ivars.each do |ivar| - self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def self.#{ivar} - return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar}) - ivar = superclass.#{ivar} - return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}") - @#{ivar} = ivar.duplicable? ? ivar.dup : ivar - end - RUBY - unless options[:instance_reader] == false - self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{ivar} - self.class.#{ivar} - end - RUBY - end - instance_variable_set(:"@#{ivar}", yield) if block_given? - end - end - - # Defines class-level inheritable attribute writer. Attributes are available to subclasses, - # each subclass has a copy of parent's attribute. - # - # @param *syms Boolean}]> Array of attributes to - # define inheritable writer for. - # @option syms :instance_writer if true, instance-level inheritable attribute writer is defined. - # @return An Array of the attributes that were made into inheritable writers. - # - # @api public - # - # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it - # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere. - def extlib_inheritable_writer(*ivars) - options = ivars.extract_options! - - ivars.each do |ivar| - self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def self.#{ivar}=(obj) - @#{ivar} = obj - end - RUBY - unless options[:instance_writer] == false - self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{ivar}=(obj) self.class.#{ivar} = obj end - RUBY - end - - self.send("#{ivar}=", yield) if block_given? - end - end - - # Defines class-level inheritable attribute accessor. Attributes are available to subclasses, - # each subclass has a copy of parent's attribute. - # - # @param *syms Boolean}]> Array of attributes to - # define inheritable accessor for. - # @option syms :instance_writer if true, instance-level inheritable attribute writer is defined. - # @return An Array of attributes turned into inheritable accessors. - # - # @api public - def extlib_inheritable_accessor(*syms, &block) - extlib_inheritable_reader(*syms) - extlib_inheritable_writer(*syms, &block) - end -end -- cgit v1.2.3 From f978c4b2e44401260bbf4b5a954fda0b2bc71781 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 17 Nov 2010 16:12:21 -0500 Subject: remove the rescue block by returning a not asking Base for lookup_ancestors. It was also marked for later optimization. --- activerecord/lib/active_record/base.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index b35f59d6df..60a9ca7464 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -736,15 +736,12 @@ module ActiveRecord #:nodoc: def lookup_ancestors #:nodoc: klass = self classes = [klass] + return classes if klass == ActiveRecord::Base + while klass != klass.base_class classes << klass = klass.superclass end classes - rescue - # OPTIMIZE this rescue is to fix this test: ./test/cases/reflection_test.rb:56:in `test_human_name_for_column' - # Apparently the method base_class causes some trouble. - # It now works for sure. - [self] end # Set the i18n scope to overwrite ActiveModel. -- cgit v1.2.3 From 9c1993bf6bdd0a3d2c46310c953631c1d5a7e3d1 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 17 Nov 2010 23:12:22 +0800 Subject: replace and with && as per rails coding convention --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 60a9ca7464..314f676711 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1283,7 +1283,7 @@ MSG # ["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 - if values.first.is_a?(Hash) and statement =~ /:\w+/ + if values.first.is_a?(Hash) && statement =~ /:\w+/ replace_named_bind_variables(statement, values.first) elsif statement.include?('?') replace_bind_variables(statement, values) -- cgit v1.2.3 From fe42c00ac38b834ee9ef34f0707558cf02dbe6c0 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 31 Oct 2010 11:16:16 +0000 Subject: Fix bug with 0bb85ed9ffa9808926b46e8f7e59cab5b85ac19f which missed out a fixtures declaration in cascaded_eager_loading_test.rb --- activerecord/test/cases/associations/cascaded_eager_loading_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 37c6f354a8..0742e311d9 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -10,7 +10,8 @@ require 'models/reply' require 'models/person' class CascadedEagerLoadingTest < ActiveRecord::TestCase - fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, :categorizations, :people + fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, + :categorizations, :people, :categories def test_eager_association_loading_with_cascaded_two_levels authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id") -- cgit v1.2.3 From 56c5820458fd3981161393c285cce67fdf35e60b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 16:14:17 -0800 Subject: use shorter form for sql literals --- activerecord/lib/active_record/relation/query_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 9c399d3333..514576564c 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -141,7 +141,7 @@ module ActiveRecord "#{@klass.table_name}.#{@klass.primary_key} DESC" : reverse_sql_order(order_clause).join(', ') - except(:order).order(Arel::SqlLiteral.new(order)) + except(:order).order(Arel.sql(order)) end def arel -- cgit v1.2.3 From 00693209ecc222842949d7cab076f89890cbd507 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 17:10:40 -0800 Subject: collapsing same table / column WHERE clauses to be OR [#4598 state:resolved] --- .../lib/active_record/relation/query_methods.rb | 29 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 514576564c..07ca2e2088 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -174,10 +174,7 @@ module ActiveRecord arel = build_joins(arel, @joins_values) unless @joins_values.empty? - (@where_values - ['']).uniq.each do |where| - where = Arel.sql(where) if String === where - arel = arel.where(Arel::Nodes::Grouping.new(where)) - end + arel = collapse_wheres(arel, (@where_values - ['']).uniq) arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty? @@ -198,6 +195,30 @@ module ActiveRecord private + def collapse_wheres(arel, wheres) + equalities = wheres.grep(Arel::Nodes::Equality) + + groups = equalities.group_by do |equality| + left = equality.left + # table, column + [left.relation.name, left.name] + end + + groups.each do |_, eqls| + head = eqls.first + test = eqls.inject(head) do |memo, expr| + expr == head ? expr : memo.or(expr) + end + arel = arel.where(test) + end + + (wheres - equalities).each do |where| + where = Arel.sql(where) if String === where + arel = arel.where(Arel::Nodes::Grouping.new(where)) + end + arel + end + def build_where(opts, other = []) case opts when String, Array -- cgit v1.2.3 From c6bfd6802ae4c8e179e875a707ec42bf73d13a20 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 15 May 2010 17:43:35 -0300 Subject: When use where more than once on the same column, relation doesn't do an 'or' or 'in' with the values --- activerecord/test/cases/relations_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index e39b1f396c..6649923421 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -451,6 +451,15 @@ class RelationTest < ActiveRecord::TestCase assert_equal author, authors end + def test_find_all_using_where_twice_should_or_the_relation + david = authors(:david) + relation = Author.unscoped + relation = relation.where(:name => david.name) + relation = relation.where(:name => 'Santiago') + relation = relation.where(:id => david.id) + assert_equal [david], relation.all + end + def test_exists davids = Author.where(:name => 'David') assert davids.exists? -- cgit v1.2.3 From 80d9b724c3f2f49ce99f1c41eddbebe7cf16686d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 17:28:40 -0800 Subject: group can be done by left side only --- activerecord/lib/active_record/relation/query_methods.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 07ca2e2088..9e7503a60d 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -199,15 +199,12 @@ module ActiveRecord equalities = wheres.grep(Arel::Nodes::Equality) groups = equalities.group_by do |equality| - left = equality.left - # table, column - [left.relation.name, left.name] + equality.left end groups.each do |_, eqls| - head = eqls.first - test = eqls.inject(head) do |memo, expr| - expr == head ? expr : memo.or(expr) + test = eqls.inject(eqls.shift) do |memo, expr| + memo.or(expr) end arel = arel.where(test) end -- cgit v1.2.3 From 126fbd7ed8a310bf940414c1b7ddab06b03d400e Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 17 Nov 2010 21:46:55 -0500 Subject: unscoped takes care of named_scopes too --- activerecord/lib/active_record/base.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index f588475bbf..d7a7101404 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -856,8 +856,7 @@ module ActiveRecord #:nodoc: # limit(10) # Fires "SELECT * FROM posts LIMIT 10" # } # - # It is recommended to use block form of unscoped because chaining unscoped with named_scope - # does not work. Assuming that published is a named_scope following two statements are same. + # Assuming that published is a named_scope following two statements are same. # # Post.unscoped.published # Post.published -- cgit v1.2.3 From d19768b50c246c55b0c57403a7b79006100cab0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 18 Nov 2010 09:32:48 +0100 Subject: Facepunch failing tests. --- railties/test/generators/migration_generator_test.rb | 12 ++++++------ railties/test/generators/model_generator_test.rb | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index f9d1e42d24..288ec30460 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -34,12 +34,12 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string", "body:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_class_method :up, content do |up| + assert_method :up, content do |up| assert_match /add_column :posts, :title, :string/, up assert_match /add_column :posts, :body, :text/, up end - assert_class_method :down, content do |down| + assert_method :down, content do |down| assert_match /remove_column :posts, :title/, down assert_match /remove_column :posts, :body/, down end @@ -51,12 +51,12 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string", "body:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_class_method :up, content do |up| + assert_method :up, content do |up| assert_match /remove_column :posts, :title/, up assert_match /remove_column :posts, :body/, up end - assert_class_method :down, content do |down| + assert_method :down, content do |down| assert_match /add_column :posts, :title, :string/, down assert_match /add_column :posts, :body, :text/, down end @@ -68,11 +68,11 @@ class MigrationGeneratorTest < Rails::Generators::TestCase run_generator [migration, "title:string", "content:text"] assert_migration "db/migrate/#{migration}.rb" do |content| - assert_class_method :up, content do |up| + assert_method :up, content do |up| assert_match /^\s*$/, up end - assert_class_method :down, content do |down| + assert_method :down, content do |down| assert_match /^\s*$/, down end end diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 52e08cf2dd..8a0f560bc8 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -99,13 +99,13 @@ class ModelGeneratorTest < Rails::Generators::TestCase run_generator ["product", "name:string", "supplier_id:integer"] assert_migration "db/migrate/create_products.rb" do |m| - assert_class_method :up, m do |up| + assert_method :up, m do |up| assert_match /create_table :products/, up assert_match /t\.string :name/, up assert_match /t\.integer :supplier_id/, up end - assert_class_method :down, m do |down| + assert_method :down, m do |down| assert_match /drop_table :products/, down end end @@ -141,7 +141,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase run_generator ["account", "--no-timestamps"] assert_migration "db/migrate/create_accounts.rb" do |m| - assert_class_method :up, m do |up| + assert_method :up, m do |up| assert_no_match /t.timestamps/, up end end -- cgit v1.2.3 From 03f141378705cb544986ad2db54169c8f1c464c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Hackin?= Date: Thu, 18 Nov 2010 08:25:38 -0200 Subject: Fix code for customize the error messages html adding a .html_safe of 8.3 section --- railties/guides/source/active_record_validations_callbacks.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 374c0f84a5..444a1d4154 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -824,10 +824,10 @@ Here is a simple example where we change the Rails behaviour to always display t ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| if instance.error_message.kind_of?(Array) %(#{html_tag}  - #{instance.error_message.join(',')}) + #{instance.error_message.join(',')}).html_safe else %(#{html_tag}  - #{instance.error_message}) + #{instance.error_message}).html_safe end end -- cgit v1.2.3 From 77fc0cc165bb389527edc7eae3cf2c4249da857f Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Thu, 18 Nov 2010 17:19:29 +0100 Subject: Ensure that initializers are executed before loading rake tasks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/test/application/rake_test.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 719550f9d9..23cd2378c7 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -34,6 +34,22 @@ module ApplicationTests assert_match "SuperMiddleware", Dir.chdir(app_path){ `rake middleware` } end + def test_initializers_are_executed_in_rake_tasks + add_to_config <<-RUBY + initializer "do_something" do + puts "Doing something..." + end + + rake_tasks do + task :do_nothing => :environment do + end + end + RUBY + + output = Dir.chdir(app_path){ `rake do_nothing` } + assert_match "Doing something...", output + end + def test_code_statistics_sanity assert_match "Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0", Dir.chdir(app_path){ `rake stats` } -- cgit v1.2.3 From c5a284f8eb6113f06030ea7a18543905146e8768 Mon Sep 17 00:00:00 2001 From: Alex Rothenberg Date: Mon, 8 Nov 2010 15:30:27 -0500 Subject: Adapters can specify maximum number of ids they support in a list of expressions (default is nil meaning unlimited but Oracle imposes a limit of 1000) Limit is used to make multiple queries when preloading associated has_many or habtm records --- .../lib/active_record/association_preload.rb | 26 ++++++++--- .../connection_adapters/abstract_adapter.rb | 5 +++ activerecord/test/cases/associations/eager_test.rb | 52 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 911a5155fd..a205549d60 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -193,13 +193,17 @@ module ActiveRecord conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}" conditions << append_conditions(reflection, preload_options) - associated_records = reflection.klass.unscoped.where([conditions, ids]). + associated_records_proxy = reflection.klass.unscoped. includes(options[:include]). joins("INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}"). select("#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id"). - order(options[:order]).to_a + order(options[:order]) - set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id') + all_associated_records = associated_records(ids) do |some_ids| + associated_records_proxy.where([conditions, ids]).to_a + end + + set_association_collection_records(id_to_record_map, reflection.name, all_associated_records, 'the_parent_record_id') end def preload_has_one_association(records, reflection, preload_options={}) @@ -358,13 +362,14 @@ module ActiveRecord find_options = { :select => preload_options[:select] || options[:select] || Arel::SqlLiteral.new("#{table_name}.*"), :include => preload_options[:include] || options[:include], - :conditions => [conditions, ids], :joins => options[:joins], :group => preload_options[:group] || options[:group], :order => preload_options[:order] || options[:order] } - reflection.klass.scoped.apply_finder_options(find_options).to_a + associated_records(ids) do |some_ids| + reflection.klass.scoped.apply_finder_options(find_options.merge(:conditions => [conditions, some_ids])).to_a + end end @@ -382,6 +387,17 @@ module ActiveRecord def in_or_equals_for_ids(ids) ids.size > 1 ? "IN (?)" : "= ?" end + + # Some databases impose a limit on the number of ids in a list (in Oracle its 1000) + # Make several smaller queries if necessary or make one query if the adapter supports it + def associated_records(ids) + max_ids_in_a_list = connection.ids_in_list_limit || ids.size + records = [] + ids.each_slice(max_ids_in_a_list) do |some_ids| + records += yield(some_ids) + end + records + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index f3fba9a3a9..ada1560ce2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -91,6 +91,11 @@ module ActiveRecord false end + # Does this adapter restrict the number of ids you can use in a list. Oracle has a limit of 1000. + def ids_in_list_limit + nil + end + # QUOTING ================================================== # Override to return the quoted table name. Defaults to column quoting. diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 66fb5ac1e1..c532522e76 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -79,6 +79,58 @@ class EagerAssociationTest < ActiveRecord::TestCase end end + def test_preloading_has_many_in_multiple_queries_with_more_ids_than_database_can_handle + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + posts = Post.find(:all, :include=>:comments) + assert_equal 7, posts.size + end + + def test_preloading_has_many_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) + posts = Post.find(:all, :include=>:comments) + assert_equal 7, posts.size + end + + def test_preloading_habtm_in_multiple_queries_with_more_ids_than_database_can_handle + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + posts = Post.find(:all, :include=>:categories) + assert_equal 7, posts.size + end + + def test_preloading_habtm_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) + posts = Post.find(:all, :include=>:categories) + assert_equal 7, posts.size + end + + def test_load_associated_records_in_one_query_when_adapter_has_no_limit + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) + Post.expects(:i_was_called).with([1,2,3,4,5,6,7]).returns([1]) + associated_records = Post.send(:associated_records, [1,2,3,4,5,6,7]) do |some_ids| + Post.i_was_called(some_ids) + end + assert_equal [1], associated_records + end + + def test_load_associated_records_in_several_queries_when_many_ids_passed + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + Post.expects(:i_was_called).with([1,2,3,4,5]).returns([1]) + Post.expects(:i_was_called).with([6,7]).returns([6]) + associated_records = Post.send(:associated_records, [1,2,3,4,5,6,7]) do |some_ids| + Post.i_was_called(some_ids) + end + assert_equal [1,6], associated_records + end + + def test_load_associated_records_in_one_query_when_a_few_ids_passed + Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + Post.expects(:i_was_called).with([1,2,3]).returns([1]) + associated_records = Post.send(:associated_records, [1,2,3]) do |some_ids| + Post.i_was_called(some_ids) + end + assert_equal [1], associated_records + end + def test_including_duplicate_objects_from_belongs_to popular_post = Post.create!(:title => 'foo', :body => "I like cars!") comment = popular_post.comments.create!(:body => "lol") -- cgit v1.2.3 From 26923756fb23eb9c2993a365f9819027f20d5e77 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 10:01:21 -0800 Subject: removing space errors --- activerecord/lib/active_record/association_preload.rb | 2 +- activerecord/test/cases/associations/eager_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index a205549d60..9743b1b4a7 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -387,7 +387,7 @@ module ActiveRecord def in_or_equals_for_ids(ids) ids.size > 1 ? "IN (?)" : "= ?" end - + # Some databases impose a limit on the number of ids in a list (in Oracle its 1000) # Make several smaller queries if necessary or make one query if the adapter supports it def associated_records(ids) diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index c532522e76..c00b8a1cde 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -102,7 +102,7 @@ class EagerAssociationTest < ActiveRecord::TestCase posts = Post.find(:all, :include=>:categories) assert_equal 7, posts.size end - + def test_load_associated_records_in_one_query_when_adapter_has_no_limit Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) Post.expects(:i_was_called).with([1,2,3,4,5,6,7]).returns([1]) -- cgit v1.2.3 From c52e2cf4b3ef22fea6989df906a53188e632b9a4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 10:10:18 -0800 Subject: delegating path and open to internal tempfile --- actionpack/lib/action_dispatch/http/upload.rb | 10 ++++++++-- actionpack/test/dispatch/uploaded_file_test.rb | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index 84e58d7d6a..37effade4f 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/object/blank' - module ActionDispatch module Http class UploadedFile @@ -13,6 +11,14 @@ module ActionDispatch raise(ArgumentError, ':tempfile is required') unless @tempfile end + def open + @tempfile.open + end + + def path + @tempfile.path + end + def read(*args) @tempfile.read(*args) end diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb index b51697b930..e2a7f1bad7 100644 --- a/actionpack/test/dispatch/uploaded_file_test.rb +++ b/actionpack/test/dispatch/uploaded_file_test.rb @@ -28,6 +28,18 @@ module ActionDispatch assert_equal 'foo', uf.tempfile end + def test_delegates_path_to_tempfile + tf = Class.new { def path; 'thunderhorse' end } + uf = Http::UploadedFile.new(:tempfile => tf.new) + assert_equal 'thunderhorse', uf.path + end + + def test_delegates_open_to_tempfile + tf = Class.new { def open; 'thunderhorse' end } + uf = Http::UploadedFile.new(:tempfile => tf.new) + assert_equal 'thunderhorse', uf.open + end + def test_delegates_to_tempfile tf = Class.new { def read; 'thunderhorse' end } uf = Http::UploadedFile.new(:tempfile => tf.new) -- cgit v1.2.3 From be797750e6ce866ea08307f63bf35304a965c8d4 Mon Sep 17 00:00:00 2001 From: Leonardo Capillera Date: Thu, 18 Nov 2010 16:31:27 -0200 Subject: Remove deprecated form_for with strings or symbols Signed-off-by: Santiago Pastorino --- actionpack/lib/action_view/helpers/form_helper.rb | 12 +++------ actionpack/test/template/erb/form_for_test.rb | 3 ++- actionpack/test/template/erb/helper.rb | 4 ++- actionpack/test/template/form_helper_test.rb | 33 ----------------------- 4 files changed, 8 insertions(+), 44 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 8c300ec745..dec1ae6e4f 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -303,15 +303,9 @@ module ActionView options[:html] ||= {} - case record - when String, Symbol - object_name = record - object = nil - else - object = record.is_a?(Array) ? record.last : record - object_name = options[:as] || ActiveModel::Naming.param_key(object) - apply_form_for_options!(record, options) - end + object = record.is_a?(Array) ? record.last : record + object_name = options[:as] || ActiveModel::Naming.param_key(object) + apply_form_for_options!(record, options) options[:html][:remote] = options.delete(:remote) builder = options[:parent_builder] = instantiate_builder(object_name, object, options, &proc) diff --git a/actionpack/test/template/erb/form_for_test.rb b/actionpack/test/template/erb/form_for_test.rb index e722b40a9a..02f07496e0 100644 --- a/actionpack/test/template/erb/form_for_test.rb +++ b/actionpack/test/template/erb/form_for_test.rb @@ -1,10 +1,11 @@ require "abstract_unit" require "template/erb/helper" +require "controller/fake_models" module ERBTest class TagHelperTest < BlockTestCase test "form_for works" do - output = render_content "form_for(:staticpage, :url => {:controller => 'blah', :action => 'update'})", "" + output = render_content "form_for(Post.new, :url => {:controller => 'blah', :action => 'update'})", "" assert_match %r{.*}, output end end diff --git a/actionpack/test/template/erb/helper.rb b/actionpack/test/template/erb/helper.rb index 799f9e4036..fb9d0315f3 100644 --- a/actionpack/test/template/erb/helper.rb +++ b/actionpack/test/template/erb/helper.rb @@ -4,6 +4,8 @@ module ERBTest include ActionView::Helpers::TagHelper include ActionView::Helpers::JavaScriptHelper include ActionView::Helpers::FormHelper + include ActionView::Context + include ActionController::RecordIdentifier attr_accessor :output_buffer, :controller @@ -20,4 +22,4 @@ module ERBTest "<%= #{str} do %>#{rest}<% end %>" end end -end \ No newline at end of file +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 2c60096475..7179ae4e9c 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -781,23 +781,6 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end - def test_form_for_without_object - form_for(:post, :html => { :id => 'create-post' }) do |f| - concat f.text_field(:title) - concat f.text_area(:body) - concat f.check_box(:secret) - end - - expected = whole_form("/", "create-post") do - "" + - "" + - "" + - "" - end - - assert_dom_equal expected, output_buffer - end - def test_form_for_with_index form_for(@post, :as => "post[]") do |f| concat f.label(:title) @@ -867,22 +850,6 @@ class FormHelperTest < ActionView::TestCase I18n.locale = old_locale end - def test_submit_without_object_and_locale_strings - old_locale, I18n.locale = I18n.locale, :submit - - form_for(:post) do |f| - concat f.submit :class => "extra" - end - - expected = whole_form do - "" - end - - assert_dom_equal expected, output_buffer - ensure - I18n.locale = old_locale - end - def test_submit_with_object_and_nested_lookup old_locale, I18n.locale = I18n.locale, :submit -- cgit v1.2.3 From e3d8331c5b543ea7ea2024d05bd79526d11341c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 18 Nov 2010 20:22:14 +0100 Subject: Revert "Remove deprecated form_for with strings or symbols" This code was not deprecated. What was deprecated is the following: form_for(:foo, @foo) Which now should be rewritten as: form_for(@foo, :as => :foo) The following format is valid: form_for(:foo) This reverts commit be797750e6ce866ea08307f63bf35304a965c8d4. --- actionpack/lib/action_view/helpers/form_helper.rb | 12 ++++++--- actionpack/test/template/erb/form_for_test.rb | 3 +-- actionpack/test/template/erb/helper.rb | 4 +-- actionpack/test/template/form_helper_test.rb | 33 +++++++++++++++++++++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index dec1ae6e4f..8c300ec745 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -303,9 +303,15 @@ module ActionView options[:html] ||= {} - object = record.is_a?(Array) ? record.last : record - object_name = options[:as] || ActiveModel::Naming.param_key(object) - apply_form_for_options!(record, options) + case record + when String, Symbol + object_name = record + object = nil + else + object = record.is_a?(Array) ? record.last : record + object_name = options[:as] || ActiveModel::Naming.param_key(object) + apply_form_for_options!(record, options) + end options[:html][:remote] = options.delete(:remote) builder = options[:parent_builder] = instantiate_builder(object_name, object, options, &proc) diff --git a/actionpack/test/template/erb/form_for_test.rb b/actionpack/test/template/erb/form_for_test.rb index 02f07496e0..e722b40a9a 100644 --- a/actionpack/test/template/erb/form_for_test.rb +++ b/actionpack/test/template/erb/form_for_test.rb @@ -1,11 +1,10 @@ require "abstract_unit" require "template/erb/helper" -require "controller/fake_models" module ERBTest class TagHelperTest < BlockTestCase test "form_for works" do - output = render_content "form_for(Post.new, :url => {:controller => 'blah', :action => 'update'})", "" + output = render_content "form_for(:staticpage, :url => {:controller => 'blah', :action => 'update'})", "" assert_match %r{.*}, output end end diff --git a/actionpack/test/template/erb/helper.rb b/actionpack/test/template/erb/helper.rb index fb9d0315f3..799f9e4036 100644 --- a/actionpack/test/template/erb/helper.rb +++ b/actionpack/test/template/erb/helper.rb @@ -4,8 +4,6 @@ module ERBTest include ActionView::Helpers::TagHelper include ActionView::Helpers::JavaScriptHelper include ActionView::Helpers::FormHelper - include ActionView::Context - include ActionController::RecordIdentifier attr_accessor :output_buffer, :controller @@ -22,4 +20,4 @@ module ERBTest "<%= #{str} do %>#{rest}<% end %>" end end -end +end \ No newline at end of file diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 7179ae4e9c..2c60096475 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -781,6 +781,23 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_form_for_without_object + form_for(:post, :html => { :id => 'create-post' }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post") do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + def test_form_for_with_index form_for(@post, :as => "post[]") do |f| concat f.label(:title) @@ -850,6 +867,22 @@ class FormHelperTest < ActionView::TestCase I18n.locale = old_locale end + def test_submit_without_object_and_locale_strings + old_locale, I18n.locale = I18n.locale, :submit + + form_for(:post) do |f| + concat f.submit :class => "extra" + end + + expected = whole_form do + "" + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + def test_submit_with_object_and_nested_lookup old_locale, I18n.locale = I18n.locale, :submit -- cgit v1.2.3 From e107dcca6b132d39f578b48fba39891eaf902a0d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 13:39:21 -0800 Subject: testing multiple ORd queries --- activerecord/test/cases/relations_test.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 6649923421..535bcd4396 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -460,6 +460,18 @@ class RelationTest < ActiveRecord::TestCase assert_equal [david], relation.all end + def test_find_all_with_multiple_ors + david = authors(:david) + relation = [ + { :name => david.name }, + { :name => 'Santiago' }, + { :name => 'tenderlove' }, + ].inject(Author.unscoped) do |memo, param| + memo.where(param) + end + assert_equal [david], relation.all + end + def test_exists davids = Author.where(:name => 'David') assert davids.exists? -- cgit v1.2.3 From 07a74f196d6766c09e28ed696debb120a035dde7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:53:59 -0800 Subject: connection is set from the connection pool during migrations --- activerecord/lib/active_record/migration.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 0eabc4a4aa..06a8747fde 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -300,8 +300,9 @@ module ActiveRecord attr_accessor :name, :version def initialize - @name = self.class.name - @version = nil + @name = self.class.name + @version = nil + @connection = nil end def up @@ -326,7 +327,12 @@ module ActiveRecord end result = nil - time = Benchmark.measure { result = send(direction) } + time = nil + ActiveRecord::Base.connection_pool.with_connection do |conn| + @connection = conn + time = Benchmark.measure { result = send(direction) } + @connection = nil + end case direction when :up then announce "migrated (%.4fs)" % time.real; write @@ -367,7 +373,7 @@ module ActiveRecord end def connection - ActiveRecord::Base.connection + @connection || ActiveRecord::Base.connection end def method_missing(method, *arguments, &block) -- cgit v1.2.3 From 52b71c01fd3c8a87152f55129a8cb3234190734a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 16 Nov 2010 19:57:09 -0200 Subject: Revert "Quick fix for not escaping []s (not ideal)" According to http://www.ietf.org/rfc/rfc2616.txt and http://tools.ietf.org/rfc/rfc3986.txt [ and ] are reserved characters and should be escaped using "%" HEX HEX This reverts commit 856d2fd874d72dd9f83204affff4edfef3308361 and 1ee9b40b18a0bed5bb10a0785f7e2730bac983f6.. --- actionpack/test/controller/routing_test.rb | 6 +++--- activesupport/lib/active_support/core_ext/object/to_param.rb | 4 +--- activesupport/lib/active_support/core_ext/object/to_query.rb | 4 ++-- activesupport/test/core_ext/object/to_query_test.rb | 8 ++++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index ce5c899a19..cd067b7d18 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1444,7 +1444,7 @@ class RouteSetTest < ActiveSupport::TestCase end def test_expand_array_build_query_string - assert_uri_equal '/foo?x[]=1&x[]=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]}) + assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]}) end def test_escape_spaces_build_query_string_selected_keys @@ -1744,9 +1744,9 @@ class RackMountIntegrationTests < ActiveSupport::TestCase assert_equal '/posts', @routes.generate({:controller => 'posts'}, {:controller => 'posts', :action => 'index'}) assert_equal '/posts/create', @routes.generate({:action => 'create'}, {:controller => 'posts'}) assert_equal '/posts?foo=bar', @routes.generate(:controller => 'posts', :foo => 'bar') - assert_equal '/posts?foo[]=bar&foo[]=baz', @routes.generate(:controller => 'posts', :foo => ['bar', 'baz']) + assert_equal '/posts?foo%5B%5D=bar&foo%5B%5D=baz', @routes.generate(:controller => 'posts', :foo => ['bar', 'baz']) assert_equal '/posts?page=2', @routes.generate(:controller => 'posts', :page => 2) - assert_equal '/posts?q[foo][a]=b', @routes.generate(:controller => 'posts', :q => { :foo => { :a => 'b'}}) + assert_equal '/posts?q%5Bfoo%5D%5Ba%5D=b', @routes.generate(:controller => 'posts', :q => { :foo => { :a => 'b'}}) assert_equal '/news.rss', @routes.generate(:controller => 'news', :action => 'index', :format => 'rss') diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb index ecb2bca82c..593f376159 100644 --- a/activesupport/lib/active_support/core_ext/object/to_param.rb +++ b/activesupport/lib/active_support/core_ext/object/to_param.rb @@ -1,5 +1,3 @@ - - class Object # Alias of to_s. def to_param @@ -41,7 +39,7 @@ class Hash # ==== Examples # { :name => 'David', :nationality => 'Danish' }.to_param # => "name=David&nationality=Danish" # - # { :name => 'David', :nationality => 'Danish' }.to_param('user') # => "user[name]=David&user[nationality]=Danish" + # { :name => 'David', :nationality => 'Danish' }.to_query('user') # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish" def to_param(namespace = nil) collect do |key, value| value.to_query(namespace ? "#{namespace}[#{key}]" : key) diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb index c9981895b4..3f1540f685 100644 --- a/activesupport/lib/active_support/core_ext/object/to_query.rb +++ b/activesupport/lib/active_support/core_ext/object/to_query.rb @@ -7,7 +7,7 @@ class Object # Note: This method is defined as a default implementation for all Objects for Hash#to_query to work. def to_query(key) require 'cgi' unless defined?(CGI) && defined?(CGI::escape) - "#{CGI.escape(key.to_s).gsub(/%(5B|5D)/n) { [$1].pack('H*') }}=#{CGI.escape(to_param.to_s)}" + "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}" end end @@ -15,7 +15,7 @@ class Array # Converts an array into a string suitable for use as a URL query string, # using the given +key+ as the param name. # - # ['Rails', 'coding'].to_query('hobbies') # => "hobbies[]=Rails&hobbies[]=coding" + # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding" def to_query(key) prefix = "#{key}[]" collect { |value| value.to_query(prefix) }.join '&' diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index e28b4cd493..84da52f4bf 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -18,22 +18,22 @@ class ToQueryTest < Test::Unit::TestCase end def test_nested_conversion - assert_query_equal 'person[login]=seckar&person[name]=Nicholas', + assert_query_equal 'person%5Blogin%5D=seckar&person%5Bname%5D=Nicholas', :person => ActiveSupport::OrderedHash[:login, 'seckar', :name, 'Nicholas'] end def test_multiple_nested - assert_query_equal 'account[person][id]=20&person[id]=10', + assert_query_equal 'account%5Bperson%5D%5Bid%5D=20&person%5Bid%5D=10', ActiveSupport::OrderedHash[:account, {:person => {:id => 20}}, :person, {:id => 10}] end def test_array_values - assert_query_equal 'person[id][]=10&person[id][]=20', + assert_query_equal 'person%5Bid%5D%5B%5D=10&person%5Bid%5D%5B%5D=20', :person => {:id => [10, 20]} end def test_array_values_are_not_sorted - assert_query_equal 'person[id][]=20&person[id][]=10', + assert_query_equal 'person%5Bid%5D%5B%5D=20&person%5Bid%5D%5B%5D=10', :person => {:id => [20, 10]} end -- cgit v1.2.3 From d891ad4e92c4f4d854ba321c42000026b5c75187 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 18 Nov 2010 23:52:17 -0200 Subject: Make ARes tests unescape [ and ] --- activeresource/test/cases/base_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb index abf4259a54..ab801902ac 100644 --- a/activeresource/test/cases/base_test.rb +++ b/activeresource/test/cases/base_test.rb @@ -463,9 +463,9 @@ class BaseTest < Test::Unit::TestCase assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male') assert Person.collection_path(:gender => 'male', :student => true).include?('student=true') - assert_equal '/people.xml?name[]=bob&name[]=your+uncle%2Bme&name[]=&name[]=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false]) + assert_equal '/people.xml?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false]) - assert_equal '/people.xml?struct[a][]=2&struct[a][]=1&struct[b]=fred', Person.collection_path(:struct => ActiveSupport::OrderedHash[:a, [2,1], 'b', 'fred']) + assert_equal '/people.xml?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred', Person.collection_path(:struct => ActiveSupport::OrderedHash[:a, [2,1], 'b', 'fred']) end def test_custom_element_path @@ -512,7 +512,7 @@ class BaseTest < Test::Unit::TestCase assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :person_id => 1, :type => 'work') assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, 'person_id' => 1, :type => 'work') assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :type => 'work', :person_id => 1) - assert_equal '/people/1/addresses/1.xml?type[]=work&type[]=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time']) + assert_equal '/people/1/addresses/1.xml?type%5B%5D=work&type%5B%5D=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time']) end def test_custom_element_path_with_prefix_and_parameters -- cgit v1.2.3 From bf78ceb7722c30f94a7fc915d53d123502ae7c1d Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 19 Nov 2010 17:25:37 +0100 Subject: i18n guide: fix external link to rack locale --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index b42942bb63..3179748c56 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -278,7 +278,7 @@ def extract_locale_from_accept_language_header end -Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's "http_accept_language":http://github.com/iain/http_accept_language/tree/master or even Rack middleware such as Ryan Tomayko's "locale":http://github.com/rtomayko/rack-contrib/blob/master/lib/rack/locale.rb. +Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's "http_accept_language":http://github.com/iain/http_accept_language/tree/master or even Rack middleware such as Ryan Tomayko's "locale":http://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/locale.rb. h5. Using GeoIP (or Similar) Database -- cgit v1.2.3 From b1ffd65b8f96391748d9034317b4e6ce8ded7eb4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 18 Nov 2010 23:20:54 -0200 Subject: Useless assignation --- actionpack/lib/abstract_controller/rendering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 475785a4b4..48171e6bd1 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -138,7 +138,7 @@ module AbstractController case action when NilClass when Hash - options, action = action, nil + options = action when String, Symbol action = action.to_s key = action.include?(?/) ? :file : :action -- cgit v1.2.3 From 555b7cd04a268073d69478eee6e90ac4c749c38c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 18 Nov 2010 23:27:05 -0200 Subject: Don't merge just directly add to the action to the :partial key --- actionpack/lib/abstract_controller/rendering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 48171e6bd1..83e7c902ef 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -144,7 +144,7 @@ module AbstractController key = action.include?(?/) ? :file : :action options[key] = action else - options.merge!(:partial => action) + options[:partial] = action end options -- cgit v1.2.3 From bb7b705b0c524ef279ea562dda8fb3a2241caa9a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 19 Nov 2010 14:26:13 -0200 Subject: Fix indentation --- actionpack/lib/abstract_controller/rendering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 83e7c902ef..ba31e2b1ea 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -119,7 +119,7 @@ module AbstractController controller_path end - private + private # This method should return a hash with assigns. # You can overwrite this configuration per controller. -- cgit v1.2.3 From cb8f7a1156933bfd12887142706b40be85eb05b2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 19 Nov 2010 18:24:58 +0100 Subject: removes orphan tests, custom String#% was removed from AS in 39d6f9e --- activesupport/test/core_ext/string_ext_test.rb | 69 -------------------------- 1 file changed, 69 deletions(-) diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 8be65c99f2..bb865cae91 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -321,75 +321,6 @@ class CoreExtStringMultibyteTest < ActiveSupport::TestCase end end -=begin - string.rb - Interpolation for String. - - Copyright (C) 2005-2009 Masao Mutoh - - You may redistribute it and/or modify it under the same - license terms as Ruby. -=end -class TestGetTextString < Test::Unit::TestCase - def test_sprintf - assert_equal("foo is a number", "%{msg} is a number" % {:msg => "foo"}) - assert_equal("bar is a number", "%s is a number" % ["bar"]) - assert_equal("bar is a number", "%s is a number" % "bar") - assert_equal("1, test", "%{num}, %{record}" % {:num => 1, :record => "test"}) - assert_equal("test, 1", "%{record}, %{num}" % {:num => 1, :record => "test"}) - assert_equal("1, test", "%d, %s" % [1, "test"]) - assert_equal("test, 1", "%2$s, %1$d" % [1, "test"]) - assert_raise(ArgumentError) { "%-%" % [1] } - end - - def test_percent - assert_equal("% 1", "%% %d" % {:num => 1.0}) - assert_equal("%{num} %d 1", "%%{num} %%d %d" % {:num => 1}) - end - - def test_sprintf_percent_in_replacement - assert_equal("%s", "%{msg}" % { :msg => '%s', :not_translated => 'should not happen' }) - end - - def test_sprintf_lack_argument - assert_raises(KeyError) { "%{num}, %{record}" % {:record => "test"} } - assert_raises(KeyError) { "%{record}" % {:num => 1} } - end - - def test_no_placeholder - # Causes a "too many arguments for format string" warning - # on 1.8.7 and 1.9 but we still want to make sure the behavior works - silence_warnings do - assert_equal("aaa", "aaa" % {:num => 1}) - assert_equal("bbb", "bbb" % [1]) - end - end - - def test_sprintf_ruby19_style - assert_equal("1", "%d" % {:num => 1}) - assert_equal("0b1", "%#b" % {:num => 1}) - assert_equal("foo", "%s" % {:msg => "foo"}) - assert_equal("1.000000", "%f" % {:num => 1.0}) - assert_equal(" 1", "%3.0f" % {:num => 1.0}) - assert_equal("100.00", "%2.2f" % {:num => 100.0}) - assert_equal("0x64", "%#x" % {:num => 100.0}) - assert_raise(ArgumentError) { "%,d" % {:num => 100} } - assert_raise(ArgumentError) { "%/d" % {:num => 100} } - end - - def test_sprintf_old_style - assert_equal("foo 1.000000", "%s %f" % ["foo", 1.0]) - end - - def test_sprintf_mix_unformatted_and_formatted_named_placeholders - assert_equal("foo 1.000000", "%{name} %f" % {:name => "foo", :num => 1.0}) - end - - def test_string_interpolation_raises_an_argument_error_when_mixing_named_and_unnamed_placeholders - assert_raises(ArgumentError) { "%{name} %f" % [1.0] } - assert_raises(ArgumentError) { "%{name} %f" % [1.0, 2.0] } - end -end - class OutputSafetyTest < ActiveSupport::TestCase def setup @string = "hello" -- cgit v1.2.3 From deff5289474d966bb12ae18c1b816df3eeb11f27 Mon Sep 17 00:00:00 2001 From: Henning Koch Date: Fri, 19 Nov 2010 18:16:54 +0100 Subject: Fix AssetIncludeTag ensuring that files are in the wrong directory [#6015 state:resolved] Signed-off-by: Santiago Pastorino --- .../helpers/asset_tag_helpers/asset_include_tag.rb | 6 +-- actionpack/test/template/asset_tag_helper_test.rb | 44 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb index 3bc81ae068..15f8e10b7f 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb @@ -57,8 +57,8 @@ module ActionView private - def path_to_asset(source) - asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension) + def path_to_asset(source, include_host = true) + asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host) end def compute_paths(*args) @@ -77,7 +77,7 @@ module ActionView def ensure_sources!(sources) sources.each do |source| - asset_file_path!(path_to_asset(source)) + asset_file_path!(path_to_asset(source, false)) end return sources end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 139d832c5f..fbcc99a17a 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -680,6 +680,26 @@ class AssetTagHelperTest < ActionView::TestCase FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) end + def test_caching_javascript_include_tag_with_named_paths_and_relative_url_root_when_caching_off + ENV["RAILS_ASSET_ID"] = "" + @controller.config.relative_url_root = "/collaboration/hieraki" + config.perform_caching = false + + assert_dom_equal( + %(), + javascript_include_tag('robber', :cache => true) + ) + + assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) + + assert_dom_equal( + %(), + javascript_include_tag('robber', :cache => "money", :recursive => true) + ) + + assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) + end + def test_caching_javascript_include_tag_when_caching_off ENV["RAILS_ASSET_ID"] = "" config.perform_caching = false @@ -907,6 +927,30 @@ class AssetTagHelperTest < ActionView::TestCase FileUtils.rm_f(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) end + + def test_caching_stylesheet_link_tag_with_named_paths_and_relative_url_root_when_caching_off + ENV["RAILS_ASSET_ID"] = "" + @controller.config.relative_url_root = "/collaboration/hieraki" + config.perform_caching = false + + assert_dom_equal( + %(), + stylesheet_link_tag('robber', :cache => true) + ) + + assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'all.css')) + + assert_dom_equal( + %(), + stylesheet_link_tag('robber', :cache => "money") + ) + + assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::STYLESHEETS_DIR, 'money.css')) + end + + + + def test_caching_stylesheet_include_tag_when_caching_off ENV["RAILS_ASSET_ID"] = "" config.perform_caching = false -- cgit v1.2.3 From 9280fbf795d26146fe149514a32e22612b0311ee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 10:13:56 -0800 Subject: instantiate the delegate object after initialize is defined so that our initialize method actually gets called --- activerecord/lib/active_record/migration.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 06a8747fde..9892c6c338 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -294,9 +294,6 @@ module ActiveRecord cattr_accessor :verbose - self.delegate = new - self.verbose = true - attr_accessor :name, :version def initialize @@ -305,6 +302,10 @@ module ActiveRecord @connection = nil end + # instantiate the delegate object after initialize is defined + self.verbose = true + self.delegate = new + def up self.class.delegate = self return unless self.class.respond_to?(:up) -- cgit v1.2.3 From 24174d1b3aa1b8ac4fec95f82f6204e2d095805d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 10:23:13 -0800 Subject: this return value is not used, so stop returning it --- activerecord/lib/active_record/migration.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 9892c6c338..b303ff4225 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -327,11 +327,10 @@ module ActiveRecord when :down then announce "reverting" end - result = nil time = nil ActiveRecord::Base.connection_pool.with_connection do |conn| @connection = conn - time = Benchmark.measure { result = send(direction) } + time = Benchmark.measure { send(direction) } @connection = nil end @@ -339,8 +338,6 @@ module ActiveRecord when :up then announce "migrated (%.4fs)" % time.real; write when :down then announce "reverted (%.4fs)" % time.real; write end - - result end def write(text="") -- cgit v1.2.3 From 843e319f78631d056e5018a690d0e16fc4dee619 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 14:59:25 -0800 Subject: partial implementation of the command recorder --- activerecord/lib/active_record/migration.rb | 2 + .../active_record/migration/command_recorder.rb | 48 +++++++++++++++ .../test/cases/migration/command_recorder_test.rb | 72 ++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 activerecord/lib/active_record/migration/command_recorder.rb create mode 100644 activerecord/test/cases/migration/command_recorder_test.rb diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index b303ff4225..e7063bca11 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -284,6 +284,8 @@ module ActiveRecord # In application.rb. # class Migration + autoload :CommandRecorder, 'active_record/migration/command_recorder' + class << self attr_accessor :delegate # :nodoc: end diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb new file mode 100644 index 0000000000..25b8649350 --- /dev/null +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -0,0 +1,48 @@ +module ActiveRecord + class Migration + # ActiveRecord::Migration::CommandRecorder records commands done during + # a migration and knows how to reverse those commands. + class CommandRecorder + attr_reader :commands + + def initialize + @commands = [] + end + + # record +command+. +command+ should be a method name and arguments. + # For example: + # + # recorder.record(:method_name, [:arg1, arg2]) + def record(*command) + @commands << command + end + + # Returns a list that represents commands that are the inverse of the + # commands stored in +commands+. + def inverse + @commands.map { |name, args| send(:"invert_#{name}", args) } + end + + private + def invert_create_table(args) + [:drop_table, args] + end + + def invert_rename_table(args) + [:rename_table, args.reverse] + end + + def invert_add_column(args) + [:remove_column, args.first(2)] + end + + def invert_rename_index(args) + [:rename_index, args.reverse] + end + + def invert_rename_column(args) + [:rename_column, [args.first] + args.last(2).reverse] + end + end + end +end diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb new file mode 100644 index 0000000000..c33ce7cadf --- /dev/null +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -0,0 +1,72 @@ +require "cases/helper" + +module ActiveRecord + class Migration + class CommandRecorderTest < ActiveRecord::TestCase + def setup + @recorder = CommandRecorder.new + end + + def test_record + @recorder.record :create_table, [:system_settings] + assert_equal 1, @recorder.commands.length + end + + def test_inverse + @recorder.record :create_table, [:system_settings] + assert_equal 1, @recorder.inverse.length + + @recorder.record :rename_table, [:old, :new] + assert_equal 2, @recorder.inverse.length + end + + def test_invert_create_table + @recorder.record :create_table, [:system_settings] + drop_table = @recorder.inverse.first + assert_equal [:drop_table, [:system_settings]], drop_table + end + + def test_invert_rename_table + @recorder.record :rename_table, [:old, :new] + rename = @recorder.inverse.first + assert_equal [:rename_table, [:new, :old]], rename + end + + def test_invert_add_column + @recorder.record :add_column, [:table, :column, :type, {}] + remove = @recorder.inverse.first + assert_equal [:remove_column, [:table, :column]], remove + end + + def test_invert_rename_column + @recorder.record :rename_column, [:table, :old, :new] + rename = @recorder.inverse.first + assert_equal [:rename_column, [:table, :new, :old]], rename + end + + def test_invert_add_index + @recorder.record :add_index, [:table, [:one, :two], {:options => true}] + remove = @recorder.inverse.first + assert_equal [:remove_index, [:table, {:column => [:one, :two]}]], remove + end + + def test_invert_rename_index + @recorder.record :rename_index, [:old, :new] + rename = @recorder.inverse.first + assert_equal [:rename_index, [:new, :old]], rename + end + + def test_invert_add_timestamps + @recorder.record :add_timestamps, [:table] + remove = @recorder.inverse.first + assert_equal [:remove_timestamps, [:table]], remove + end + + def test_invert_remove_timestamps + @recorder.record :remove_timestamps, [:table] + add = @recorder.inverse.first + assert_equal [:add_timestamps, [:table]], add + end + end + end +end -- cgit v1.2.3 From 24b637a80f659eb03f8efe459f9d6aae2338e434 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:05:29 -0800 Subject: inverting add_index --- activerecord/lib/active_record/migration/command_recorder.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 25b8649350..032ce3aad8 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -43,6 +43,11 @@ module ActiveRecord def invert_rename_column(args) [:rename_column, [args.first] + args.last(2).reverse] end + + def invert_add_index(args) + table, columns, _ = *args + [:remove_index, [table, {:column => columns}]] + end end end end -- cgit v1.2.3 From 5d93900dc6a423fe8d7b0c6e330deeaca4b8b72c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:07:25 -0800 Subject: add and remove timestamps can be inverted --- activerecord/lib/active_record/migration/command_recorder.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 032ce3aad8..231e981e53 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -48,6 +48,14 @@ module ActiveRecord table, columns, _ = *args [:remove_index, [table, {:column => columns}]] end + + def invert_remove_timestamps(args) + [:add_timestamps, args] + end + + def invert_add_timestamps(args) + [:remove_timestamps, args] + end end end end -- cgit v1.2.3 From b29a24bb6f13b8af9c12b77ee0ddc1f84c79ab55 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:09:25 -0800 Subject: commands are reversed --- activerecord/lib/active_record/migration/command_recorder.rb | 2 +- activerecord/test/cases/migration/command_recorder_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 231e981e53..73450c2390 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -20,7 +20,7 @@ module ActiveRecord # Returns a list that represents commands that are the inverse of the # commands stored in +commands+. def inverse - @commands.map { |name, args| send(:"invert_#{name}", args) } + @commands.reverse.map { |name, args| send(:"invert_#{name}", args) } end private diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index c33ce7cadf..47c3332078 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -20,6 +20,13 @@ module ActiveRecord assert_equal 2, @recorder.inverse.length end + def test_inverted_commands_are_reveresed + @recorder.record :create_table, [:hello] + @recorder.record :create_table, [:world] + tables = @recorder.inverse.map(&:last) + assert_equal [[:world], [:hello]], tables + end + def test_invert_create_table @recorder.record :create_table, [:system_settings] drop_table = @recorder.inverse.first -- cgit v1.2.3 From 96b50a039276b4391ddf07b0a74850ce7bad6863 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:12:09 -0800 Subject: IrreversibleMigration is raised if we cannot invert the command --- activerecord/lib/active_record/migration/command_recorder.rb | 6 +++++- activerecord/test/cases/migration/command_recorder_test.rb | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 73450c2390..87ad603c04 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -20,7 +20,11 @@ module ActiveRecord # Returns a list that represents commands that are the inverse of the # commands stored in +commands+. def inverse - @commands.reverse.map { |name, args| send(:"invert_#{name}", args) } + @commands.reverse.map { |name, args| + method = :"invert_#{name}" + raise IrreversibleMigration unless respond_to?(method, true) + send(method, args) + } end private diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 47c3332078..50d75e0400 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -7,6 +7,13 @@ module ActiveRecord @recorder = CommandRecorder.new end + def test_unknown_commands_raise_exception + @recorder.record :execute, ['some sql'] + assert_raises(ActiveRecord::IrreversibleMigration) do + @recorder.inverse + end + end + def test_record @recorder.record :create_table, [:system_settings] assert_equal 1, @recorder.commands.length -- cgit v1.2.3 From 0d7410faabaafc6cd64f636b22a450faedc732ca Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:15:03 -0800 Subject: updating documentation --- activerecord/lib/active_record/migration/command_recorder.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 87ad603c04..8a98a177d5 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -18,7 +18,13 @@ module ActiveRecord end # Returns a list that represents commands that are the inverse of the - # commands stored in +commands+. + # commands stored in +commands+. For example: + # + # recorder.record(:rename_table, [:old, :new]) + # recorder.inverse # => [:rename_table, [:new, :old]] + # + # This method will raise an IrreversibleMigration exception if it cannot + # invert the +commands+. def inverse @commands.reverse.map { |name, args| method = :"invert_#{name}" -- cgit v1.2.3 From 6dbbfae5638a6c847fd63d52a72247e2bb15a320 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Nov 2010 15:52:13 -0800 Subject: adding invertable migration test --- .../test/cases/invertable_migration_test.rb | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 activerecord/test/cases/invertable_migration_test.rb diff --git a/activerecord/test/cases/invertable_migration_test.rb b/activerecord/test/cases/invertable_migration_test.rb new file mode 100644 index 0000000000..2477048954 --- /dev/null +++ b/activerecord/test/cases/invertable_migration_test.rb @@ -0,0 +1,42 @@ +require "cases/helper" + +module ActiveRecord + class InvertableMigrationTest < ActiveRecord::TestCase + class InvertableMigration < ActiveRecord::Migration + def change + create_table("horses") do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + end + + def write(text = '') + # sssshhhhh!! + end + end + + def treardown + if ActiveRecord::Base.connection.table_exists?("horses") + ActiveRecord::Base.connection.drop_table("horses") + end + end + + def test_invertable? + migration = InvertableMigration.new + assert migration.invertable?, 'should be invertable' + end + + def test_up + migration = InvertableMigration.new + migration.migrate(:up) + assert migration.connection.table_exists?("horses"), "horses should exist" + end + + def test_down + migration = InvertableMigration.new + migration.migrate :up + migration.migrate :down + assert !migration.connection.table_exists?("horses") + end + end +end -- cgit v1.2.3 From 6519df4157a861c9c9d567ee57983ded0e967a10 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 09:26:11 -0800 Subject: command recorder will record commands sent to a delegate object --- .../active_record/migration/command_recorder.rb | 16 +++++++++++++--- .../test/cases/migration/command_recorder_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 8a98a177d5..fa189b8009 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -3,10 +3,11 @@ module ActiveRecord # ActiveRecord::Migration::CommandRecorder records commands done during # a migration and knows how to reverse those commands. class CommandRecorder - attr_reader :commands + attr_reader :commands, :delegate - def initialize + def initialize(delegate = nil) @commands = [] + @delegate = delegate end # record +command+. +command+ should be a method name and arguments. @@ -29,10 +30,19 @@ module ActiveRecord @commands.reverse.map { |name, args| method = :"invert_#{name}" raise IrreversibleMigration unless respond_to?(method, true) - send(method, args) + __send__(method, args) } end + def respond_to?(*args) # :nodoc: + super || delegate.respond_to?(*args) + end + + def send(method, *args) # :nodoc: + return super unless respond_to?(method) + record(method, args) + end + private def invert_create_table(args) [:drop_table, args] diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 50d75e0400..ea2292dda5 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -7,6 +7,28 @@ module ActiveRecord @recorder = CommandRecorder.new end + def test_respond_to_delegates + recorder = CommandRecorder.new(Class.new { + def america; end + }.new) + assert recorder.respond_to?(:america) + end + + def test_send_calls_super + assert_raises(NoMethodError) do + @recorder.send(:create_table, :horses) + end + end + + def test_send_delegates_to_record + recorder = CommandRecorder.new(Class.new { + def create_table(name); end + }.new) + assert recorder.respond_to?(:create_table), 'respond_to? create_table' + recorder.send(:create_table, :horses) + assert_equal [[:create_table, [:horses]]], recorder.commands + end + def test_unknown_commands_raise_exception @recorder.record :execute, ['some sql'] assert_raises(ActiveRecord::IrreversibleMigration) do -- cgit v1.2.3 From 47017bd1697d6b4d6780356a403f91536eacd689 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 10:31:03 -0800 Subject: invertable migrations are working --- activerecord/lib/active_record/migration.rb | 20 +++++++++++++++++++- .../lib/active_record/migration/command_recorder.rb | 2 +- activerecord/test/cases/invertable_migration_test.rb | 5 ----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index e7063bca11..99dd50ccb1 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -332,7 +332,25 @@ module ActiveRecord time = nil ActiveRecord::Base.connection_pool.with_connection do |conn| @connection = conn - time = Benchmark.measure { send(direction) } + if respond_to?(:change) + if direction == :down + recorder = CommandRecorder.new(@connection) + suppress_messages do + @connection = recorder + change + end + @connection = conn + time = Benchmark.measure { + recorder.inverse.each do |cmd, args| + send(cmd, *args) + end + } + else + time = Benchmark.measure { change } + end + else + time = Benchmark.measure { send(direction) } + end @connection = nil end diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index fa189b8009..fc669d2e89 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -3,7 +3,7 @@ module ActiveRecord # ActiveRecord::Migration::CommandRecorder records commands done during # a migration and knows how to reverse those commands. class CommandRecorder - attr_reader :commands, :delegate + attr_accessor :commands, :delegate def initialize(delegate = nil) @commands = [] diff --git a/activerecord/test/cases/invertable_migration_test.rb b/activerecord/test/cases/invertable_migration_test.rb index 2477048954..ab08cf6fe2 100644 --- a/activerecord/test/cases/invertable_migration_test.rb +++ b/activerecord/test/cases/invertable_migration_test.rb @@ -21,11 +21,6 @@ module ActiveRecord end end - def test_invertable? - migration = InvertableMigration.new - assert migration.invertable?, 'should be invertable' - end - def test_up migration = InvertableMigration.new migration.migrate(:up) -- cgit v1.2.3 From 0cc6c46fe9711d2377ff1ae6c55a03b3d1267874 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 10:42:33 -0800 Subject: testing a non-invertible migration case --- .../test/cases/invertable_migration_test.rb | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/activerecord/test/cases/invertable_migration_test.rb b/activerecord/test/cases/invertable_migration_test.rb index ab08cf6fe2..b4c1dccb22 100644 --- a/activerecord/test/cases/invertable_migration_test.rb +++ b/activerecord/test/cases/invertable_migration_test.rb @@ -2,16 +2,28 @@ require "cases/helper" module ActiveRecord class InvertableMigrationTest < ActiveRecord::TestCase - class InvertableMigration < ActiveRecord::Migration + class SilentMigration < ActiveRecord::Migration + def write(text = '') + # sssshhhhh!! + end + end + + class InvertableMigration < SilentMigration def change create_table("horses") do |t| t.column :content, :text t.column :remind_at, :datetime end end + end - def write(text = '') - # sssshhhhh!! + class NonInvertableMigration < SilentMigration + def change + create_table("horses") do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + remove_column "horses", :content end end @@ -21,6 +33,14 @@ module ActiveRecord end end + def test_no_reverse + migration = NonInvertableMigration.new + migration.migrate(:up) + assert_raises(IrreversibleMigration) do + migration.migrate(:down) + end + end + def test_up migration = InvertableMigration.new migration.migrate(:up) -- cgit v1.2.3 From 87124457e55a207e190fc8dc981c2dc68445c736 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 10:55:57 -0800 Subject: fisting my spelling errors --- .../test/cases/invertable_migration_test.rb | 57 ---------------------- .../test/cases/invertible_migration_test.rb | 57 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 activerecord/test/cases/invertable_migration_test.rb create mode 100644 activerecord/test/cases/invertible_migration_test.rb diff --git a/activerecord/test/cases/invertable_migration_test.rb b/activerecord/test/cases/invertable_migration_test.rb deleted file mode 100644 index b4c1dccb22..0000000000 --- a/activerecord/test/cases/invertable_migration_test.rb +++ /dev/null @@ -1,57 +0,0 @@ -require "cases/helper" - -module ActiveRecord - class InvertableMigrationTest < ActiveRecord::TestCase - class SilentMigration < ActiveRecord::Migration - def write(text = '') - # sssshhhhh!! - end - end - - class InvertableMigration < SilentMigration - def change - create_table("horses") do |t| - t.column :content, :text - t.column :remind_at, :datetime - end - end - end - - class NonInvertableMigration < SilentMigration - def change - create_table("horses") do |t| - t.column :content, :text - t.column :remind_at, :datetime - end - remove_column "horses", :content - end - end - - def treardown - if ActiveRecord::Base.connection.table_exists?("horses") - ActiveRecord::Base.connection.drop_table("horses") - end - end - - def test_no_reverse - migration = NonInvertableMigration.new - migration.migrate(:up) - assert_raises(IrreversibleMigration) do - migration.migrate(:down) - end - end - - def test_up - migration = InvertableMigration.new - migration.migrate(:up) - assert migration.connection.table_exists?("horses"), "horses should exist" - end - - def test_down - migration = InvertableMigration.new - migration.migrate :up - migration.migrate :down - assert !migration.connection.table_exists?("horses") - end - end -end diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb new file mode 100644 index 0000000000..7e61ab0e47 --- /dev/null +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -0,0 +1,57 @@ +require "cases/helper" + +module ActiveRecord + class InvertibleMigrationTest < ActiveRecord::TestCase + class SilentMigration < ActiveRecord::Migration + def write(text = '') + # sssshhhhh!! + end + end + + class InvertibleMigration < SilentMigration + def change + create_table("horses") do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + end + end + + class NonInvertibleMigration < SilentMigration + def change + create_table("horses") do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + remove_column "horses", :content + end + end + + def treardown + if ActiveRecord::Base.connection.table_exists?("horses") + ActiveRecord::Base.connection.drop_table("horses") + end + end + + def test_no_reverse + migration = NonInvertibleMigration.new + migration.migrate(:up) + assert_raises(IrreversibleMigration) do + migration.migrate(:down) + end + end + + def test_up + migration = InvertibleMigration.new + migration.migrate(:up) + assert migration.connection.table_exists?("horses"), "horses should exist" + end + + def test_down + migration = InvertibleMigration.new + migration.migrate :up + migration.migrate :down + assert !migration.connection.table_exists?("horses") + end + end +end -- cgit v1.2.3 From db32b545dadae7808c210cd7ceef949a620490f0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 11:20:02 -0800 Subject: adding Migration#change to the CHANGELOG --- activerecord/CHANGELOG | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 7f54c0fa30..f1e16ea2c1 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,23 @@ *Rails 3.1.0 (unreleased)* +* Migrations can be defined as reversible, meaning that the migration system +will figure out how to reverse your migration. To use reversible migrations, +just define the "change" method. For example: + + class MyMigration < ActiveRecord::Migration + def change + create_table(:horses) do + t.column :content, :text + t.column :remind_at, :datetime + end + end + end + +Some things cannot be automatically reversed for you. If you know how to +reverse those things, you should define 'up' and 'down' in your migration. If +you define something in `change` that cannot be reversed, an +IrreversibleMigration exception will be raised when going down. + * Migrations should use instance methods rather than class methods: class FooMigration < ActiveRecord::Migration def up -- cgit v1.2.3 From a4d9b1d329ef897f6b23216b01cb510db35a37b5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 11:34:42 -0800 Subject: adding documentation for reversible migrations --- activerecord/lib/active_record/migration.rb | 32 ++++++++++++++++++++++ .../active_record/migration/command_recorder.rb | 12 +++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 99dd50ccb1..f6321f1499 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -283,6 +283,38 @@ module ActiveRecord # # In application.rb. # + # == Reversible Migrations + # + # Starting with Rails 3.1, you will be able to define reversible migrations. + # Reversible migrations are migrations that know how to go +down+ for you. + # You simply supply the +up+ logic, and the Migration system will figure out + # how to execute the down commands for you. + # + # To define a reversible migration, define the +change+ method in your + # migration like this: + # + # class TenderloveMigration < ActiveRecord::Migration + # def change + # create_table(:horses) do + # t.column :content, :text + # t.column :remind_at, :datetime + # end + # end + # end + # + # This migration will create the horses table for you on the way up, and + # automatically figure out how to drop the table on the way down. + # + # Some commands like +remove_column+ cannot be reversed. If you care to + # define how to move up and down in these cases, you should define the +up+ + # and +down+ methods as before. + # + # If a command cannot be reversed, an + # ActiveRecord::IrreversibleMigration exception will be raised when + # the migration is moving down. + # + # For a list of commands that are reversible, please see + # ActiveRecord::Migration::CommandRecorder. class Migration autoload :CommandRecorder, 'active_record/migration/command_recorder' diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index fc669d2e89..d7e481905a 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -1,7 +1,17 @@ module ActiveRecord class Migration # ActiveRecord::Migration::CommandRecorder records commands done during - # a migration and knows how to reverse those commands. + # a migration and knows how to reverse those commands. The CommandRecorder + # knows how to invert the following commands: + # + # * add_column + # * add_index + # * add_timestamp + # * create_table + # * remove_timestamps + # * rename_column + # * rename_index + # * rename_table class CommandRecorder attr_accessor :commands, :delegate -- cgit v1.2.3 From 598fc85f9eff4949264bcec78a0ed9b90c46f616 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 11:42:58 -0800 Subject: fisting typeo, thanks @vinibaggio --- activerecord/test/cases/invertible_migration_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index 7e61ab0e47..afec64750e 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -27,7 +27,7 @@ module ActiveRecord end end - def treardown + def teardown if ActiveRecord::Base.connection.table_exists?("horses") ActiveRecord::Base.connection.drop_table("horses") end -- cgit v1.2.3 From 6bd93f672ac1c0c4cfe708745c925b4bbe666947 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 11:48:23 -0800 Subject: wtf vim --- activerecord/CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index f1e16ea2c1..a3e3051b96 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -9,7 +9,7 @@ just define the "change" method. For example: create_table(:horses) do t.column :content, :text t.column :remind_at, :datetime - end + end end end -- cgit v1.2.3 From 902ae14e650d87bc0ba3d34030c9bb38646c0d9f Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 19 Nov 2010 21:42:18 +0100 Subject: guides: gives clear instructions for feedback, removes links to the now archived LH project --- railties/guides/assets/stylesheets/main.css | 2 +- railties/guides/rails_guides/helpers.rb | 9 ++------ .../source/action_controller_overview.textile | 2 -- .../guides/source/action_mailer_basics.textile | 2 -- .../guides/source/action_view_overview.textile | 2 -- .../guides/source/active_record_querying.textile | 2 -- .../active_record_validations_callbacks.textile | 2 -- .../source/active_support_core_extensions.textile | 2 -- railties/guides/source/association_basics.textile | 2 -- railties/guides/source/caching_with_rails.textile | 1 - railties/guides/source/command_line.textile | 3 --- railties/guides/source/configuring.textile | 2 -- railties/guides/source/contribute.textile | 2 +- .../guides/source/contributing_to_rails.textile | 4 +--- .../source/debugging_rails_applications.textile | 2 -- railties/guides/source/form_helpers.textile | 2 -- railties/guides/source/generators.textile | 2 -- railties/guides/source/getting_started.textile | 2 -- railties/guides/source/i18n.textile | 5 ----- railties/guides/source/index.html.erb | 14 ++++++------ railties/guides/source/layout.html.erb | 25 ++++++++++++++++++++++ .../guides/source/layouts_and_rendering.textile | 2 -- railties/guides/source/migrations.textile | 2 -- railties/guides/source/performance_testing.textile | 2 -- railties/guides/source/plugins.textile | 2 -- .../source/rails_application_templates.textile | 2 -- railties/guides/source/rails_on_rack.textile | 2 -- railties/guides/source/routing.textile | 2 -- railties/guides/source/security.textile | 2 -- railties/guides/source/testing.textile | 2 -- 30 files changed, 37 insertions(+), 70 deletions(-) diff --git a/railties/guides/assets/stylesheets/main.css b/railties/guides/assets/stylesheets/main.css index 932ee402c4..cf6e9e5cc8 100644 --- a/railties/guides/assets/stylesheets/main.css +++ b/railties/guides/assets/stylesheets/main.css @@ -333,7 +333,7 @@ h6 { padding: 0.125em 0 0.25em 28px;*/ } -#mainCol dd.ticket, #subCol dd.ticket { +#mainCol dd.work-in-progress, #subCol dd.work-in-progress { background: #fff9d8 url(../images/tab_yellow.gif) no-repeat left top; border: none; padding: 1.25em 1em 1.25em 48px; diff --git a/railties/guides/rails_guides/helpers.rb b/railties/guides/rails_guides/helpers.rb index bf99538696..d466c76c7c 100644 --- a/railties/guides/rails_guides/helpers.rb +++ b/railties/guides/rails_guides/helpers.rb @@ -4,19 +4,14 @@ module RailsGuides link = content_tag(:a, :href => url) { name } result = content_tag(:dt, link) - if ticket = options[:ticket] - result << content_tag(:dd, lh(ticket), :class => 'ticket') + if options[:work_in_progress] + result << content_tag(:dd, 'Work in progress', :class => 'work-in-progress') end result << content_tag(:dd, capture(&block)) result end - def lh(id, label = "Lighthouse Ticket") - url = "http://rails.lighthouseapp.com/projects/16213/tickets/#{id}" - content_tag(:a, label, :href => url) - end - def author(name, nick, image = 'credits_pic_blank.gif', &block) image = "images/#{image}" diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile index b39075f101..0d6c66f168 100644 --- a/railties/guides/source/action_controller_overview.textile +++ b/railties/guides/source/action_controller_overview.textile @@ -814,8 +814,6 @@ NOTE: Certain exceptions are only rescuable from the +ApplicationController+ cla h3. Changelog -"Lighthouse Ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/17 - * February 17, 2009: Yet another proofread by Xavier Noria. * November 4, 2008: First release version by Tore Darell diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index 8d2ce44e93..b75c528a33 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -508,6 +508,4 @@ In the test we send the email and store the returned object in the +email+ varia h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/25 - * September 30, 2010: Fixed typos and reformatted Action Mailer configuration table for better understanding. "Jaime Iniesta":http://jaimeiniesta.com diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile index 54792600a5..051baa660c 100644 --- a/railties/guides/source/action_view_overview.textile +++ b/railties/guides/source/action_view_overview.textile @@ -1472,7 +1472,5 @@ You can read more about the Rails Internationalization (I18n) API "here":i18n.ht h3. Changelog -"Lighthouse Ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/71 - * September 3, 2009: Continuing work by Trevor Turk, leveraging the "Action Pack docs":http://ap.rubyonrails.org/ and "What's new in Edge Rails":http://ryandaigle.com/articles/2007/8/3/what-s-new-in-edge-rails-partials-get-layouts * April 5, 2009: Starting work by Trevor Turk, leveraging Mike Gunderloy's docs diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 6837c8b11a..328439fdb8 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -928,8 +928,6 @@ For options, please see the parent section, "Calculations":#calculations. h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/16 - * April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * February 3, 2010: Update to Rails 3 by "James Miller":credits.html#bensie * February 7, 2009: Second version by "Pratik":credits.html#lifo diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index e9ff6197ec..f7ef33bc1f 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -1160,8 +1160,6 @@ config.active_record.observers = :mailer_observer h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/26-active-record-validations-and-callbacks - * July 20, 2010: Fixed typos and rephrased some paragraphs for clarity. "Jaime Iniesta":http://jaimeiniesta.com * May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * May 15, 2010: Validation Errors section updated by "Emili Parreño":http://www.eparreno.com diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index dc1200812e..d41d8b6c3d 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -3401,7 +3401,5 @@ NOTE: Defined in +active_support/core_ext/load_error.rb+. h3. Changelog -"Lighthouse ticket":https://rails.lighthouseapp.com/projects/16213/tickets/67 - * August 10, 2010: Starts to take shape, added to the index. * April 18, 2009: Initial version by "Xavier Noria":credits.html#fxn diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile index f6d61373e1..14bbe907f3 100644 --- a/railties/guides/source/association_basics.textile +++ b/railties/guides/source/association_basics.textile @@ -1876,8 +1876,6 @@ Extensions can refer to the internals of the association proxy using these three h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/11 - * April 7, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * April 19, 2009: Added +:touch+ option to +belongs_to+ associations by "Mike Gunderloy":credits.html#mgunderloy * February 1, 2009: Added +:autosave+ option "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 3320b610e7..63c52da32a 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -368,7 +368,6 @@ h3. Further reading h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/10-guide-to-caching * May 02, 2009: Formatting cleanups * April 26, 2009: Clean up typos in submitted patch diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index 752b5926f7..acd105c622 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -590,6 +590,3 @@ h5. Miscellaneous Tasks +rake routes+ will list all of your defined routes, which is useful for tracking down routing problems in your app, or giving you a good overview of the URLs in an app you're trying to get familiar with. -h3. Changelog - -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/29 diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 28fff5c11e..e39ccbc4b8 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -277,8 +277,6 @@ Some parts of Rails can also be configured externally by supplying environment v h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/28 - * August 13, 2009: Updated with config syntax and added general configuration options by "John Pignata" * January 3, 2009: First reasonably complete draft by "Mike Gunderloy":credits.html#mgunderloy * November 5, 2008: Rough outline by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/contribute.textile b/railties/guides/source/contribute.textile index 88c5c79e9d..3d4607de1d 100644 --- a/railties/guides/source/contribute.textile +++ b/railties/guides/source/contribute.textile @@ -1,6 +1,6 @@ h2. Contribute to the Rails Guides -Rails Guides aim to improve the Rails documentation and to make the barrier to entry as low as possible. A reasonably experienced developer should be able to use the Guides to come up to speed on Rails quickly. You can track the overall effort at the "Rails Guides Lighthouse":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets. Our sponsors have contributed prizes for those who write an entire guide, but there are many other ways to contribute. +Rails Guides aim to improve the Rails documentation and to make the barrier to entry as low as possible. A reasonably experienced developer should be able to use the guides to come up to speed on Rails quickly. Our sponsors have contributed prizes for those who write an entire guide, but there are many other ways to contribute. endprologue. diff --git a/railties/guides/source/contributing_to_rails.textile b/railties/guides/source/contributing_to_rails.textile index 7184759610..f501335958 100644 --- a/railties/guides/source/contributing_to_rails.textile +++ b/railties/guides/source/contributing_to_rails.textile @@ -189,7 +189,7 @@ h3. Contributing to the Rails Documentation Another area where you can help out if you're not yet ready to take the plunge to writing Rails core code is with Rails documentation. You can help with the Rails Guides or the Rails API documentation. -TIP: "docrails":http://github.com/lifo/docrails/tree/master is the documentation branch for Rails with an *open commit policy*. You can simply PM "lifo":http://github.com/lifo on Github and ask for the commit rights. Documentation changes made as part of the "docrails":http://github.com/lifo/docrails/tree/master project are merged back to the Rails master code from time to time. Check out the "original announcement":http://weblog.rubyonrails.org/2008/5/2/help-improve-rails-documentation-on-git-branch for more details. +TIP: "docrails":http://github.com/lifo/docrails/tree/master is the documentation branch for Rails with an *open commit policy*, it has public write access. Documentation changes made as part of the "docrails":http://github.com/lifo/docrails/tree/master project are merged back to the Rails master code from time to time. Check out the "original announcement":http://weblog.rubyonrails.org/2008/5/2/help-improve-rails-documentation-on-git-branch for more details. h4. The Rails Guides @@ -300,8 +300,6 @@ And then...think about your next contribution! h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/64 - * April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * August 1, 2009: Updates/amplifications by "Mike Gunderloy":credits.html#mgunderloy * March 2, 2009: Initial draft by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/debugging_rails_applications.textile b/railties/guides/source/debugging_rails_applications.textile index adf427147b..6613fad406 100644 --- a/railties/guides/source/debugging_rails_applications.textile +++ b/railties/guides/source/debugging_rails_applications.textile @@ -704,8 +704,6 @@ h3. References h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/5 - * April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * November 3, 2008: Accepted for publication. Added RJS, memory leaks and plugins chapters by "Emilio Tagua":credits.html#miloops * October 19, 2008: Copy editing pass by "Mike Gunderloy":credits.html#mgunderloy diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index ded82512d3..e178a60307 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -776,8 +776,6 @@ Many apps grow beyond simple forms editing a single object. For example when cre h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/1 - * April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com h3. Authors diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index 0f2cbb76dc..c0d3116fe4 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -363,8 +363,6 @@ Fallbacks allow your generators to have a single responsibility, increasing code h3. Changelog -"Lighthouse Ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/102 - * August 23, 2010: Edit pass by "Xavier Noria":credits.html#fxn * April 30, 2010: Reviewed by José Valim diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index f3420e37d1..902b7353c0 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1469,8 +1469,6 @@ Two very common sources of data that are not UTF-8: h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2 - * August 30, 2010: Minor editing after Rails 3 release by "Joost Baaij":http://www.spacebabies.nl * July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com * May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 8a7e9fcae6..825185c832 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -889,8 +889,3 @@ fn1. Or, to quote "Wikipedia":http://en.wikipedia.org/wiki/Internationalization_ fn2. Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files. fn3. One of these reasons is that we don't want to imply any unnecessary load for applications that do not need any I18n capabilities, so we need to keep the I18n library as simple as possible for English. Another reason is that it is virtually impossible to implement a one-fits-all solution for all problems related to I18n for all existing languages. So a solution that allows us to exchange the entire implementation easily is appropriate anyway. This also makes it much easier to experiment with custom features and extensions. - - -h3. Changelog - -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/23 diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index 6b897e3a6a..84fbc53a69 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -31,7 +31,7 @@ Ruby on Rails Guides
Rails Guides are a result of the ongoing Guides hackfest, and a work in progress.
-
Guides marked with this icon are currently being worked on. While they might still be useful to you, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections at the respective Lighthouse ticket.
+
Guides marked with this icon are currently being worked on. While they might still be useful to you, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections to the author.
<% end %> @@ -71,7 +71,7 @@ Ruby on Rails Guides

This guide covers the basic layout features of Action Controller and Action View, including rendering and redirecting, using content_for blocks, and working with partials.

<% end %> -<%= guide("Action View Form Helpers", 'form_helpers.html', :ticket => 1) do %> +<%= guide("Action View Form Helpers", 'form_helpers.html', :work_in_progress => true) do %>

Guide to using built-in Form helpers.

<% end %> @@ -100,11 +100,11 @@ Ruby on Rails Guides

This guide covers how to add internationalization to your applications. Your application will be able to translate content to different languages, change pluralization rules, use correct date formats for each country and so on.

<% end %> -<%= guide("Action Mailer Basics", 'action_mailer_basics.html', :ticket => 25) do %> +<%= guide("Action Mailer Basics", 'action_mailer_basics.html', :work_in_progress => true) do %>

This guide describes how to use Action Mailer to send and receive emails.

<% end %> -<%= guide("Testing Rails Applications", 'testing.html', :ticket => 8) do %> +<%= guide("Testing Rails Applications", 'testing.html', :work_in_progress => true) do %>

This is a rather comprehensive guide to doing both unit and functional tests in Rails. It covers everything from "What is a test?" to the testing APIs. Enjoy.

<% end %> @@ -124,11 +124,11 @@ Ruby on Rails Guides

This guide covers the basic configuration settings for a Rails application.

<% end %> -<%= guide("Rails Command Line Tools and Rake tasks", 'command_line.html', :ticket => 29) do %> +<%= guide("Rails Command Line Tools and Rake tasks", 'command_line.html', :work_in_progress => true) do %>

This guide covers the command line tools and rake tasks provided by Rails.

<% end %> -<%= guide("Caching with Rails", 'caching_with_rails.html', :ticket => 10) do %> +<%= guide("Caching with Rails", 'caching_with_rails.html', :work_in_progress => true) do %>

Various caching techniques provided by Rails.

<% end %> @@ -136,7 +136,7 @@ Ruby on Rails Guides

Extending Rails

- <%= guide("The Basics of Creating Rails Plugins", 'plugins.html', :ticket => 32) do %> + <%= guide("The Basics of Creating Rails Plugins", 'plugins.html', :work_in_progress => true) do %>

This guide covers how to build a plugin to extend the functionality of Rails.

<% end %> diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index d4b87dc45b..bb62506f04 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -106,6 +106,31 @@
<%= yield.html_safe %> + +

Feedback

+

+ You're encouraged to help in keeping the quality of this guide. +

+

+ If you see any typos or factual errors you are confident to + patch please clone <%= link_to 'docrails', 'https://github.com/lifo/docrails' %> + and push the change yourself. That branch of Rails has public write access. + Commits are still reviewed, but that happens after you've submitted your + contribution. <%= link_to 'docrails', 'https://github.com/lifo/docrails' %> is + cross-merged with master periodically. +

+

+ You may also find incomplete content, or stuff that is not up to date. + Please do add any missing documentation for master. Check the + <%= link_to 'Ruby on Rails Guides Guidelines', 'ruby_on_rails_guides_guidelines.html' %> + guide for style and conventions. +

+

+ Issues may also be reported <%= link_to 'in Github', 'https://github.com/lifo/docrails/issues' %>. +

+

And last but not least, any kind of discussion regarding Ruby on Rails + documentation is very welcome in the <%= link_to 'rubyonrails-docs mailing list', 'http://groups.google.com/group/rubyonrails-docs' %>. +

diff --git a/railties/guides/source/layouts_and_rendering.textile b/railties/guides/source/layouts_and_rendering.textile index 4e26d152bf..80a1fdd38d 100644 --- a/railties/guides/source/layouts_and_rendering.textile +++ b/railties/guides/source/layouts_and_rendering.textile @@ -1194,8 +1194,6 @@ There are several ways of getting similar results with different sub-templating h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/15 - * April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * January 25, 2010: Rails 3.0 Update by "Mikel Lindsaar":credits.html#raasdnil * December 27, 2008: Merge patch from Rodrigo Rosenfeld Rosas covering subtemplates diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 4c49a4ccbc..a9c3d51752 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -590,7 +590,5 @@ Although Active Record does not provide any tools for working directly with such h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/6 - * July 15, 2010: minor typos corrected by "Jaime Iniesta":http://jaimeiniesta.com * September 14, 2008: initial version by "Frederick Cheung":credits.html#fcheung diff --git a/railties/guides/source/performance_testing.textile b/railties/guides/source/performance_testing.textile index 9dda6d420a..41bdd27e9b 100644 --- a/railties/guides/source/performance_testing.textile +++ b/railties/guides/source/performance_testing.textile @@ -524,7 +524,5 @@ Rails has been lucky to have two startups dedicated to Rails specific performanc h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/4 - * January 9, 2009: Complete rewrite by "Pratik":credits.html#lifo * September 6, 2008: Initial version by Matthew Bergman diff --git a/railties/guides/source/plugins.textile b/railties/guides/source/plugins.textile index d32e7de564..cb43282ace 100644 --- a/railties/guides/source/plugins.textile +++ b/railties/guides/source/plugins.textile @@ -1513,7 +1513,5 @@ The final plugin should have a directory structure that looks something like thi h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/32-update-plugins-guide - * April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * November 17, 2008: Major revision by Jeff Dean diff --git a/railties/guides/source/rails_application_templates.textile b/railties/guides/source/rails_application_templates.textile index bc7b151dfe..d4b887ad02 100644 --- a/railties/guides/source/rails_application_templates.textile +++ b/railties/guides/source/rails_application_templates.textile @@ -233,6 +233,4 @@ git :commit => "-a -m 'Initial commit'" h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/78 - * April 29, 2009: Initial version by "Pratik":credits.html#lifo diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile index eaebb05f17..f17e9b4798 100644 --- a/railties/guides/source/rails_on_rack.textile +++ b/railties/guides/source/rails_on_rack.textile @@ -237,7 +237,5 @@ h4. Understanding Middlewares h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/58 - * February 7, 2009: Second version by "Pratik":credits.html#lifo * January 11, 2009: First version by "Pratik":credits.html#lifo diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index cc0c3316c8..918279f9eb 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -853,8 +853,6 @@ assert_routing({ :path => "photos", :method => :post }, { :controller => "photos h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/3 - * April 10, 2010: Updated guide to remove outdated and superfluous information, and to provide information about new features, by "Yehuda Katz":http://www.yehudakatz.com * April 2, 2010: Updated guide to match new Routing DSL in Rails 3, by "Rizwan Reza":http://www.rizwanreza.com/ * Febuary 1, 2010: Modifies the routing documentation to match new routing DSL in Rails 3, by Prem Sichanugrist diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index 4656cf4e40..693645b202 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -979,6 +979,4 @@ The security landscape shifts and it is important to keep up to date, because mi h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/7 - * November 1, 2008: First approved version by Heiko Webers diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index 043a2462b4..3d4f31cc5d 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -940,8 +940,6 @@ The built-in +test/unit+ based testing is not the only way to test Rails applica h3. Changelog -"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/8 - * April 4, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com * November 13, 2008: Revised based on feedback from Pratik Naik by "Akshay Surve":credits.html#asurve (not yet approved for publication) * October 14, 2008: Edit and formatting pass by "Mike Gunderloy":credits.html#mgunderloy (not yet approved for publication) -- cgit v1.2.3 From 938243feb9ea177b84276821818c9eed66064340 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 16:26:09 -0800 Subject: do not require ruby-debug automatically. please require it if you have declared it as a dependency --- actionpack/test/abstract_unit.rb | 8 -------- activemodel/test/cases/helper.rb | 6 ------ activerecord/test/cases/helper.rb | 5 ----- railties/lib/rails/test_help.rb | 11 ----------- 4 files changed, 30 deletions(-) diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 92597e40ff..60534a9746 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -36,14 +36,6 @@ require 'active_record' require 'action_controller/caching' require 'action_controller/caching/sweeping' -begin - require 'ruby-debug' - Debugger.settings[:autoeval] = true - Debugger.start -rescue LoadError - # Debugging disabled. `gem install ruby-debug` to enable. -end - require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late module Rails diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb index a81584bbad..01f0158678 100644 --- a/activemodel/test/cases/helper.rb +++ b/activemodel/test/cases/helper.rb @@ -12,9 +12,3 @@ ActiveSupport::Deprecation.debug = true require 'rubygems' require 'test/unit' - -begin - require 'ruby-debug' - Debugger.start -rescue LoadError -end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 52f26b71f5..f9bbc5299b 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -13,11 +13,6 @@ require 'active_record' require 'active_support/dependencies' require 'connection' -begin - require 'ruby-debug' -rescue LoadError -end - # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 38f2f651f4..f81002328f 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -39,14 +39,3 @@ class ActionDispatch::IntegrationTest @routes = Rails.application.routes end end - -begin - require_library_or_gem 'ruby-debug' - Debugger.start - if Debugger.respond_to?(:settings) - Debugger.settings[:autoeval] = true - Debugger.settings[:autolist] = 1 - end -rescue LoadError - # ruby-debug wasn't available so neither can the debugging be -end -- cgit v1.2.3 From d3f8765482133df14d355f1763d3df1c883d2689 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 20 Nov 2010 02:28:58 -0200 Subject: Avoid range object creation --- actionpack/lib/abstract_controller/rendering.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index ba31e2b1ea..91b75273fa 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -128,7 +128,7 @@ module AbstractController hash = {} variables = instance_variable_names variables -= protected_instance_variables if respond_to?(:protected_instance_variables) - variables.each { |name| hash[name.to_s[1..-1]] = instance_variable_get(name) } + variables.each { |name| hash[name.to_s[1, name.length]] = instance_variable_get(name) } hash end -- cgit v1.2.3 From 4f3b5b8ec1443f0a6150178ce06b1dc43377540e Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 20 Nov 2010 02:46:55 -0200 Subject: Fix indentation --- .../lib/action_controller/metal/rendering.rb | 47 +++++++++++----------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index e524e546ad..14cc547dd0 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -20,36 +20,35 @@ module ActionController private - # Normalize arguments by catching blocks and setting them on :update. - def _normalize_args(action=nil, options={}, &blk) #:nodoc: - options = super - options[:update] = blk if block_given? - options - end - - # Normalize both text and status options. - def _normalize_options(options) #:nodoc: - if options.key?(:text) && options[:text].respond_to?(:to_text) - options[:text] = options[:text].to_text - end + # Normalize arguments by catching blocks and setting them on :update. + def _normalize_args(action=nil, options={}, &blk) #:nodoc: + options = super + options[:update] = blk if block_given? + options + end - if options[:status] - options[:status] = Rack::Utils.status_code(options[:status]) - end + # Normalize both text and status options. + def _normalize_options(options) #:nodoc: + if options.key?(:text) && options[:text].respond_to?(:to_text) + options[:text] = options[:text].to_text + end - super + if options[:status] + options[:status] = Rack::Utils.status_code(options[:status]) end - # Process controller specific options, as status, content-type and location. - def _process_options(options) #:nodoc: - status, content_type, location = options.values_at(:status, :content_type, :location) + super + end - self.status = status if status - self.content_type = content_type if content_type - self.headers["Location"] = url_for(location) if location + # Process controller specific options, as status, content-type and location. + def _process_options(options) #:nodoc: + status, content_type, location = options.values_at(:status, :content_type, :location) - super - end + self.status = status if status + self.content_type = content_type if content_type + self.headers["Location"] = url_for(location) if location + super + end end end -- cgit v1.2.3 From 5b86e8f5e9fbc55a04d72113035054c35a400507 Mon Sep 17 00:00:00 2001 From: nosolopau Date: Sat, 20 Nov 2010 04:23:31 -0800 Subject: Spelling mistake: "Projecto" instead of "projeto" --- railties/guides/source/3_0_release_notes.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile index 9c08c9fa0a..2d9655fa7a 100644 --- a/railties/guides/source/3_0_release_notes.textile +++ b/railties/guides/source/3_0_release_notes.textile @@ -271,10 +271,10 @@ end scope 'es' do - resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'projeto' + resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'projecto' end -# Gives you the edit action with /es/projeto/1/cambiar +# Gives you the edit action with /es/projecto/1/cambiar * Added +root+ method to the router as a short cut for match '/', :to => path. -- cgit v1.2.3 From 206e48e8b943981b5b9ffc1fe7a2150e2ac21427 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 20 Nov 2010 16:20:42 +0100 Subject: applies API conventions to the RDoc of json_encode * Examples running with the text are preferred over separate Example sections. * No need to call puts, in # => we show the return value, not STDOUT. * Say explicitly that double quotes are removed. * Specify that we are talking \uXXX, rather than, say, HTML entities. --- .../core_ext/string/output_safety.rb | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 37c206ea3c..bb0f747960 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -33,21 +33,23 @@ class ERB singleton_class.send(:remove_method, :html_escape) module_function :html_escape - # A utility method for escaping HTML entities in JSON strings. - # This method is also aliased as j. + # A utility method for escaping HTML entities in JSON strings + # using \uXXXX JavaScript escape sequences for string literals: # - # Note that after this operation is performed the output is not - # a valid JSON. + # json_escape("is a > 0 & a < 10?") + # # => is a \u003E 0 \u0026 a \u003C 10? # - # In your ERb templates, use this method to escape any HTML entities: - # <%=j @person.to_json %> + # Note that after this operation is performed the output is not + # valid JSON. In particular double quotes are removed: # - # ==== Example: - # puts json_escape("{\"name\":\"john\",\"created_at\":\"2010-04-28T01:39:31Z\",\"id\":1}") + # json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}') # # => {name:john,created_at:2010-04-28T01:39:31Z,id:1} # - # puts json_escape("is a > 0 & a < 10?") - # # => is a \u003E 0 \u0026 a \u003C 10? + # This method is also aliased as +j+, and available as a helper + # in Rails templates: + # + # <%=j @person.to_json %> + # def json_escape(s) s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } end -- cgit v1.2.3 From 3ddbaf955e45eed15662e2f141b75dc0df63c1b0 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Sun, 21 Nov 2010 01:36:27 +0700 Subject: Mention the case that `render` will return nil if given `:collection` is nil or empty when rendering partial. --- actionpack/lib/action_view/partials.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb index 844c3e9572..cd3f130dc4 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/partials.rb @@ -75,6 +75,11 @@ module ActionView # # <%= render :partial => "ad", :collection => @advertisements, :spacer_template => "ad_divider" %> # + # If the given :collection is nil or empty, render will return nil. This will allow you + # to specify a text which will displayed instead by using this form: + # + # <%= render(:partial => "ad", :collection => @advertisements) || "There's no ad to be displayed" %> + # # NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also # just keep domain objects, like Active Records, in there. # -- cgit v1.2.3 From 8d8062190ddd0452088f6ea917267ed993a70990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 20 Nov 2010 19:39:30 +0100 Subject: I18n is always loaded on boot by Active Model or Action Pack, so no need for supporting lazy hooks. --- activesupport/lib/active_support/i18n.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 4d33f597d9..00ea8813dd 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -7,4 +7,3 @@ rescue LoadError => e end I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" -ActiveSupport.run_load_hooks(:i18n) -- cgit v1.2.3 From d7db6a88734c3b666f4b85f266d223eff408b294 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 19 Nov 2010 18:29:33 +0100 Subject: class inheritable attributes is used no more! all internal use of class inheritable has been changed to class_attribute. class inheritable attributes has been deprecated. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionmailer/lib/action_mailer/test_case.rb | 7 +++++-- actionpack/lib/action_controller/test_case.rb | 6 ++++-- .../vendor/html-scanner/html/sanitizer.rb | 4 ++-- actionpack/lib/action_view/helpers/form_helper.rb | 4 ++-- activerecord/lib/active_record/associations.rb | 13 +++++++------ .../associations/association_collection.rb | 2 +- .../lib/active_record/attribute_methods/dirty.rb | 3 ++- .../attribute_methods/time_zone_conversion.rb | 6 ++++-- activerecord/lib/active_record/base.rb | 20 ++++++++++++-------- activerecord/lib/active_record/named_scope.rb | 10 ++++++---- activerecord/lib/active_record/nested_attributes.rb | 13 +++++++++---- activerecord/lib/active_record/reflection.rb | 20 +++++++++----------- activerecord/lib/active_record/timestamp.rb | 8 +++++--- activerecord/test/cases/associations_test.rb | 8 ++++---- activeresource/lib/active_resource/base.rb | 8 +++++--- .../core_ext/class/inheritable_attributes.rb | 9 +++++++++ .../class/class_inheritable_attributes_test.rb | 5 +++++ 17 files changed, 91 insertions(+), 55 deletions(-) diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb index f4d1bb59f1..63e18147f6 100644 --- a/actionmailer/lib/action_mailer/test_case.rb +++ b/actionmailer/lib/action_mailer/test_case.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActionMailer class NonInferrableMailerError < ::StandardError def initialize(name) @@ -15,11 +17,11 @@ module ActionMailer module ClassMethods def tests(mailer) - write_inheritable_attribute(:mailer_class, mailer) + self._mailer_class = mailer end def mailer_class - if mailer = read_inheritable_attribute(:mailer_class) + if mailer = self._mailer_class mailer else tests determine_default_mailer(name) @@ -65,6 +67,7 @@ module ActionMailer end included do + class_attribute :_mailer_class setup :initialize_test_deliveries setup :set_expected_mail end diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 2b2f647d32..0f43527a56 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -1,6 +1,7 @@ require 'rack/session/abstract/id' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/to_query' +require 'active_support/core_ext/class/attribute' module ActionController module TemplateAssertions @@ -325,11 +326,11 @@ module ActionController def controller_class=(new_class) prepare_controller_class(new_class) if new_class - write_inheritable_attribute(:controller_class, new_class) + self._controller_class = new_class end def controller_class - if current_controller_class = read_inheritable_attribute(:controller_class) + if current_controller_class = self._controller_class current_controller_class else self.controller_class = determine_default_controller_class(name) @@ -442,6 +443,7 @@ module ActionController included do include ActionController::TemplateAssertions include ActionDispatch::Assertions + class_attribute :_controller_class setup :setup_controller_request_and_response end diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index dceddb9b80..3e5d23b5c1 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -1,5 +1,5 @@ require 'set' -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' module HTML class Sanitizer @@ -60,7 +60,7 @@ module HTML class WhiteListSanitizer < Sanitizer [:protocol_separator, :uri_attributes, :allowed_attributes, :allowed_tags, :allowed_protocols, :bad_tags, :allowed_css_properties, :allowed_css_keywords, :shorthand_css_properties].each do |attr| - class_inheritable_accessor attr, :instance_writer => false + class_attribute attr, :instance_writer => false end # A regular expression of the valid characters used to separate protocols like diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 8c300ec745..ef5bbd8ae3 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -2,7 +2,7 @@ require 'cgi' require 'action_view/helpers/date_helper' require 'action_view/helpers/tag_helper' require 'action_view/helpers/form_tag_helper' -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/string/output_safety' @@ -1117,7 +1117,7 @@ module ActionView class FormBuilder #:nodoc: # The methods which wrap a form helper call. - class_inheritable_accessor :field_helpers + class_attribute :field_helpers self.field_helpers = (FormHelper.instance_method_names - ['form_for']) attr_accessor :object_name, :object, :options diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 08a4ebfd7e..7da38cd03f 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -4,6 +4,7 @@ require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/module/remove_method' +require 'active_support/core_ext/class/attribute' module ActiveRecord class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc: @@ -1810,12 +1811,12 @@ module ActiveRecord callbacks.each do |callback_name| full_callback_name = "#{callback_name}_for_#{association_name}" defined_callbacks = options[callback_name.to_sym] - if options.has_key?(callback_name.to_sym) - class_inheritable_reader full_callback_name.to_sym - write_inheritable_attribute(full_callback_name.to_sym, [defined_callbacks].flatten) - else - write_inheritable_attribute(full_callback_name.to_sym, []) - end + + full_callback_value = options.has_key?(callback_name.to_sym) ? [defined_callbacks].flatten : [] + + # TODO : why do i need method_defined? I think its because of the inheritance chain + class_attribute full_callback_name.to_sym unless method_defined?(full_callback_name) + self.send("#{full_callback_name}=", full_callback_value) end end diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 6090376bb8..774103342a 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -530,7 +530,7 @@ module ActiveRecord def callbacks_for(callback_name) full_callback_name = "#{callback_name}_for_#{@reflection.name}" - @owner.class.read_inheritable_attribute(full_callback_name.to_sym) || [] + @owner.class.send(full_callback_name.to_sym) || [] end def ensure_owner_is_not_new diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 439880c1fa..c19a33faa8 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/object/blank' module ActiveRecord @@ -88,7 +89,7 @@ module ActiveRecord end def clone_with_time_zone_conversion_attribute?(attr, old) - old.class.name == "Time" && time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(attr.to_sym) + old.class.name == "Time" && time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(attr.to_sym) end end end diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index d640b26b74..dc2785b6bf 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActiveRecord module AttributeMethods module TimeZoneConversion @@ -7,7 +9,7 @@ module ActiveRecord cattr_accessor :time_zone_aware_attributes, :instance_writer => false self.time_zone_aware_attributes = false - class_inheritable_accessor :skip_time_zone_conversion_for_attributes, :instance_writer => false + class_attribute :skip_time_zone_conversion_for_attributes, :instance_writer => false self.skip_time_zone_conversion_for_attributes = [] end @@ -54,7 +56,7 @@ module ActiveRecord private def create_time_zone_conversion_attribute?(name, column) - time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(name.to_sym) && [:datetime, :timestamp].include?(column.type) + time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) && [:datetime, :timestamp].include?(column.type) end end end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 314f676711..8bde1869c7 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -7,7 +7,7 @@ require 'active_support/time' require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/class/delegating_attributes' -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/hash/deep_merge' require 'active_support/core_ext/hash/indifferent_access' @@ -412,7 +412,7 @@ module ActiveRecord #:nodoc: self.store_full_sti_class = true # Stores the default scope for the class - class_inheritable_accessor :default_scoping, :instance_writer => false + class_attribute :default_scoping, :instance_writer => false self.default_scoping = [] # Returns a hash of all the attributes that have been specified for serialization as @@ -420,6 +420,9 @@ module ActiveRecord #:nodoc: class_attribute :serialized_attributes self.serialized_attributes = {} + class_attribute :_attr_readonly, :instance_writer => false + self._attr_readonly = [] + class << self # Class methods delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped delegate :find_each, :find_in_batches, :to => :scoped @@ -504,12 +507,12 @@ module ActiveRecord #:nodoc: # Attributes listed as readonly will be used to create a new record but update operations will # ignore these fields. def attr_readonly(*attributes) - write_inheritable_attribute(:attr_readonly, Set.new(attributes.map { |a| a.to_s }) + (readonly_attributes || [])) + self._attr_readonly = Set.new(attributes.map { |a| a.to_s }) + (self._attr_readonly || []) end # Returns an array of all the attributes that have been specified as readonly. def readonly_attributes - read_inheritable_attribute(:attr_readonly) || [] + self._attr_readonly end # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, @@ -724,8 +727,8 @@ module ActiveRecord #:nodoc: @arel_engine = @relation = @arel_table = nil end - def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc: - descendants.each { |klass| klass.reset_inheritable_attributes; klass.reset_column_information } + def reset_column_information_for_all_subclasses#:nodoc: + descendants.each { |klass| klass.reset_column_information } end def attribute_method?(attribute) @@ -1126,7 +1129,8 @@ MSG # Article.create.published # => true def default_scope(options = {}) reset_scoped_methods - self.default_scoping << construct_finder_arel(options, default_scoping.pop) + default_scoping = self.default_scoping.dup + self.default_scoping = default_scoping << construct_finder_arel(options, default_scoping.pop) end def current_scoped_methods #:nodoc: @@ -1579,7 +1583,7 @@ MSG self.class.columns_hash[name.to_s] end - # Returns true if +comparison_object+ is the same exact object, or +comparison_object+ + # Returns true if +comparison_object+ is the same exact object, or +comparison_object+ # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+. # # Note that new records are different from any other record by definition, unless the diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 0b92ba5caa..0f421560f0 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -2,12 +2,18 @@ require 'active_support/core_ext/array' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/kernel/singleton_class' require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/class/attribute' module ActiveRecord # = Active Record Named \Scopes module NamedScope extend ActiveSupport::Concern + included do + class_attribute :scopes + self.scopes = {} + end + module ClassMethods # Returns an anonymous \scope. # @@ -33,10 +39,6 @@ module ActiveRecord end end - def scopes - read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) - end - # Adds a class method for retrieving and querying objects. A \scope represents a narrowing of a database query, # such as where(:color => :red).select('shirts.*').includes(:washing_instructions). # diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 0c3392263a..f1d3eaed38 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -2,6 +2,7 @@ require 'active_support/core_ext/hash/except' require 'active_support/core_ext/object/try' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/hash/indifferent_access' +require 'active_support/core_ext/class/attribute' module ActiveRecord module NestedAttributes #:nodoc: @@ -11,7 +12,7 @@ module ActiveRecord extend ActiveSupport::Concern included do - class_inheritable_accessor :nested_attributes_options, :instance_writer => false + class_attribute :nested_attributes_options, :instance_writer => false self.nested_attributes_options = {} end @@ -268,7 +269,11 @@ module ActiveRecord if reflection = reflect_on_association(association_name) reflection.options[:autosave] = true add_autosave_association_callbacks(reflection) + + nested_attributes_options = self.nested_attributes_options.dup nested_attributes_options[association_name.to_sym] = options + self.nested_attributes_options = nested_attributes_options + type = (reflection.collection? ? :collection : :one_to_one) # def pirate_attributes=(attributes) @@ -315,7 +320,7 @@ module ActiveRecord # update_only is true, and a :_destroy key set to a truthy value, # then the existing record will be marked for destruction. def assign_nested_attributes_for_one_to_one_association(association_name, attributes) - options = nested_attributes_options[association_name] + options = self.nested_attributes_options[association_name] attributes = attributes.with_indifferent_access check_existing_record = (options[:update_only] || !attributes['id'].blank?) @@ -364,7 +369,7 @@ module ActiveRecord # { :id => '2', :_destroy => true } # ]) def assign_nested_attributes_for_collection_association(association_name, attributes_collection) - options = nested_attributes_options[association_name] + options = self.nested_attributes_options[association_name] unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array) raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})" @@ -433,7 +438,7 @@ module ActiveRecord end def call_reject_if(association_name, attributes) - case callback = nested_attributes_options[association_name][:reject_if] + case callback = self.nested_attributes_options[association_name][:reject_if] when Symbol method(callback).arity == 0 ? send(callback) : send(callback, attributes) when Proc diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index a2260e9a19..a07c321960 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -1,8 +1,15 @@ +require 'active_support/core_ext/class/attribute' + module ActiveRecord # = Active Record Reflection module Reflection # :nodoc: extend ActiveSupport::Concern + included do + class_attribute :reflections + self.reflections = {} + end + # Reflection enables to interrogate Active Record classes and objects # about their associations and aggregations. This information can, # for example, be used in a form builder that takes an Active Record object @@ -20,18 +27,9 @@ module ActiveRecord when :composed_of reflection = AggregateReflection.new(macro, name, options, active_record) end - write_inheritable_hash :reflections, name => reflection - reflection - end - # Returns a hash containing all AssociationReflection objects for the current class. - # Example: - # - # Invoice.reflections - # Account.reflections - # - def reflections - read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {}) + self.reflections = self.reflections.merge(name => reflection) + reflection end # Returns an array of AggregateReflection objects for all the aggregations in the class. diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index 230adf6b2b..2ecbd906bd 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/class/attribute' + module ActiveRecord # = Active Record Timestamp # @@ -29,14 +31,14 @@ module ActiveRecord extend ActiveSupport::Concern included do - class_inheritable_accessor :record_timestamps, :instance_writer => false + class_attribute :record_timestamps, :instance_writer => false self.record_timestamps = true end private def create #:nodoc: - if record_timestamps + if self.record_timestamps current_time = current_time_from_proper_timezone all_timestamp_attributes.each do |column| @@ -61,7 +63,7 @@ module ActiveRecord end def should_record_timestamps? - record_timestamps && (!partial_updates? || changed? || (attributes.keys & self.class.serialized_attributes.keys).present?) + self.record_timestamps && (!partial_updates? || changed? || (attributes.keys & self.class.serialized_attributes.keys).present?) end def timestamp_attributes_for_update_in_model diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 93a51d3606..83c605d2bb 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -270,17 +270,17 @@ class OverridingAssociationsTest < ActiveRecord::TestCase def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited # redeclared association on AR descendant should not inherit callbacks from superclass - callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) + callbacks = PeopleList.before_add_for_has_and_belongs_to_many assert_equal([:enlist], callbacks) - callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) + callbacks = DifferentPeopleList.before_add_for_has_and_belongs_to_many assert_equal([], callbacks) end def test_has_many_association_redefinition_callbacks_should_differ_and_not_inherited # redeclared association on AR descendant should not inherit callbacks from superclass - callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_many) + callbacks = PeopleList.before_add_for_has_many assert_equal([:enlist], callbacks) - callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_many) + callbacks = DifferentPeopleList.before_add_for_has_many assert_equal([], callbacks) end diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb index b5b46d7431..d959fd103a 100644 --- a/activeresource/lib/active_resource/base.rb +++ b/activeresource/lib/active_resource/base.rb @@ -1,6 +1,6 @@ require 'active_support' require 'active_support/core_ext/class/attribute_accessors' -require 'active_support/core_ext/class/inheritable_attributes' +require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/module/attr_accessor_with_default' @@ -263,6 +263,8 @@ module ActiveResource # The logger for diagnosing and tracing Active Resource calls. cattr_accessor :logger + class_attribute :_format + class << self # Creates a schema for this resource - setting the attributes that are # known prior to fetching an instance from the remote system. @@ -492,13 +494,13 @@ module ActiveResource format = mime_type_reference_or_format.is_a?(Symbol) ? ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format - write_inheritable_attribute(:format, format) + self._format = format connection.format = format if site end # Returns the current format, default is ActiveResource::Formats::XmlFormat. def format - read_inheritable_attribute(:format) || ActiveResource::Formats::XmlFormat + self._format || ActiveResource::Formats::XmlFormat end # Sets the number of seconds after which requests to the REST API should time out. diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb index 043a650ea0..ca3db2349e 100644 --- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb @@ -1,8 +1,10 @@ require 'active_support/core_ext/object/duplicable' require 'active_support/core_ext/array/extract_options' +require 'active_support/deprecation' # Retained for backward compatibility. Methods are now included in Class. module ClassInheritableAttributes # :nodoc: + DEPRECATION_WARNING_MESSAGE = "class_inheritable_attribute is deprecated, please use class_attribute method instead. Notice their behavior are slightly different, so refer to class_attribute documentation first" end # It is recommended to use class_attribute over methods defined in this file. Please @@ -36,6 +38,7 @@ end # Person.new.hair_colors # => NoMethodError class Class # :nodoc: def class_inheritable_reader(*syms) + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE options = syms.extract_options! syms.each do |sym| next if sym.is_a?(Hash) @@ -54,6 +57,7 @@ class Class # :nodoc: end def class_inheritable_writer(*syms) + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@ -71,6 +75,7 @@ class Class # :nodoc: end def class_inheritable_array_writer(*syms) + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@ -88,6 +93,7 @@ class Class # :nodoc: end def class_inheritable_hash_writer(*syms) + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE options = syms.extract_options! syms.each do |sym| class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@ -124,6 +130,7 @@ class Class # :nodoc: end def write_inheritable_attribute(key, value) + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES) @inheritable_attributes = {} end @@ -141,10 +148,12 @@ class Class # :nodoc: end def read_inheritable_attribute(key) + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE inheritable_attributes[key] end def reset_inheritable_attributes + ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES end diff --git a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb index b284e5ee1c..020dfce56a 100644 --- a/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb +++ b/activesupport/test/core_ext/class/class_inheritable_attributes_test.rb @@ -3,9 +3,14 @@ require 'active_support/core_ext/class/inheritable_attributes' class ClassInheritableAttributesTest < Test::Unit::TestCase def setup + ActiveSupport::Deprecation.silenced = true @klass = Class.new end + def teardown + ActiveSupport::Deprecation.silenced = false + end + def test_reader_declaration assert_nothing_raised do @klass.class_inheritable_reader :a -- cgit v1.2.3 From 8796f9a31a77bb2ab97ea6c2cf2036fb6e38497e Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 19 Nov 2010 18:30:48 +0100 Subject: removed an AR method which wasn't used internally, had no tests, and had no docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- activerecord/lib/active_record/base.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8bde1869c7..aee6f3a7eb 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -727,10 +727,6 @@ module ActiveRecord #:nodoc: @arel_engine = @relation = @arel_table = nil end - def reset_column_information_for_all_subclasses#:nodoc: - descendants.each { |klass| klass.reset_column_information } - end - def attribute_method?(attribute) super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, ''))) end -- cgit v1.2.3 From d5779efaf2375466ab557868e586b9dbd942abc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 20 Nov 2010 21:56:08 +0100 Subject: Ensure calling reset session twice does not raise errors. --- actionpack/test/activerecord/active_record_store_test.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 7c595d1b89..f0fb113860 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -23,6 +23,7 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest def call_reset_session session[:foo] reset_session + reset_session if params[:twice] session[:foo] = "baz" head :ok end @@ -94,6 +95,17 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest end end + def test_calling_reset_session_twice_does_not_raise_errors + with_test_route_set do + get '/call_reset_session', :twice => "true" + assert_response :success + + get '/get_session_value' + assert_response :success + assert_equal 'foo: "baz"', response.body + end + end + def test_setting_session_value_after_session_reset with_test_route_set do get '/set_session_value' -- cgit v1.2.3 From d773ef8e8c819f09ad3b436b11631c26e4ca2ff9 Mon Sep 17 00:00:00 2001 From: Jamison Dance Date: Sat, 20 Nov 2010 14:55:39 -0700 Subject: fix some grammar issues with section 2.5 --- railties/guides/source/active_record_validations_callbacks.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 444a1d4154..59db20c926 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -141,7 +141,7 @@ end h4(#validations_overview-errors). +errors[]+ -To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+ that returns an array with all attribute errors, when there are no errors on the specified attribute, an empty array is returned. +To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+. It returns an array of all the errors for +:attribue+. If there are no errors on the specified attribute, an empty array is returned. This method is only useful _after_ validations have been run, because it only inspects the errors collection and does not trigger validations itself. It's different from the +ActiveRecord::Base#invalid?+ method explained above because it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. -- cgit v1.2.3 From 074782eda2caddb054d20a99e8d167ef8e1eecd2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 21 Nov 2010 00:01:10 +0100 Subject: copy-edits d773ef8 --- railties/guides/source/active_record_validations_callbacks.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 59db20c926..9ddbe6fadc 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -141,7 +141,7 @@ end h4(#validations_overview-errors). +errors[]+ -To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+. It returns an array of all the errors for +:attribue+. If there are no errors on the specified attribute, an empty array is returned. +To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+. It returns an array of all the errors for +:attribute+. If there are no errors on the specified attribute, an empty array is returned. This method is only useful _after_ validations have been run, because it only inspects the errors collection and does not trigger validations itself. It's different from the +ActiveRecord::Base#invalid?+ method explained above because it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. -- cgit v1.2.3 From 69d47a00c7e43e2431aa1b164a2e6309da1bf118 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Sat, 20 Nov 2010 21:00:44 -0500 Subject: use_accept_header is no longer supported --- actionpack/lib/action_dispatch/http/mime_negotiation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index b959aa258e..5bb42cca3a 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -36,7 +36,7 @@ module ActionDispatch # # GET /posts/5.xml | request.format => Mime::XML # GET /posts/5.xhtml | request.format => Mime::HTML - # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of ActionController::Base.use_accept_header + # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first # def format(view_path = []) formats.first -- cgit v1.2.3 From f326221c701e4f9d991e3eadcc793a73795fb218 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 21 Nov 2010 03:22:57 +0100 Subject: Spanish for "project" is "proyecto" --- railties/guides/source/3_0_release_notes.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile index 2d9655fa7a..adb1c755df 100644 --- a/railties/guides/source/3_0_release_notes.textile +++ b/railties/guides/source/3_0_release_notes.textile @@ -271,10 +271,10 @@ end scope 'es' do - resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'projecto' + resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'proyecto' end -# Gives you the edit action with /es/projecto/1/cambiar +# Gives you the edit action with /es/proyecto/1/cambiar * Added +root+ method to the router as a short cut for match '/', :to => path. -- cgit v1.2.3 From 3d377454dbeb9ab9fc0a4d491498c237e33e8d4b Mon Sep 17 00:00:00 2001 From: eparreno Date: Mon, 15 Nov 2010 19:21:40 +0100 Subject: remove old school validations and replaced with new validates method. Pending: fix active_record guide --- .../active_record_validations_callbacks.textile | 18 ++++---- railties/guides/source/i18n.textile | 48 +++++++++++----------- railties/guides/source/migrations.textile | 2 +- railties/guides/source/security.textile | 2 +- railties/guides/source/testing.textile | 2 +- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index f7ef33bc1f..2a6f0715a9 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -96,7 +96,7 @@ To verify whether or not an object is valid, Rails uses the +valid?+ method. You class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end Person.create(:name => "John Doe").valid? # => true @@ -109,7 +109,7 @@ Note that an object instantiated with +new+ will not report errors even if it's class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end >> p = Person.new @@ -147,7 +147,7 @@ This method is only useful _after_ validations have been run, because it only in class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end >> Person.new.errors[:name].any? # => false @@ -355,7 +355,7 @@ This helper validates that the specified attributes are not empty. It uses the + class Person < ActiveRecord::Base - validates_presence_of :name, :login, :email + validates :name, :presence => true, :login, :email end @@ -505,7 +505,7 @@ class Person < ActiveRecord::Base validates_numericality_of :age, :on => :update # the default (validates on both create and update) - validates_presence_of :name, :on => :save + validates :name, :presence => true, :on => :save end @@ -603,7 +603,7 @@ Returns an OrderedHash with all errors. Each key is the attribute name and the v class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 end @@ -623,7 +623,7 @@ h4(#working_with_validation_errors-errors-2). +errors[]+ class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 end @@ -699,7 +699,7 @@ The +clear+ method is used when you intentionally want to clear all the messages class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 end @@ -723,7 +723,7 @@ The +size+ method returns the total number of error messages for the object. class Person < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true validates_length_of :name, :minimum => 3 validates_presence_of :email end diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 825185c832..12901e4dac 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -672,11 +672,11 @@ Active Record validation error messages can also be translated easily. Active Re This gives you quite powerful means to flexibly adjust your messages to your application's needs. -Consider a User model with a +validates_presence_of+ validation for the name attribute like this: +Consider a User model with a validation for the name attribute like this: class User < ActiveRecord::Base - validates_presence_of :name + validates :name, :presence => true end @@ -706,7 +706,7 @@ For example, you might have an Admin model inheriting from User: class Admin < User - validates_presence_of :name + validates :name, :presence => true end @@ -733,27 +733,27 @@ So, for example, instead of the default error message +"can not be blank"+ you c * +count+, where available, can be used for pluralization if present: |_. validation |_.with option |_.message |_.interpolation| -| validates_confirmation_of | - | :confirmation | -| -| validates_acceptance_of | - | :accepted | -| -| validates_presence_of | - | :blank | -| -| validates_length_of | :within, :in | :too_short | count| -| validates_length_of | :within, :in | :too_long | count| -| validates_length_of | :is | :wrong_length | count| -| validates_length_of | :minimum | :too_short | count| -| validates_length_of | :maximum | :too_long | count| -| validates_uniqueness_of | - | :taken | -| -| validates_format_of | - | :invalid | -| -| validates_inclusion_of | - | :inclusion | -| -| validates_exclusion_of | - | :exclusion | -| -| validates_associated | - | :invalid | -| -| validates_numericality_of | - | :not_a_number | -| -| validates_numericality_of | :greater_than | :greater_than | count| -| validates_numericality_of | :greater_than_or_equal_to | :greater_than_or_equal_to | count| -| validates_numericality_of | :equal_to | :equal_to | count| -| validates_numericality_of | :less_than | :less_than | count| -| validates_numericality_of | :less_than_or_equal_to | :less_than_or_equal_to | count| -| validates_numericality_of | :odd | :odd | -| -| validates_numericality_of | :even | :even | -| +| confirmation | - | :confirmation | -| +| acceptance | - | :accepted | -| +| presence | - | :blank | -| +| length | :within, :in | :too_short | count| +| length | :within, :in | :too_long | count| +| length | :is | :wrong_length | count| +| length | :minimum | :too_short | count| +| length | :maximum | :too_long | count| +| uniqueness | - | :taken | -| +| format | - | :invalid | -| +| inclusion | - | :inclusion | -| +| exclusion | - | :exclusion | -| +| associated | - | :invalid | -| +| numericality | - | :not_a_number | -| +| numericality | :greater_than | :greater_than | count| +| numericality | :greater_than_or_equal_to | :greater_than_or_equal_to | count| +| numericality | :equal_to | :equal_to | count| +| numericality | :less_than | :less_than | count| +| numericality | :less_than_or_equal_to | :less_than_or_equal_to | count| +| numericality | :odd | :odd | -| +| numericality | :even | :even | -| h5. Translations for the Active Record +error_messages_for+ Helper diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index a9c3d51752..0d13fbc10a 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -584,7 +584,7 @@ h3. Active Record and Referential Integrity The Active Record way claims that intelligence belongs in your models, not in the database. As such, features such as triggers or foreign key constraints, which push some of that intelligence back into the database, are not heavily used. -Validations such as +validates_uniqueness_of+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints. +Validations such as +validates :foreign_key, :uniqueness => true+ are one way in which models can enforce data integrity. The +:dependent+ option on associations allows models to automatically destroy child objects when the parent is destroyed. Like anything which operates at the application level these cannot guarantee referential integrity and so some people augment them with foreign key constraints. Although Active Record does not provide any tools for working directly with such features, the +execute+ method can be used to execute arbitrary SQL. There are also a number of plugins such as "foreign_key_migrations":http://github.com/harukizaemon/redhillonrails/tree/master/foreign_key_migrations/ which add foreign key support to Active Record (including support for dumping foreign keys in +db/schema.rb+). diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index 693645b202..6f766430c1 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -550,7 +550,7 @@ Ruby uses a slightly different approach than many other languages to match the e class File < ActiveRecord::Base - validates_format_of :name, :with => /^[\w\.\-\+]+$/ + validates :name, format => /^[\w\.\-\+]+$/ end diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile index 3d4f31cc5d..c292a5d83b 100644 --- a/railties/guides/source/testing.textile +++ b/railties/guides/source/testing.textile @@ -315,7 +315,7 @@ Now to get this test to pass we can add a model level validation for the _title_ class Post < ActiveRecord::Base - validates_presence_of :title + validates :title, :presence => true end -- cgit v1.2.3 From 4a51328ae8d51f8d1a637780d5b82fd27261758f Mon Sep 17 00:00:00 2001 From: zhengjia Date: Tue, 16 Nov 2010 09:26:21 -0600 Subject: Minor fix on Rails:Railtie documentation --- railties/lib/rails/railtie.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index c76bc83377..030a838dc1 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -97,7 +97,7 @@ module Rails # If your railtie has rake tasks, you can tell Rails to load them through the method # rake tasks: # - # class MyRailtie < Railtie + # class MyRailtie < Rails::Railtie # rake_tasks do # load "path/to/my_railtie.tasks" # end @@ -107,7 +107,7 @@ module Rails # your generators at a different location, you can specify in your Railtie a block which # will load them during normal generators lookup: # - # class MyRailtie < Railtie + # class MyRailtie < Rails::Railtie # generators do # require "path/to/my_railtie_generator" # end -- cgit v1.2.3 From 3c645536448e1ba1fa81160162a1eefe03bb6787 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Tue, 16 Nov 2010 22:25:20 +0100 Subject: i18n guide: it's activerecord.errors.messages.record_invalid (instead of 'invalid'), and messagges typo --- railties/guides/source/i18n.textile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 12901e4dac..4f6ae5fbd2 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -464,24 +464,24 @@ I18n.t 'message' The +translate+ method also takes a +:scope+ option which can contain one or more additional keys that will be used to specify a “namespace” or scope for a translation key: -I18n.t :invalid, :scope => [:activerecord, :errors, :messages] +I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages] -This looks up the +:invalid+ message in the Active Record error messages. +This looks up the +:record_invalid+ message in the Active Record error messages. Additionally, both the key and scopes can be specified as dot-separated keys as in: -I18n.translate :"activerecord.errors.messages.invalid" +I18n.translate "activerecord.errors.messages.record_invalid" Thus the following calls are equivalent: -I18n.t 'activerecord.errors.messages.invalid' -I18n.t 'errors.messages.invalid', :scope => :active_record -I18n.t :invalid, :scope => 'activerecord.errors.messages' -I18n.t :invalid, :scope => [:activerecord, :errors, :messages] +I18n.t 'activerecord.errors.messages.record_invalid' +I18n.t 'errors.messages.record_invalid', :scope => :active_record +I18n.t :record_invalid, :scope => 'activerecord.errors.messages' +I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages] h5. Defaults @@ -697,7 +697,7 @@ activerecord.errors.models.user.attributes.name.blank activerecord.errors.models.user.blank activerecord.errors.messages.blank errors.attributes.name.blank -errors.messagges.blank +errors.messages.blank When your models are additionally using inheritance then the messages are looked up in the inheritance chain. @@ -719,7 +719,7 @@ activerecord.errors.models.user.attributes.title.blank activerecord.errors.models.user.blank activerecord.errors.messages.blank errors.attributes.title.blank -errors.messagges.blank +errors.messages.blank This way you can provide special translations for various error messages at different points in your models inheritance chain and in the attributes, models, or default scopes. -- cgit v1.2.3 From cbea139130f0d5794a7756fcf93aed48c033ce29 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Tue, 16 Nov 2010 22:35:11 +0100 Subject: i18n guide: remove link to external page about 'How to encode the current locale in the URL' as it no longer exists --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 4f6ae5fbd2..31b6d72041 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -253,7 +253,7 @@ match '/:locale' => 'dashboard#index' Do take special care about the *order of your routes*, so this route declaration does not "eat" other ones. (You may want to add it directly before the +root :to+ declaration.) -IMPORTANT: This solution has currently one rather big *downside*. Due to the _default_url_options_ implementation, you have to pass the +:id+ option explicitly, like this: +link_to 'Show', book_url(:id => book)+ and not depend on Rails' magic in code like +link_to 'Show', book+. If this should be a problem, have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. See also the page "How to encode the current locale in the URL":http://rails-i18n.org/wiki/wikipages/how-to-encode-the-current-locale-in-the-url in the Rails i18n Wiki. +IMPORTANT: This solution has currently one rather big *downside*. Due to the _default_url_options_ implementation, you have to pass the +:id+ option explicitly, like this: +link_to 'Show', book_url(:id => book)+ and not depend on Rails' magic in code like +link_to 'Show', book+. If this should be a problem, have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. h4. Setting the Locale from the Client Supplied Information -- cgit v1.2.3 From f044d38192dab10ccdf6556e2bb3b9c90a912fbe Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Wed, 17 Nov 2010 09:24:47 +0100 Subject: i18n guide: this is not longer a problem --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 31b6d72041..4ae11b1b7b 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -253,7 +253,7 @@ match '/:locale' => 'dashboard#index' Do take special care about the *order of your routes*, so this route declaration does not "eat" other ones. (You may want to add it directly before the +root :to+ declaration.) -IMPORTANT: This solution has currently one rather big *downside*. Due to the _default_url_options_ implementation, you have to pass the +:id+ option explicitly, like this: +link_to 'Show', book_url(:id => book)+ and not depend on Rails' magic in code like +link_to 'Show', book+. If this should be a problem, have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. +NOTE: Have a look at two plugins which simplify work with routes in this way: Sven Fuchs's "routing_filter":http://github.com/svenfuchs/routing-filter/tree/master and Raul Murciano's "translate_routes":http://github.com/raul/translate_routes/tree/master. h4. Setting the Locale from the Client Supplied Information -- cgit v1.2.3 From c8ab3992f85569e43055b9e57c67324f5d5088cd Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 17 Nov 2010 21:46:55 -0500 Subject: unscoped takes care of named_scopes too --- activerecord/lib/active_record/base.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index aee6f3a7eb..aa028c6f36 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -852,8 +852,7 @@ module ActiveRecord #:nodoc: # limit(10) # Fires "SELECT * FROM posts LIMIT 10" # } # - # It is recommended to use block form of unscoped because chaining unscoped with named_scope - # does not work. Assuming that published is a named_scope following two statements are same. + # Assuming that published is a named_scope following two statements are same. # # Post.unscoped.published # Post.published -- cgit v1.2.3 From f5a51a778804f7a48b8f43e591ad3bc6b828867e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Hackin?= Date: Thu, 18 Nov 2010 08:25:38 -0200 Subject: Fix code for customize the error messages html adding a .html_safe of 8.3 section --- railties/guides/source/active_record_validations_callbacks.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 2a6f0715a9..fddd715feb 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -824,10 +824,10 @@ Here is a simple example where we change the Rails behaviour to always display t ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| if instance.error_message.kind_of?(Array) %(#{html_tag}  - #{instance.error_message.join(',')}) + #{instance.error_message.join(',')}).html_safe else %(#{html_tag}  - #{instance.error_message}) + #{instance.error_message}).html_safe end end -- cgit v1.2.3 From 925aeed4b61141cc62dec42b0b577158f077ffc1 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Fri, 19 Nov 2010 17:25:37 +0100 Subject: i18n guide: fix external link to rack locale --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 4ae11b1b7b..1a83b84004 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -278,7 +278,7 @@ def extract_locale_from_accept_language_header end -Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's "http_accept_language":http://github.com/iain/http_accept_language/tree/master or even Rack middleware such as Ryan Tomayko's "locale":http://github.com/rtomayko/rack-contrib/blob/master/lib/rack/locale.rb. +Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's "http_accept_language":http://github.com/iain/http_accept_language/tree/master or even Rack middleware such as Ryan Tomayko's "locale":http://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/locale.rb. h5. Using GeoIP (or Similar) Database -- cgit v1.2.3 From f975f35147d7d6df7f6094bfd60e3b7dd45aa2b3 Mon Sep 17 00:00:00 2001 From: nosolopau Date: Sat, 20 Nov 2010 04:23:31 -0800 Subject: Spelling mistake: "Projecto" instead of "projeto" --- railties/guides/source/3_0_release_notes.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile index 9c08c9fa0a..2d9655fa7a 100644 --- a/railties/guides/source/3_0_release_notes.textile +++ b/railties/guides/source/3_0_release_notes.textile @@ -271,10 +271,10 @@ end scope 'es' do - resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'projeto' + resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'projecto' end -# Gives you the edit action with /es/projeto/1/cambiar +# Gives you the edit action with /es/projecto/1/cambiar * Added +root+ method to the router as a short cut for match '/', :to => path. -- cgit v1.2.3 From e65c23dc3e775be3162de25548f3192939ff3da3 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Sun, 21 Nov 2010 01:36:27 +0700 Subject: Mention the case that `render` will return nil if given `:collection` is nil or empty when rendering partial. --- actionpack/lib/action_view/partials.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb index 844c3e9572..cd3f130dc4 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/partials.rb @@ -75,6 +75,11 @@ module ActionView # # <%= render :partial => "ad", :collection => @advertisements, :spacer_template => "ad_divider" %> # + # If the given :collection is nil or empty, render will return nil. This will allow you + # to specify a text which will displayed instead by using this form: + # + # <%= render(:partial => "ad", :collection => @advertisements) || "There's no ad to be displayed" %> + # # NOTE: Due to backwards compatibility concerns, the collection can't be one of hashes. Normally you'd also # just keep domain objects, like Active Records, in there. # -- cgit v1.2.3 From ffed9db2692475a6e24354336f884991075906c5 Mon Sep 17 00:00:00 2001 From: Jamison Dance Date: Sat, 20 Nov 2010 14:55:39 -0700 Subject: fix some grammar issues with section 2.5 --- railties/guides/source/active_record_validations_callbacks.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index fddd715feb..940ee93cc1 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -141,7 +141,7 @@ end h4(#validations_overview-errors). +errors[]+ -To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+ that returns an array with all attribute errors, when there are no errors on the specified attribute, an empty array is returned. +To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+. It returns an array of all the errors for +:attribue+. If there are no errors on the specified attribute, an empty array is returned. This method is only useful _after_ validations have been run, because it only inspects the errors collection and does not trigger validations itself. It's different from the +ActiveRecord::Base#invalid?+ method explained above because it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. -- cgit v1.2.3 From a03a3b7c3130a93ca6385a1f89ce553d00ca3c49 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 21 Nov 2010 00:01:10 +0100 Subject: copy-edits d773ef8 --- railties/guides/source/active_record_validations_callbacks.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 940ee93cc1..9ce0423244 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -141,7 +141,7 @@ end h4(#validations_overview-errors). +errors[]+ -To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+. It returns an array of all the errors for +:attribue+. If there are no errors on the specified attribute, an empty array is returned. +To verify whether or not a particular attribute of an object is valid, you can use +errors[:attribute]+. It returns an array of all the errors for +:attribute+. If there are no errors on the specified attribute, an empty array is returned. This method is only useful _after_ validations have been run, because it only inspects the errors collection and does not trigger validations itself. It's different from the +ActiveRecord::Base#invalid?+ method explained above because it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. -- cgit v1.2.3 From 7d5b097357c3bbfb86c95271d1bdbe5148a01069 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Sat, 20 Nov 2010 21:00:44 -0500 Subject: use_accept_header is no longer supported --- actionpack/lib/action_dispatch/http/mime_negotiation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index b959aa258e..5bb42cca3a 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -36,7 +36,7 @@ module ActionDispatch # # GET /posts/5.xml | request.format => Mime::XML # GET /posts/5.xhtml | request.format => Mime::HTML - # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of ActionController::Base.use_accept_header + # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first # def format(view_path = []) formats.first -- cgit v1.2.3 From 7c51d1fcf9dc504c2dfd6e7184bbe8186f09819d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 21 Nov 2010 03:22:57 +0100 Subject: Spanish for "project" is "proyecto" --- railties/guides/source/3_0_release_notes.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/3_0_release_notes.textile b/railties/guides/source/3_0_release_notes.textile index 2d9655fa7a..adb1c755df 100644 --- a/railties/guides/source/3_0_release_notes.textile +++ b/railties/guides/source/3_0_release_notes.textile @@ -271,10 +271,10 @@ end scope 'es' do - resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'projecto' + resources :projects, :path_names => { :edit => 'cambiar' }, :path => 'proyecto' end -# Gives you the edit action with /es/projecto/1/cambiar +# Gives you the edit action with /es/proyecto/1/cambiar * Added +root+ method to the router as a short cut for match '/', :to => path. -- cgit v1.2.3 From 15fd29b3eaf9e2e202542fcf9a582b0180fc2664 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 21 Nov 2010 10:17:30 +0100 Subject: documents <%== in the AS guide --- railties/guides/source/active_support_core_extensions.textile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index d41d8b6c3d..7333a81cf9 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -1189,6 +1189,12 @@ To insert something verbatim use the +raw+ helper rather than calling +html_safe <%= raw @cms.current_template %> <%# inserts @cms.current_template as is %> +or, equivalently, use <%==: + + +<%== @cms.current_template %> <%# inserts @cms.current_template as is %> + + The +raw+ helper calls +html_safe+ for you: -- cgit v1.2.3 From 799a6fa047aa44ab4813dbf9328941b6d620e9b6 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 21 Nov 2010 10:25:23 +0100 Subject: realigns a series of hash arrows --- .../test/controller/new_base/render_template_test.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index 9899036fe8..584f2d772c 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -4,16 +4,16 @@ module RenderTemplate class WithoutLayoutController < ActionController::Base self.view_paths = [ActionView::FixtureResolver.new( - "test/basic.html.erb" => "Hello from basic.html.erb", - "shared.html.erb" => "Elastica", - "locals.html.erb" => "The secret is <%= secret %>", - "xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend", - "with_raw.html.erb" => "Hello <%=raw 'this is raw' %>", - "with_implicit_raw.html.erb"=> "Hello <%== 'this is also raw' %>", - "test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>", - "test/with_json.json.erb" => "<%= render :template => 'test/final' %>", - "test/final.json.erb" => "{ final: json }", - "test/with_error.html.erb" => "<%= idontexist %>" + "test/basic.html.erb" => "Hello from basic.html.erb", + "shared.html.erb" => "Elastica", + "locals.html.erb" => "The secret is <%= secret %>", + "xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend", + "with_raw.html.erb" => "Hello <%=raw 'this is raw' %>", + "with_implicit_raw.html.erb" => "Hello <%== 'this is also raw' %>", + "test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>", + "test/with_json.json.erb" => "<%= render :template => 'test/final' %>", + "test/final.json.erb" => "{ final: json }", + "test/with_error.html.erb" => "<%= idontexist %>" )] def index -- cgit v1.2.3 From 51007f1dbafe029ed85b2a296736a00e6b24ec58 Mon Sep 17 00:00:00 2001 From: Brian Alexander Date: Sun, 21 Nov 2010 19:54:05 -0800 Subject: Previous version inaccurately suggested that resources :posts, :path => "/admin" would route "/admin/posts" to the PostsController but it actually routed "/admin" to the PostsController --- railties/guides/source/routing.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 918279f9eb..2f5c88b8c3 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -194,7 +194,7 @@ end or, for a single case -resources :posts, :path => "/admin" +resources :posts, :path => "/admin/posts" In each of these cases, the named routes remain the same as if you did not use +scope+. In the last case, the following paths map to +PostsController+: -- cgit v1.2.3 From f821055dc7bead5ab348f63279cd4321d4d9c3c8 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 21 Nov 2010 02:20:09 +0100 Subject: Do not create table_name_prefix method on isolated module if the method already exists. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/engine.rb | 6 ++++-- railties/test/railties/engine_test.rb | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 62fb781c19..85fa4424c4 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -363,8 +363,10 @@ module Rails _railtie end - define_method(:table_name_prefix) do - "#{name}_" + unless mod.respond_to?(:table_name_prefix) + define_method(:table_name_prefix) do + "#{name}_" + end end end end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 701b6816c8..7548c6318e 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -683,5 +683,24 @@ module RailtiesTest app_generators = Rails.application.config.generators.options[:rails] assert_equal :test_unit , app_generators[:test_framework] end + + test "do not create table_name_prefix method if it already exists" do + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + def self.table_name_prefix + "foo" + end + + class Engine < ::Rails::Engine + isolate_namespace(Bukkits) + end + end + RUBY + + boot_rails + require "#{rails_root}/config/environment" + + assert_equal "foo", Bukkits.table_name_prefix + end end end -- cgit v1.2.3 From 115abd52b6bf6801dce7c3fbcb0e29d4213a5bb2 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 21 Nov 2010 02:47:20 +0100 Subject: Ensure that app generator is not loaded twice to get rid of warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- railties/lib/rails/generators.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 27a4007c20..66c4088a68 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -302,6 +302,7 @@ module Rails $LOAD_PATH.each do |base| Dir[File.join(base, "{rails/generators,generators}", "**", "*_generator.rb")].each do |path| begin + path = path.sub("#{base}/", "") require path rescue Exception => e # No problem -- cgit v1.2.3 From 8c17d30d687b0b9719d6998b1dc8144490132b8d Mon Sep 17 00:00:00 2001 From: "David N. Welton" Date: Mon, 22 Nov 2010 15:09:58 +0100 Subject: Slightly more natural sounding phrase. --- railties/guides/source/generators.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index c0d3116fe4..e0796d2f72 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -201,7 +201,7 @@ config.generators do |g| end -If we generate another resource with the scaffold generator, we can notice that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators. +If we generate another resource with the scaffold generator, we can see that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators. To demonstrate this, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator: -- cgit v1.2.3 From 2515ad8a3e03402c1d5a5f9b46c48a3a9bf75081 Mon Sep 17 00:00:00 2001 From: Pavel Gorbokon Date: Mon, 22 Nov 2010 16:37:33 +0200 Subject: Fix ruby syntax errors in railties/guides docs --- railties/guides/source/active_record_validations_callbacks.textile | 2 +- railties/guides/source/security.textile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 9ce0423244..0824ba450c 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -355,7 +355,7 @@ This helper validates that the specified attributes are not empty. It uses the + class Person < ActiveRecord::Base - validates :name, :presence => true, :login, :email + validates :name, :login, :email, :presence => true end diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile index 6f766430c1..5b24d8c8e3 100644 --- a/railties/guides/source/security.textile +++ b/railties/guides/source/security.textile @@ -550,7 +550,7 @@ Ruby uses a slightly different approach than many other languages to match the e class File < ActiveRecord::Base - validates :name, format => /^[\w\.\-\+]+$/ + validates :name, :format => /^[\w\.\-\+]+$/ end -- cgit v1.2.3 From 0598bd4d2db332e05fb4189169441fb1ad12e9b1 Mon Sep 17 00:00:00 2001 From: "David N. Welton" Date: Mon, 22 Nov 2010 16:05:53 +0100 Subject: Explain that NamedBase makes the variable 'name' available to the script. --- railties/guides/source/generators.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile index e0796d2f72..99c34ed30f 100644 --- a/railties/guides/source/generators.textile +++ b/railties/guides/source/generators.textile @@ -92,7 +92,7 @@ class InitializerGenerator < Rails::Generators::NamedBase end -First, notice that we are inheriting from +Rails::Generators::NamedBase+ instead of +Rails::Generators::Base+. This means that our generator expects at least one argument, which will be the name of the initializer. +First, notice that we are inheriting from +Rails::Generators::NamedBase+ instead of +Rails::Generators::Base+. This means that our generator expects at least one argument, which will be the name of the initializer, and will be available in our code in the variable +name+. We can see that by invoking the description of this new generator (don't forget to delete the old generator file): -- cgit v1.2.3 From 559c4292bcd132e87b50aa8f0807f2684cf234b8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Nov 2010 14:07:28 -0200 Subject: Remove unneeded metaprogramming and method generation in favor of direct definition --- .../lib/action_controller/metal/renderers.rb | 34 +++++++--------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index f9b226b7c9..41bcae75c9 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -15,30 +15,12 @@ module ActionController end module ClassMethods - def _write_render_options - renderers = _renderers.map do |name, value| - <<-RUBY_EVAL - if options.key?(:#{name}) - _process_options(options) - return _render_option_#{name}(options.delete(:#{name}), options) - end - RUBY_EVAL - end - - class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 - def _handle_render_options(options) - #{renderers.join} - end - RUBY_EVAL - end - def use_renderers(*args) new = _renderers.dup args.each do |key| new[key] = RENDERERS[key] end self._renderers = new.freeze - _write_render_options end alias use_renderer use_renderers end @@ -47,11 +29,20 @@ module ActionController _handle_render_options(options) || super end + def _handle_render_options(options) + _renderers.each do |name, value| + if options.key?(name.to_sym) + _process_options(options) + return send("_render_option_#{name}", options.delete(name.to_sym), options) + end + end + nil + end + RENDERERS = {} def self.add(key, &block) define_method("_render_option_#{key}", &block) RENDERERS[key] = block - All._write_render_options end module All @@ -61,13 +52,8 @@ module ActionController INCLUDED = [] included do self._renderers = RENDERERS - _write_render_options INCLUDED << self end - - def self._write_render_options - INCLUDED.each(&:_write_render_options) - end end add :json do |json, options| -- cgit v1.2.3 From 6e559168dc68a32bdbdf87e26ebfcb464be7e886 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Nov 2010 18:47:47 -0200 Subject: There's no need for ternary op here --- actionpack/lib/action_controller/metal/mime_responds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index f7dd0dcb69..6fe1f4ece5 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -291,7 +291,7 @@ module ActionController #:nodoc: alias :all :any def custom(mime_type, &block) - mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s) + mime_type = Mime::Type.lookup(mime_type.to_s) unless mime_type.is_a?(Mime::Type) @order << mime_type @responses[mime_type] ||= block end -- cgit v1.2.3 From c937ddb5cec87168c4eb0d6c3030f771e80c2e72 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Nov 2010 19:00:05 -0200 Subject: Remove unused constant --- actionpack/lib/action_controller/metal/renderers.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 41bcae75c9..67cf08445d 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -49,10 +49,8 @@ module ActionController extend ActiveSupport::Concern include Renderers - INCLUDED = [] included do self._renderers = RENDERERS - INCLUDED << self end end -- cgit v1.2.3 From 61950a4b05ce1b5640ac3f3720f9a3368ce95a29 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 02:21:57 -0500 Subject: current code ignores http header "Accept" if it has ....,*/* . MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible to a device to send request such that */* appear at the beginning of the "Accept" header. This patch ensures that "Accept" header is ignored for such cases too. Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_negotiation.rb | 2 +- actionpack/test/controller/mime_responds_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 5bb42cca3a..afce4d9651 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -48,7 +48,7 @@ module ActionDispatch @env["action_dispatch.request.formats"] ||= if parameters[:format] Array(Mime[parameters[:format]]) - elsif xhr? || (accept && accept !~ /,\s*\*\/\*/) + elsif xhr? || (accept && accept !~ /,\s*\*\/\*|\*\/\*,/) accepts else [Mime::HTML] diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index b6ce9f7d34..c68b3ab13f 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -216,6 +216,12 @@ class RespondToControllerTest < ActionController::TestCase assert_response 406 end + def test_json_or_yaml_with_leading_star_star + @request.accept = "*/*, application/json" + get :json_xml_or_html + assert_equal 'HTML', @response.body + end + def test_json_or_yaml xhr :get, :json_or_yaml assert_equal 'JSON', @response.body -- cgit v1.2.3 From f5fba917f8dbf45fcbf04b4b26cf54eb3b300057 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 08:53:47 -0500 Subject: failing test for #6022 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/controller/mime_responds_test.rb | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index c68b3ab13f..2de9b28e68 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -2,6 +2,14 @@ require 'abstract_unit' require 'controller/fake_models' require 'active_support/core_ext/hash/conversions' +class StarStarMimeController < ActionController::Base + layout nil + + def index + render + end +end + class RespondToController < ActionController::Base layout :set_layout @@ -160,6 +168,32 @@ class RespondToController < ActionController::Base end end +class StarStarMimeControllerTest < ActionController::TestCase + tests StarStarMimeController + + def setup; super; end + def teardown; super; end + + def test_javascript_with_format + @request.accept = "text/javascript" + get :index, :format => 'js' + assert_match "function addition(a,b){ return a+b; }", @response.body + end + + def test_javascript_with_no_format + @request.accept = "text/javascript" + get :index + assert_match "function addition(a,b){ return a+b; }", @response.body + end + + def test_javascript_with_no_format_only_star_star + @request.accept = "*/*" + get :index + assert_match "function addition(a,b){ return a+b; }", @response.body + end + +end + class RespondToControllerTest < ActionController::TestCase tests RespondToController -- cgit v1.2.3 From eb6ccc9953a5e952737174995b5230f0b2c56b1f Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 08:58:01 -0500 Subject: do not assume that there is no space between leading */* and comma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_negotiation.rb | 2 +- actionpack/test/controller/mime_responds_test.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index afce4d9651..2b401114f0 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -48,7 +48,7 @@ module ActionDispatch @env["action_dispatch.request.formats"] ||= if parameters[:format] Array(Mime[parameters[:format]]) - elsif xhr? || (accept && accept !~ /,\s*\*\/\*|\*\/\*,/) + elsif xhr? || (accept && accept !~ /,\s*\*\/\*|\*\/\*\s*,/) accepts else [Mime::HTML] diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 2de9b28e68..7a799411db 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -254,6 +254,10 @@ class RespondToControllerTest < ActionController::TestCase @request.accept = "*/*, application/json" get :json_xml_or_html assert_equal 'HTML', @response.body + + @request.accept = "*/* , application/json" + get :json_xml_or_html + assert_equal 'HTML', @response.body end def test_json_or_yaml -- cgit v1.2.3 From cbb2651cc0e102b8f519acc41035adc32a8cc01b Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 08:58:49 -0500 Subject: add the fixture file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/fixtures/star_star_mime/index.js.erb | 1 + 1 file changed, 1 insertion(+) create mode 100644 actionpack/test/fixtures/star_star_mime/index.js.erb diff --git a/actionpack/test/fixtures/star_star_mime/index.js.erb b/actionpack/test/fixtures/star_star_mime/index.js.erb new file mode 100644 index 0000000000..4da4181f56 --- /dev/null +++ b/actionpack/test/fixtures/star_star_mime/index.js.erb @@ -0,0 +1 @@ +function addition(a,b){ return a+b; } -- cgit v1.2.3 From d04a21b36281a0608cdd72c02e4df3b1136f8887 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 09:07:44 -0500 Subject: declare regex as a constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_negotiation.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 2b401114f0..68ba1a81b5 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -42,13 +42,15 @@ module ActionDispatch formats.first end + BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ + def formats accept = @env['HTTP_ACCEPT'] @env["action_dispatch.request.formats"] ||= if parameters[:format] Array(Mime[parameters[:format]]) - elsif xhr? || (accept && accept !~ /,\s*\*\/\*|\*\/\*\s*,/) + elsif xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) accepts else [Mime::HTML] -- cgit v1.2.3 From b798a59bd582d8590d4fb8df44885d41cd5299f3 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 11:27:26 -0500 Subject: test for text/*, application/* and image/* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/dispatch/mime_type_test.rb | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 4c2b95550c..48755e6b5f 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -6,10 +6,36 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse single" do Mime::LOOKUP.keys.each do |mime_type| - assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type) + unless image_type == 'image/*' + assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type) + end end end + test "parse text with trailing star star" do + accept = "text/*" + expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS + parsed = Mime::Type.parse(accept) + assert_equal 9, parsed.size + assert_equal expect, parsed + end + + test "parse application with trailing star star" do + accept = "application/*" + expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::R + parsed = Mime::Type.parse(accept) + assert_equal 9, parsed.size + assert_equal expect, parsed + end + + test "parse image with trailing star star" do + accept = "image/*" + parsed = Mime::Type.parse(accept) + assert_equal 2, parsed.size + assert parsed.include?(Mime::PNG) + assert_equal 'image/*', parsed[1].instance_variable_get('@string') + end + test "parse without q" do accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*" expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::TEXT, Mime::PDF, Mime::ALL] -- cgit v1.2.3 From 6f6e754bac4c78f657feb0ea119447546aa87197 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 11:34:37 -0500 Subject: implement code that handles text/*, appplication/*, and image/* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_type.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 8f1c9b6691..3b5c1d50f2 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -103,9 +103,14 @@ module Mime ([symbol.to_s] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext] = SET.last } end + def parse(accept_header) if accept_header !~ /,/ - [Mime::Type.lookup(accept_header)] + if result = Regexp.new('(\w+)\/\*').match(accept_header) + parse_data_with_trailing_star(result[1]) + else + [Mime::Type.lookup(accept_header)] + end else # keep track of creation order to keep the subsequent sort stable list = [] @@ -160,6 +165,16 @@ module Mime list end end + + # input: 'text' + # returend value: [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] + # + # input: 'application' + # returend value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM + def parse_data_with_trailing_star(input) + keys = Mime::LOOKUP.keys.select{|k| Regexp.new(input).match(k)} + Mime::LOOKUP.select {|k,_| keys.include?(k)}.collect{|i| i[1]}.inject([]){|all,e| all.include?(e) ? all : all << e} + end end def initialize(string, symbol = nil, synonyms = []) -- cgit v1.2.3 From 4154c659feee47f246a162e2086bf07ad149ec6d Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 11:35:24 -0500 Subject: fix test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/dispatch/mime_type_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 48755e6b5f..bea93adc19 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -6,7 +6,7 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse single" do Mime::LOOKUP.keys.each do |mime_type| - unless image_type == 'image/*' + unless mime_type == 'image/*' assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type) end end @@ -14,7 +14,7 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse text with trailing star star" do accept = "text/*" - expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS + expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] parsed = Mime::Type.parse(accept) assert_equal 9, parsed.size assert_equal expect, parsed @@ -22,7 +22,7 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse application with trailing star star" do accept = "application/*" - expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::R + expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::PDF, Mime::URL_ENCODED_FORM] parsed = Mime::Type.parse(accept) assert_equal 9, parsed.size assert_equal expect, parsed -- cgit v1.2.3 From c9147ebfa06023248b5e738f0928973ddc084da7 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 11:36:36 -0500 Subject: cleanup Mime::LOOKUP after registering image/gif MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/dispatch/mime_type_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index bea93adc19..ab5bbe3a19 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -71,6 +71,7 @@ class MimeTypeTest < ActiveSupport::TestCase end ensure Mime.module_eval { remove_const :GIF if const_defined?(:GIF) } + Mime::LOOKUP.reject!{|key,_| key == 'image/gif'} end end -- cgit v1.2.3 From 23ea19e20d6f7df762635b1c6d83369922d5ad7b Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 11:39:58 -0500 Subject: rename star star to just one star MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/dispatch/mime_type_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index ab5bbe3a19..3a7ab740f4 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -12,7 +12,7 @@ class MimeTypeTest < ActiveSupport::TestCase end end - test "parse text with trailing star star" do + test "parse text with trailing star" do accept = "text/*" expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] parsed = Mime::Type.parse(accept) @@ -20,7 +20,7 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal expect, parsed end - test "parse application with trailing star star" do + test "parse application with trailing star" do accept = "application/*" expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::PDF, Mime::URL_ENCODED_FORM] parsed = Mime::Type.parse(accept) @@ -28,7 +28,7 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal expect, parsed end - test "parse image with trailing star star" do + test "parse image with trailing star" do accept = "image/*" parsed = Mime::Type.parse(accept) assert_equal 2, parsed.size -- cgit v1.2.3 From cdbbf6fd6bef3f286503859c585ada8fe66a3875 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 11:51:43 -0500 Subject: move the mime registration code to setup so that it could be cleaned up on teardown. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the test code test/controller/mime_responds_test.rb impacts test/dispatch/mime_type_test.rb. dispatch/mime_type_test.rb runs independently fine but when run as part of rake breaks because of new mime types registered in controller/mime_responds_test.rb Signed-off-by: José Valim --- actionpack/test/controller/mime_responds_test.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 7a799411db..0da051822a 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -97,7 +97,6 @@ class RespondToController < ActionController::Base end end - Mime::Type.register("text/x-mobile", :mobile) def custom_constant_handling respond_to do |type| @@ -134,7 +133,6 @@ class RespondToController < ActionController::Base end end - Mime::Type.register_alias("text/html", :iphone) def iphone_with_html_response_type request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone" @@ -200,10 +198,16 @@ class RespondToControllerTest < ActionController::TestCase def setup super @request.host = "www.example.com" + Mime::Type.register_alias("text/html", :iphone) + Mime::Type.register("text/x-mobile", :mobile) end def teardown super + Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } + Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } + Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} + Mime::LOOKUP.reject!{|key,_| key == 'text/iphone'} end def test_html @@ -616,6 +620,10 @@ class RespondWithControllerTest < ActionController::TestCase def teardown super + Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } + Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } + Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} + Mime::LOOKUP.reject!{|key,_| key == 'text/iphone'} end def test_using_resource @@ -996,6 +1004,15 @@ class MimeControllerLayoutsTest < ActionController::TestCase def setup super @request.host = "www.example.com" + Mime::Type.register_alias("text/html", :iphone) + end + + def teardown + super + Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } + Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } + Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} + Mime::LOOKUP.reject!{|key,_| key == 'text/iphone'} end def test_missing_layout_renders_properly -- cgit v1.2.3 From 8154f4b816ea1bb2489fba1829ee99cb75fdf696 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 13:32:37 -0500 Subject: Compile regex only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_type.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 3b5c1d50f2..f2ccf1784b 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -80,6 +80,9 @@ module Mime end class << self + + TRAILING_STAR_REGEXP = /(\w+)\/\*/ + def lookup(string) LOOKUP[string] end @@ -103,11 +106,10 @@ module Mime ([symbol.to_s] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext] = SET.last } end - def parse(accept_header) if accept_header !~ /,/ - if result = Regexp.new('(\w+)\/\*').match(accept_header) - parse_data_with_trailing_star(result[1]) + if accept_header =~ TRAILING_STAR_REGEXP + parse_data_with_trailing_star($1) else [Mime::Type.lookup(accept_header)] end -- cgit v1.2.3 From c5bfc6abe4fd160814f09b02afe68d7f4e25e3d6 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 13:38:36 -0500 Subject: string include method is 10x faster than creating a new regex object every single time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_type.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index f2ccf1784b..af7b62b863 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -174,7 +174,7 @@ module Mime # input: 'application' # returend value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM def parse_data_with_trailing_star(input) - keys = Mime::LOOKUP.keys.select{|k| Regexp.new(input).match(k)} + keys = Mime::LOOKUP.keys.select{|k| k.include?(input)} Mime::LOOKUP.select {|k,_| keys.include?(k)}.collect{|i| i[1]}.inject([]){|all,e| all.include?(e) ? all : all << e} end end -- cgit v1.2.3 From 794b34306eea0c7e1e99f5741df16129e8e22b3f Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 13:55:43 -0500 Subject: remove select, collect and then inject with something better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/mime_type.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index af7b62b863..2250cfa88a 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -175,7 +175,7 @@ module Mime # returend value: [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM def parse_data_with_trailing_star(input) keys = Mime::LOOKUP.keys.select{|k| k.include?(input)} - Mime::LOOKUP.select {|k,_| keys.include?(k)}.collect{|i| i[1]}.inject([]){|all,e| all.include?(e) ? all : all << e} + Mime::LOOKUP.values_at(*keys).uniq end end -- cgit v1.2.3 From 21fd93cedda9d96a81b06b96c541120a5da7a71a Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 13:59:46 -0500 Subject: make test more resilient to future changes by not testing the count and not testing the internal value of the registered mime type. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ideally all mime type registration should be cleaned up in teardown. Signed-off-by: José Valim --- actionpack/test/dispatch/mime_type_test.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 3a7ab740f4..28e8d420d5 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -31,9 +31,7 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse image with trailing star" do accept = "image/*" parsed = Mime::Type.parse(accept) - assert_equal 2, parsed.size assert parsed.include?(Mime::PNG) - assert_equal 'image/*', parsed[1].instance_variable_get('@string') end test "parse without q" do -- cgit v1.2.3 From 1c68e55ae5e90b7c072a1f6030ea3dd4becd8a07 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 22 Nov 2010 17:32:15 -0500 Subject: Revert "unscoped takes care of named_scopes too" This reverts commit 126fbd7ed8a310bf940414c1b7ddab06b03d400e. --- activerecord/lib/active_record/base.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index d7a7101404..f588475bbf 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -856,7 +856,8 @@ module ActiveRecord #:nodoc: # limit(10) # Fires "SELECT * FROM posts LIMIT 10" # } # - # Assuming that published is a named_scope following two statements are same. + # It is recommended to use block form of unscoped because chaining unscoped with named_scope + # does not work. Assuming that published is a named_scope following two statements are same. # # Post.unscoped.published # Post.published -- cgit v1.2.3 From 66c09372f3ef3d4ca2b99d44cf1859d585b9dcb3 Mon Sep 17 00:00:00 2001 From: Alex Rothenberg Date: Tue, 23 Nov 2010 06:10:19 +0800 Subject: Removed ids_in_list_limit in favor of in_clause_length defined in database_limits.rb --- activerecord/lib/active_record/association_preload.rb | 4 ++-- .../active_record/connection_adapters/abstract_adapter.rb | 5 ----- activerecord/test/cases/associations/eager_test.rb | 14 +++++++------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 9743b1b4a7..5eb1071ba2 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -391,9 +391,9 @@ module ActiveRecord # Some databases impose a limit on the number of ids in a list (in Oracle its 1000) # Make several smaller queries if necessary or make one query if the adapter supports it def associated_records(ids) - max_ids_in_a_list = connection.ids_in_list_limit || ids.size + in_clause_length = connection.in_clause_length || ids.size records = [] - ids.each_slice(max_ids_in_a_list) do |some_ids| + ids.each_slice(in_clause_length) do |some_ids| records += yield(some_ids) end records diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index ada1560ce2..f3fba9a3a9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -91,11 +91,6 @@ module ActiveRecord false end - # Does this adapter restrict the number of ids you can use in a list. Oracle has a limit of 1000. - def ids_in_list_limit - nil - end - # QUOTING ================================================== # Override to return the quoted table name. Defaults to column quoting. diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index c00b8a1cde..ea86ac29d0 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -80,31 +80,31 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_preloading_has_many_in_multiple_queries_with_more_ids_than_database_can_handle - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + Post.connection.expects(:in_clause_length).at_least_once.returns(5) posts = Post.find(:all, :include=>:comments) assert_equal 7, posts.size end def test_preloading_has_many_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) + Post.connection.expects(:in_clause_length).at_least_once.returns(nil) posts = Post.find(:all, :include=>:comments) assert_equal 7, posts.size end def test_preloading_habtm_in_multiple_queries_with_more_ids_than_database_can_handle - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + Post.connection.expects(:in_clause_length).at_least_once.returns(5) posts = Post.find(:all, :include=>:categories) assert_equal 7, posts.size end def test_preloading_habtm_in_one_queries_when_database_has_no_limit_on_ids_it_can_handle - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) + Post.connection.expects(:in_clause_length).at_least_once.returns(nil) posts = Post.find(:all, :include=>:categories) assert_equal 7, posts.size end def test_load_associated_records_in_one_query_when_adapter_has_no_limit - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(nil) + Post.connection.expects(:in_clause_length).at_least_once.returns(nil) Post.expects(:i_was_called).with([1,2,3,4,5,6,7]).returns([1]) associated_records = Post.send(:associated_records, [1,2,3,4,5,6,7]) do |some_ids| Post.i_was_called(some_ids) @@ -113,7 +113,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_load_associated_records_in_several_queries_when_many_ids_passed - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + Post.connection.expects(:in_clause_length).at_least_once.returns(5) Post.expects(:i_was_called).with([1,2,3,4,5]).returns([1]) Post.expects(:i_was_called).with([6,7]).returns([6]) associated_records = Post.send(:associated_records, [1,2,3,4,5,6,7]) do |some_ids| @@ -123,7 +123,7 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_load_associated_records_in_one_query_when_a_few_ids_passed - Post.connection.expects(:ids_in_list_limit).at_least_once.returns(5) + Post.connection.expects(:in_clause_length).at_least_once.returns(5) Post.expects(:i_was_called).with([1,2,3]).returns([1]) associated_records = Post.send(:associated_records, [1,2,3]) do |some_ids| Post.i_was_called(some_ids) -- cgit v1.2.3 From 5c86286dd6f8b58241492004e1fd872e217aca08 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 21 Nov 2010 13:46:25 +0100 Subject: add respond_to? to ActionDispatch::Integration::Runner since Runner uses method_missing to delegate to the integration session it also should define respond_to? accordingly --- actionpack/lib/action_dispatch/testing/integration.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index fee8cad9f5..e0a17130f8 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -363,6 +363,10 @@ module ActionDispatch integration_session.url_options end + def respond_to?(method, include_private = false) + @integration_session.respond_to?(method, include_private) || super + end + # Delegate unhandled messages to the current session instance. def method_missing(sym, *args, &block) reset! unless integration_session -- cgit v1.2.3 From 4395d493c5df5476e9e31df3336fc81c8a3e5d3c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Nov 2010 15:51:29 -0800 Subject: sort lists before comparing them --- actionpack/test/dispatch/mime_type_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 28e8d420d5..43123e68b2 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -14,18 +14,18 @@ class MimeTypeTest < ActiveSupport::TestCase test "parse text with trailing star" do accept = "text/*" - expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] + expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT].sort_by(&:to_s) parsed = Mime::Type.parse(accept) assert_equal 9, parsed.size - assert_equal expect, parsed + assert_equal expect, parsed.sort_by(&:to_s) end test "parse application with trailing star" do accept = "application/*" - expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::PDF, Mime::URL_ENCODED_FORM] + expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::PDF, Mime::URL_ENCODED_FORM].sort_by(&:to_s) parsed = Mime::Type.parse(accept) assert_equal 9, parsed.size - assert_equal expect, parsed + assert_equal expect, parsed.sort_by(&:to_s) end test "parse image with trailing star" do -- cgit v1.2.3 From e83d15376d7ca10e20a720727f22cc9cdbbd662c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Nov 2010 15:57:03 -0800 Subject: adding a test for the runner module [#6027 state:resolved] --- actionpack/test/controller/runner_test.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 actionpack/test/controller/runner_test.rb diff --git a/actionpack/test/controller/runner_test.rb b/actionpack/test/controller/runner_test.rb new file mode 100644 index 0000000000..24c220dcd5 --- /dev/null +++ b/actionpack/test/controller/runner_test.rb @@ -0,0 +1,22 @@ +require 'abstract_unit' +require 'action_dispatch/testing/integration' + +module ActionDispatch + class RunnerTest < Test::Unit::TestCase + class MyRunner + include Integration::Runner + + def initialize(session) + @integration_session = session + end + + def hi; end + end + + def test_respond_to? + runner = MyRunner.new(Class.new { def x; end }.new) + assert runner.respond_to?(:hi) + assert runner.respond_to?(:x) + end + end +end -- cgit v1.2.3 From 4d31ee1e0e2eccae0c9964214455ff75c647bd7f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Nov 2010 16:14:37 -0800 Subject: removing unused variables --- .../lib/active_record/associations/through_association_scope.rb | 4 ++-- activerecord/test/cases/associations/has_many_associations_test.rb | 3 +-- .../test/cases/associations/has_many_through_associations_test.rb | 1 - activerecord/test/cases/associations/has_one_associations_test.rb | 7 +++---- activerecord/test/cases/associations/inverse_associations_test.rb | 2 -- activerecord/test/cases/associations/join_model_test.rb | 2 +- 6 files changed, 7 insertions(+), 12 deletions(-) diff --git a/activerecord/lib/active_record/associations/through_association_scope.rb b/activerecord/lib/active_record/associations/through_association_scope.rb index bd8e304e99..acddfda924 100644 --- a/activerecord/lib/active_record/associations/through_association_scope.rb +++ b/activerecord/lib/active_record/associations/through_association_scope.rb @@ -16,7 +16,7 @@ module ActiveRecord :readonly => @reflection.options[:readonly] } end - + def construct_create_scope construct_owner_attributes(@reflection) end @@ -51,7 +51,7 @@ module ActiveRecord def construct_select(custom_select = nil) distinct = "DISTINCT " if @reflection.options[:uniq] - selected = custom_select || @reflection.options[:select] || "#{distinct}#{@reflection.quoted_table_name}.*" + custom_select || @reflection.options[:select] || "#{distinct}#{@reflection.quoted_table_name}.*" end def construct_joins(custom_joins = nil) diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 33c53e695b..fb772bb8e6 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -67,8 +67,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_no_sql_should_be_fired_if_association_already_loaded - car = Car.create(:name => 'honda') - bulb = car.bulbs.create + Car.create(:name => 'honda') bulbs = Car.first.bulbs bulbs.inspect # to load all instances of bulbs assert_no_queries do 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 94e1eb8c89..52432b0428 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -354,7 +354,6 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase end def test_has_many_association_through_a_belongs_to_association_where_the_association_doesnt_exist - author = authors(:mary) post = Post.create!(:title => "TITLE", :body => "BODY") assert_equal [], post.author_favorites end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 6fbeff8aa9..64449df8f5 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -163,7 +163,6 @@ class HasOneAssociationsTest < ActiveRecord::TestCase firm = ExclusivelyDependentFirm.find(9) assert_not_nil firm.account - account_id = firm.account.id assert_equal [], Account.destroyed_account_ids[firm.id] firm.destroy @@ -180,7 +179,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_dependence_with_restrict firm = RestrictedFirm.new(:name => 'restrict') firm.save! - account = firm.create_account(:credit_limit => 10) + firm.create_account(:credit_limit => 10) assert_not_nil firm.account assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } end @@ -197,8 +196,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_build_association_twice_without_saving_affects_nothing count_of_account = Account.count firm = Firm.find(:first) - account1 = firm.build_account("credit_limit" => 1000) - account2 = firm.build_account("credit_limit" => 2000) + firm.build_account("credit_limit" => 1000) + firm.build_account("credit_limit" => 2000) assert_equal count_of_account, Account.count end diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 081583038f..0491b2d1fa 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -484,7 +484,6 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase def test_child_instance_should_be_shared_with_replaced_via_accessor_parent face = faces(:confused) - old_man = face.polymorphic_man new_man = Man.new assert_not_nil face.polymorphic_man @@ -499,7 +498,6 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase def test_child_instance_should_be_shared_with_replaced_via_method_parent face = faces(:confused) - old_man = face.polymorphic_man new_man = Man.new assert_not_nil face.polymorphic_man diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 96edcfbb35..1ece961d2e 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -642,7 +642,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_preload_nil_polymorphic_belongs_to assert_nothing_raised do - taggings = Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL']) + Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL']) end end -- cgit v1.2.3 From 4ece7e06fd0009f024fd167107324122c564d551 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Nov 2010 17:06:55 -0800 Subject: removing space error --- activerecord/lib/active_record/associations/belongs_to_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index b624951cd9..b438620c8f 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -61,7 +61,7 @@ module ActiveRecord set_inverse_instance(the_target, @owner) the_target end - + def construct_find_scope { :conditions => conditions } end -- cgit v1.2.3 From dc320d5873e54338a917ced26d849a64001edf28 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Nov 2010 17:23:37 -0800 Subject: skip cloning if arguments are blank --- .../lib/active_record/relation/query_methods.rb | 30 ++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 9e7503a60d..0a4c119849 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -13,7 +13,7 @@ module ActiveRecord def includes(*args) args.reject! {|a| a.blank? } - return clone if args.empty? + return self if args.empty? relation = clone relation.includes_values = (relation.includes_values + args).flatten.uniq @@ -21,14 +21,18 @@ module ActiveRecord end def eager_load(*args) + return self if args.blank? + relation = clone - relation.eager_load_values += args unless args.blank? + relation.eager_load_values += args relation end def preload(*args) + return self if args.blank? + relation = clone - relation.preload_values += args unless args.blank? + relation.preload_values += args relation end @@ -43,22 +47,28 @@ module ActiveRecord end def group(*args) + return self if args.blank? + relation = clone - relation.group_values += args.flatten unless args.blank? + relation.group_values += args.flatten relation end def order(*args) + return self if args.blank? + relation = clone - relation.order_values += args.flatten unless args.blank? + relation.order_values += args.flatten relation end def joins(*args) + return self if args.blank? + relation = clone args.flatten! - relation.joins_values += args unless args.blank? + relation.joins_values += args relation end @@ -70,14 +80,18 @@ module ActiveRecord end def where(opts, *rest) + return self if opts.blank? + relation = clone - relation.where_values += build_where(opts, rest) unless opts.blank? + relation.where_values += build_where(opts, rest) relation end def having(*args) + return self if args.blank? + relation = clone - relation.having_values += build_where(*args) unless args.blank? + relation.having_values += build_where(*args) relation end -- cgit v1.2.3 From 9938a3fc78bf8e066d2cdfe17f3710e0e6b85a36 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 23 Nov 2010 00:32:05 -0200 Subject: Update to Prototype 1.7 [#6042 state:committed] --- .../app/templates/public/javascripts/prototype.js | 733 ++++++++++++--------- 1 file changed, 407 insertions(+), 326 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js b/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js index 06249a6ae3..474b2231bb 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js +++ b/railties/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js @@ -1,4 +1,4 @@ -/* Prototype JavaScript framework, version 1.7_rc2 +/* Prototype JavaScript framework, version 1.7 * (c) 2005-2010 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. @@ -8,7 +8,7 @@ var Prototype = { - Version: '1.7_rc2', + Version: '1.7', Browser: (function(){ var ua = navigator.userAgent; @@ -166,10 +166,12 @@ var Class = (function() { NUMBER_TYPE = 'Number', STRING_TYPE = 'String', OBJECT_TYPE = 'Object', + FUNCTION_CLASS = '[object Function]', BOOLEAN_CLASS = '[object Boolean]', NUMBER_CLASS = '[object Number]', STRING_CLASS = '[object String]', ARRAY_CLASS = '[object Array]', + DATE_CLASS = '[object Date]', NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && typeof JSON.stringify === 'function' && JSON.stringify(0) === '0' && @@ -322,7 +324,7 @@ var Class = (function() { } function isFunction(object) { - return typeof object === "function"; + return _toString.call(object) === FUNCTION_CLASS; } function isString(object) { @@ -333,6 +335,10 @@ var Class = (function() { return _toString.call(object) === NUMBER_CLASS; } + function isDate(object) { + return _toString.call(object) === DATE_CLASS; + } + function isUndefined(object) { return typeof object === "undefined"; } @@ -352,6 +358,7 @@ var Class = (function() { isFunction: isFunction, isString: isString, isNumber: isNumber, + isDate: isDate, isUndefined: isUndefined }); })(); @@ -1079,9 +1086,10 @@ Array.from = $A; slice = arrayProto.slice, _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available - function each(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); + function each(iterator, context) { + for (var i = 0, length = this.length >>> 0; i < length; i++) { + if (i in this) iterator.call(context, this[i], i, this); + } } if (!_each) _each = each; @@ -1287,8 +1295,14 @@ var Hash = Class.create(Enumerable, (function() { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); + if (Object.isArray(values)) { + var queryValues = []; + for (var i = 0, len = values.length, value; i < len; i++) { + value = values[i]; + queryValues.push(toQueryPair(key, value)); + } + return results.concat(queryValues); + } } else results.push(toQueryPair(key, values)); return results; }).join('&'); @@ -1468,9 +1482,7 @@ Ajax.Base = Class.create({ this.options.method = this.options.method.toLowerCase(); - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) + if (Object.isHash(this.options.parameters)) this.options.parameters = this.options.parameters.toObject(); } }); @@ -1486,22 +1498,21 @@ Ajax.Request = Class.create(Ajax.Base, { request: function(url) { this.url = url; this.method = this.options.method; - var params = Object.clone(this.options.parameters); + var params = Object.isString(this.options.parameters) ? + this.options.parameters : + Object.toQueryString(this.options.parameters); if (!['get', 'post'].include(this.method)) { - params['_method'] = this.method; + params += (params ? '&' : '') + "_method=" + this.method; this.method = 'post'; } - this.parameters = params; - - if (params = Object.toQueryString(params)) { - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; + if (params && this.method === 'get') { + this.url += (this.url.include('?') ? '&' : '?') + params; } + this.parameters = params.toQueryParams(); + try { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); @@ -1570,11 +1581,12 @@ Ajax.Request = Class.create(Ajax.Base, { success: function() { var status = this.getStatus(); - return !status || (status >= 200 && status < 300); + return !status || (status >= 200 && status < 300) || status == 304; }, getStatus: function() { try { + if (this.transport.status === 1223) return 204; return this.transport.status || 0; } catch (e) { return 0 } }, @@ -1849,6 +1861,11 @@ if (!Node.ELEMENT_NODE) { (function(global) { + function shouldUseCache(tagName, attributes) { + if (tagName === 'select') return false; + if ('type' in attributes) return false; + return true; + } var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ try { @@ -1866,13 +1883,19 @@ if (!Node.ELEMENT_NODE) { attributes = attributes || { }; tagName = tagName.toLowerCase(); var cache = Element.cache; + if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { tagName = '<' + tagName + ' name="' + attributes.name + '">'; delete attributes.name; return Element.writeAttribute(document.createElement(tagName), attributes); } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + + var node = shouldUseCache(tagName, attributes) ? + cache[tagName].cloneNode(false) : document.createElement(tagName); + + return Element.writeAttribute(node, attributes); }; Object.extend(global.Element, element || { }); @@ -1883,7 +1906,7 @@ if (!Node.ELEMENT_NODE) { Element.idCounter = 1; Element.cache = { }; -function purgeElement(element) { +Element._purgeElement = function(element) { var uid = element._prototypeUID; if (uid) { Element.stopObserving(element); @@ -1948,6 +1971,21 @@ Element.Methods = { } })(); + var LINK_ELEMENT_INNERHTML_BUGGY = (function() { + try { + var el = document.createElement('div'); + el.innerHTML = ""; + var isBuggy = (el.childNodes.length === 0); + el = null; + return isBuggy; + } catch(e) { + return true; + } + })(); + + var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY || + TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY; + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { var s = document.createElement("script"), isBuggy = false; @@ -1962,8 +2000,10 @@ Element.Methods = { return isBuggy; })(); + function update(element, content) { element = $(element); + var purgeElement = Element._purgeElement; var descendants = element.getElementsByTagName('*'), i = descendants.length; @@ -1984,7 +2024,7 @@ Element.Methods = { return element; } - if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { + if (ANY_INNERHTML_BUGGY) { if (tagName in Element._insertionTranslations.tags) { while (element.firstChild) { element.removeChild(element.firstChild); @@ -1993,6 +2033,12 @@ Element.Methods = { .each(function(node) { element.appendChild(node) }); + } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf(' -1) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true); + nodes.each(function(node) { element.appendChild(node) }); } else { element.innerHTML = content.stripScripts(); @@ -2402,117 +2448,6 @@ Element.Methods = { return element; }, - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - if (element.parentNode) { - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - } - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'absolute') return element; - - var offsets = Element.positionedOffset(element), - top = offsets[1], - left = offsets[0], - width = element.clientWidth, - height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'relative') return element; - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0), - left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, - valueL = 0, - element = forElement; - - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, @@ -2566,8 +2501,6 @@ if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': if (!Element.visible(element)) return null; @@ -2603,37 +2536,6 @@ if (Prototype.Browser.Opera) { } else if (Prototype.Browser.IE) { - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - if (!element.parentNode) return $(document.body); - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - if (!element.parentNode) return Element._returnOffset(0, 0); - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); @@ -2862,20 +2764,6 @@ else if (Prototype.Browser.WebKit) { return element; }; - - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; } if ('outerHTML' in document.documentElement) { @@ -2914,11 +2802,20 @@ Element._returnOffset = function(l, t) { return result; }; -Element._getContentFromAnonymousElement = function(tagName, html) { +Element._getContentFromAnonymousElement = function(tagName, html, force) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; + + var workaround = false; + if (t) workaround = true; + else if (force) { + workaround = true; + t = ['', '', 0]; + } + + if (workaround) { + div.innerHTML = ' ' + t[0] + html + t[1]; + div.removeChild(div.firstChild); for (var i = t[2]; i--; ) { div = div.firstChild; } @@ -3077,7 +2974,8 @@ Element.addMethods = function(methods) { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) + "TEXTAREA": Object.clone(Form.Element.Methods), + "BUTTON": Object.clone(Form.Element.Methods) }); } @@ -3264,6 +3162,8 @@ Element.addMethods({ purge: function(element) { if (!(element = $(element))) return; + var purgeElement = Element._purgeElement; + purgeElement(element); var descendants = element.getElementsByTagName('*'), @@ -3283,11 +3183,13 @@ Element.addMethods({ return (Number(match[1]) / 100); } - function getPixelValue(value, property) { + function getPixelValue(value, property, context) { + var element = null; if (Object.isElement(value)) { element = value; value = element.getStyle(property); } + if (value === null) { return null; } @@ -3296,7 +3198,9 @@ Element.addMethods({ return window.parseFloat(value); } - if (/\d/.test(value) && element.runtimeStyle) { + var isPercentage = value.include('%'), isViewport = (context === document.viewport); + + if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) { var style = element.style.left, rStyle = element.runtimeStyle.left; element.runtimeStyle.left = element.currentStyle.left; element.style.left = value || 0; @@ -3307,18 +3211,33 @@ Element.addMethods({ return value; } - if (value.include('%')) { + if (element && isPercentage) { + context = context || element.parentNode; var decimal = toDecimal(value); - var whole; - if (property.include('left') || property.include('right') || - property.include('width')) { - whole = $(element.parentNode).measure('width'); - } else if (property.include('top') || property.include('bottom') || - property.include('height')) { - whole = $(element.parentNode).measure('height'); + var whole = null; + var position = element.getStyle('position'); + + var isHorizontal = property.include('left') || property.include('right') || + property.include('width'); + + var isVertical = property.include('top') || property.include('bottom') || + property.include('height'); + + if (context === document.viewport) { + if (isHorizontal) { + whole = document.viewport.getWidth(); + } else if (isVertical) { + whole = document.viewport.getHeight(); + } + } else { + if (isHorizontal) { + whole = $(context).measure('width'); + } else if (isVertical) { + whole = $(context).measure('height'); + } } - return whole * decimal; + return (whole === null) ? 0 : whole * decimal; } return 0; @@ -3410,6 +3329,14 @@ Element.addMethods({ var position = element.getStyle('position'), width = element.getStyle('width'); + if (width === "0px" || width === null) { + element.style.display = 'block'; + width = element.getStyle('width'); + } + + var context = (position === 'fixed') ? document.viewport : + element.parentNode; + element.setStyle({ position: 'absolute', visibility: 'hidden', @@ -3420,9 +3347,9 @@ Element.addMethods({ var newWidth; if (width && (positionedWidth === width)) { - newWidth = getPixelValue(width); - } else if (width && (position === 'absolute' || position === 'fixed')) { - newWidth = getPixelValue(width); + newWidth = getPixelValue(element, 'width', context); + } else if (position === 'absolute' || position === 'fixed') { + newWidth = getPixelValue(element, 'width', context); } else { var parent = element.parentNode, pLayout = $(parent).getLayout(); @@ -3453,6 +3380,7 @@ Element.addMethods({ if (!(property in COMPUTATIONS)) { throw "Property not found."; } + return this._set(property, COMPUTATIONS[property].call(this, this.element)); }, @@ -3505,7 +3433,10 @@ Element.addMethods({ if (!this._preComputing) this._begin(); var bHeight = this.get('border-box-height'); - if (bHeight <= 0) return 0; + if (bHeight <= 0) { + if (!this._preComputing) this._end(); + return 0; + } var bTop = this.get('border-top'), bBottom = this.get('border-bottom'); @@ -3522,7 +3453,10 @@ Element.addMethods({ if (!this._preComputing) this._begin(); var bWidth = this.get('border-box-width'); - if (bWidth <= 0) return 0; + if (bWidth <= 0) { + if (!this._preComputing) this._end(); + return 0; + } var bLeft = this.get('border-left'), bRight = this.get('border-right'); @@ -3552,11 +3486,17 @@ Element.addMethods({ }, 'border-box-height': function(element) { - return element.offsetHeight; + if (!this._preComputing) this._begin(); + var height = element.offsetHeight; + if (!this._preComputing) this._end(); + return height; }, 'border-box-width': function(element) { - return element.offsetWidth; + if (!this._preComputing) this._begin(); + var width = element.offsetWidth; + if (!this._preComputing) this._end(); + return width; }, 'margin-box-height': function(element) { @@ -3626,23 +3566,19 @@ Element.addMethods({ }, 'border-top': function(element) { - return Object.isNumber(element.clientTop) ? element.clientTop : - getPixelValue(element, 'borderTopWidth'); + return getPixelValue(element, 'borderTopWidth'); }, 'border-bottom': function(element) { - return Object.isNumber(element.clientBottom) ? element.clientBottom : - getPixelValue(element, 'borderBottomWidth'); + return getPixelValue(element, 'borderBottomWidth'); }, 'border-left': function(element) { - return Object.isNumber(element.clientLeft) ? element.clientLeft : - getPixelValue(element, 'borderLeftWidth'); + return getPixelValue(element, 'borderLeftWidth'); }, 'border-right': function(element) { - return Object.isNumber(element.clientRight) ? element.clientRight : - getPixelValue(element, 'borderRightWidth'); + return getPixelValue(element, 'borderRightWidth'); }, 'margin-top': function(element) { @@ -3721,23 +3657,52 @@ Element.addMethods({ } function getDimensions(element) { - var layout = $(element).getLayout(); - return { - width: layout.get('width'), - height: layout.get('height') + element = $(element); + var display = Element.getStyle(element, 'display'); + + if (display && display !== 'none') { + return { width: element.offsetWidth, height: element.offsetHeight }; + } + + var style = element.style; + var originalStyles = { + visibility: style.visibility, + position: style.position, + display: style.display + }; + + var newStyles = { + visibility: 'hidden', + display: 'block' }; + + if (originalStyles.position !== 'fixed') + newStyles.position = 'absolute'; + + Element.setStyle(element, newStyles); + + var dimensions = { + width: element.offsetWidth, + height: element.offsetHeight + }; + + Element.setStyle(element, originalStyles); + + return dimensions; } function getOffsetParent(element) { - if (isDetached(element)) return $(document.body); + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); var isInline = (Element.getStyle(element, 'display') === 'inline'); if (!isInline && element.offsetParent) return $(element.offsetParent); - if (element === document.body) return $(element); while ((element = element.parentNode) && element !== document.body) { if (Element.getStyle(element, 'position') !== 'static') { - return (element.nodeName === 'HTML') ? $(document.body) : $(element); + return isHtml(element) ? $(document.body) : $(element); } } @@ -3746,16 +3711,21 @@ Element.addMethods({ function cumulativeOffset(element) { + element = $(element); var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); + if (element.parentNode) { + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + } return new Element.Offset(valueL, valueT); } function positionedOffset(element) { + element = $(element); + var layout = element.getLayout(); var valueT = 0, valueL = 0; @@ -3787,6 +3757,7 @@ Element.addMethods({ } function viewportOffset(forElement) { + element = $(element); var valueT = 0, valueL = 0, docBody = document.body; var element = forElement; @@ -3852,6 +3823,57 @@ Element.addMethods({ return element; } + if (Prototype.Browser.IE) { + getOffsetParent = getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + positionedOffset = positionedOffset.wrap(function(proceed, element) { + element = $(element); + if (!element.parentNode) return new Element.Offset(0, 0); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + hasLayout(offsetParent); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + }); + } else if (Prototype.Browser.Webkit) { + cumulativeOffset = function(element) { + element = $(element); + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return new Element.Offset(valueL, valueT); + }; + } + + Element.addMethods({ getLayout: getLayout, measure: measure, @@ -3869,6 +3891,14 @@ Element.addMethods({ return element.nodeName.toUpperCase() === 'BODY'; } + function isHtml(element) { + return element.nodeName.toUpperCase() === 'HTML'; + } + + function isDocument(element) { + return element.nodeType === Node.DOCUMENT_NODE; + } + function isDetached(element) { return element !== document.body && !Element.descendantOf(element, document.body); @@ -3880,32 +3910,10 @@ Element.addMethods({ element = $(element); if (isDetached(element)) return new Element.Offset(0, 0); - var rect = element.getBoundingClientRect(), + var rect = element.getBoundingClientRect(), docEl = document.documentElement; return new Element.Offset(rect.left - docEl.clientLeft, rect.top - docEl.clientTop); - }, - - positionedOffset: function(element) { - element = $(element); - var parent = element.getOffsetParent(); - if (isDetached(element)) return new Element.Offset(0, 0); - - if (element.offsetParent && - element.offsetParent.nodeName.toUpperCase() === 'HTML') { - return positionedOffset(element); - } - - var eOffset = element.viewportOffset(), - pOffset = isBody(parent) ? viewportOffset(parent) : - parent.viewportOffset(); - var retOffset = eOffset.relativeTo(pOffset); - - var layout = element.getLayout(); - var top = retOffset.top - layout.get('margin-top'); - var left = retOffset.left - layout.get('margin-left'); - - return new Element.Offset(left, top); } }); } @@ -4962,24 +4970,34 @@ var Form = { serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; + var key, value, submitted = false, submit = options.submit, accumulator, initial; + + if (options.hash) { + initial = {}; + accumulator = function(result, key, value) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } else result[key] = value; + return result; + }; + } else { + initial = ''; + accumulator = function(result, key, value) { + return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value); + } + } - var data = elements.inject({ }, function(result, element) { + return elements.inject(initial, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; + result = accumulator(result, key, value); } } return result; }); - - return options.hash ? data : Object.toQueryString(data); } }; @@ -5046,7 +5064,8 @@ Form.Methods = { focusFirstElement: function(form) { form = $(form); - form.findFirstElement().activate(); + var element = form.findFirstElement(); + if (element) element.activate(); return form; }, @@ -5153,67 +5172,77 @@ var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ -Form.Element.Serializers = { - input: function(element, value) { +Form.Element.Serializers = (function() { + function input(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': - return Form.Element.Serializers.inputSelector(element, value); + return inputSelector(element, value); default: - return Form.Element.Serializers.textarea(element, value); + return valueSelector(element, value); } - }, + } - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; + function inputSelector(element, value) { + if (Object.isUndefined(value)) + return element.checked ? element.value : null; else element.checked = !!value; - }, + } - textarea: function(element, value) { + function valueSelector(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; - }, + } - select: function(element, value) { + function select(element, value) { if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } + return (element.type === 'select-one' ? selectOne : selectMany)(element); + + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; } - else opt.selected = value.include(currentValue); } + else opt.selected = value.include(currentValue); } - }, + } - selectOne: function(element) { + function selectOne(element) { var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, + return index >= 0 ? optionValue(element.options[index]) : null; + } - selectMany: function(element) { + function selectMany(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); + if (opt.selected) values.push(optionValue(opt)); } return values; - }, + } - optionValue: function(opt) { - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + function optionValue(opt) { + return Element.hasAttribute(opt, 'value') ? opt.value : opt.text; } -}; + + return { + input: input, + inputSelector: inputSelector, + textarea: valueSelector, + select: select, + selectOne: selectOne, + selectMany: selectMany, + optionValue: optionValue, + button: valueSelector + }; +})(); /*--------------------------------------------------------------------------*/ @@ -5324,24 +5353,53 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl && 'onmouseleave' in docEl; + + + var isIELegacyEvent = function(event) { return false; }; + + if (window.attachEvent) { + if (window.addEventListener) { + isIELegacyEvent = function(event) { + return !(event instanceof window.Event); + }; + } else { + isIELegacyEvent = function(event) { return true; }; + } + } + var _isButton; - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - _isButton = function(event, code) { - return event.button === buttonMap[code]; - }; - } else if (Prototype.Browser.WebKit) { - _isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; + + function _isButtonForDOMEvents(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + } + + var legacyButtonMap = { 0: 1, 1: 4, 2: 2 }; + function _isButtonForLegacyEvents(event, code) { + return event.button === legacyButtonMap[code]; + } + + function _isButtonForWebKit(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 2 || (event.which == 1 && event.metaKey); + case 2: return event.which == 3; + default: return false; + } + } + + if (window.attachEvent) { + if (!window.addEventListener) { + _isButton = _isButtonForLegacyEvents; + } else { + _isButton = function(event, code) { + return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) : + _isButtonForDOMEvents(event, code); } - }; + } + } else if (Prototype.Browser.WebKit) { + _isButton = _isButtonForWebKit; } else { - _isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; + _isButton = _isButtonForDOMEvents; } function isLeftClick(event) { return _isButton(event, 0) } @@ -5371,6 +5429,7 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { function findElement(event, expression) { var element = Event.element(event); + if (!expression) return element; while (element) { if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { @@ -5411,49 +5470,59 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { event.stopped = true; } + Event.Methods = { - isLeftClick: isLeftClick, + isLeftClick: isLeftClick, isMiddleClick: isMiddleClick, - isRightClick: isRightClick, + isRightClick: isRightClick, - element: element, + element: element, findElement: findElement, - pointer: pointer, + pointer: pointer, pointerX: pointerX, pointerY: pointerY, stop: stop }; - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); - if (Prototype.Browser.IE) { + if (window.attachEvent) { function _relatedTarget(event) { var element; switch (event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; + case 'mouseover': + case 'mouseenter': + element = event.fromElement; + break; + case 'mouseout': + case 'mouseleave': + element = event.toElement; + break; + default: + return null; } return Element.extend(element); } - Object.extend(methods, { + var additionalMethods = { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return '[object Event]' } - }); + }; Event.extend = function(event, element) { if (!event) return false; - if (event._extendedByPrototype) return event; + if (!isIELegacyEvent(event)) return event; + + if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); Object.extend(event, { @@ -5463,12 +5532,18 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { pageY: pointer.y }); - return Object.extend(event, methods); + Object.extend(event, methods); + Object.extend(event, additionalMethods); + + return event; }; } else { + Event.extend = Prototype.K; + } + + if (window.addEventListener) { Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; Object.extend(Event.prototype, methods); - Event.extend = Prototype.K; } function _createResponder(element, eventName, handler) { @@ -5567,7 +5642,7 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { element.addEventListener("dataavailable", responder, false); else { element.attachEvent("ondataavailable", responder); - element.attachEvent("onfilterchange", responder); + element.attachEvent("onlosecapture", responder); } } else { var actualEventName = _getDOMEventName(eventName); @@ -5605,7 +5680,13 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { return element; } - var responder = responders.find( function(r) { return r.handler === handler; }); + var i = responders.length, responder; + while (i--) { + if (responders[i].handler === handler) { + responder = responders[i]; + break; + } + } if (!responder) return element; if (eventName.include(':')) { @@ -5613,7 +5694,7 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { element.removeEventListener("dataavailable", responder, false); else { element.detachEvent("ondataavailable", responder); - element.detachEvent("onfilterchange", responder); + element.detachEvent("onlosecapture", responder); } } else { var actualEventName = _getDOMEventName(eventName); @@ -5640,10 +5721,10 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { var event; if (document.createEvent) { event = document.createEvent('HTMLEvents'); - event.initEvent('dataavailable', true, true); + event.initEvent('dataavailable', bubble, true); } else { event = document.createEventObject(); - event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; + event.eventType = bubble ? 'ondataavailable' : 'onlosecapture'; } event.eventName = eventName; @@ -5677,7 +5758,7 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { }, handleEvent: function(event) { - var element = event.findElement(this.selector); + var element = Event.findElement(event, this.selector); if (element) this.callback.call(this.element, event, element); } }); -- cgit v1.2.3 From de829f871becc87424d75a5050883a02435c01e4 Mon Sep 17 00:00:00 2001 From: Ray Baxter Date: Mon, 22 Nov 2010 22:11:56 -0800 Subject: fix typo --- activerecord/lib/active_record/autosave_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index cb5bc06580..73ac8e82c6 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -89,7 +89,7 @@ module ActiveRecord # post = Post.create(:title => 'ruby rocks') # post.comments.create(:body => 'hello world') # post.comments[0].body = 'hi everyone' - # post.save # => saves both post and comment, with 'hi everyone' as title + # post.save # => saves both post and comment, with 'hi everyone' as body # # Destroying one of the associated models as part of the parent's save action # is as simple as marking it for destruction: -- cgit v1.2.3 From 2fe43b694f36ddb2062a91eebe61a035147265b1 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 23 Nov 2010 00:31:03 +0100 Subject: :subdomain, :domain and :tld_length options can now be used in url_for, allowing for easy manipulation of the host during link generation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_controller/metal/url_for.rb | 4 +- actionpack/lib/action_dispatch/http/url.rb | 59 ++++++++++++++-------- .../lib/action_dispatch/routing/route_set.rb | 38 +++++++++++--- actionpack/lib/action_dispatch/routing/url_for.rb | 6 +++ actionpack/test/controller/url_for_test.rb | 23 ++++++++- actionpack/test/dispatch/request_test.rb | 6 +-- 6 files changed, 105 insertions(+), 31 deletions(-) diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 333eeaeffb..6fc0cf1fb8 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -6,7 +6,8 @@ module ActionController def url_options @_url_options ||= super.reverse_merge( - :host => request.host_with_port, + :host => request.host, + :port => request.optional_port, :protocol => request.protocol, :_path_segments => request.symbolized_path_parameters ).freeze @@ -20,5 +21,6 @@ module ActionController @_url_options end end + end end diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 9c9eed2c6d..1f7633cbea 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -4,6 +4,27 @@ module ActionDispatch mattr_accessor :tld_length self.tld_length = 1 + def self.extract_domain(host, tld_length = @@tld_length) + return nil unless named_host?(host) + + host.split('.').last(1 + tld_length).join('.') + end + + def self.extract_subdomains(host, tld_length = @@tld_length) + return [] unless named_host?(host) + parts = host.split('.') + parts[0..-(tld_length+2)] + end + + def self.extract_subdomain(host, tld_length = @@tld_length) + extract_subdomains(host, tld_length).join('.') + end + + def self.named_host?(host) + !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) + end + + # Returns the complete URL used for this request. def url protocol + host_with_port + fullpath @@ -31,15 +52,18 @@ module ActionDispatch # Returns a \host:\port string for this request, such as "example.com" or # "example.com:8080". def host_with_port - "#{host}#{port_string}" + opt_port = optional_port ? ":#{optional_port}" : nil + "#{host}#{opt_port}" end # Returns the port number of this request as an integer. def port - if raw_host_with_port =~ /:(\d+)$/ - $1.to_i - else - standard_port + @port ||= begin + if raw_host_with_port =~ /:(\d+)$/ + $1.to_i + else + standard_port + end end end @@ -56,10 +80,10 @@ module ActionDispatch port == standard_port end - # Returns a \port suffix like ":8080" if the \port number of this request + # Returns a \port suffix like "8080" if the \port number of this request # is not the default HTTP \port 80 or HTTPS \port 443. - def port_string - port == standard_port ? '' : ":#{port}" + def optional_port + standard_port? ? nil : port end def server_port @@ -69,9 +93,7 @@ module ActionDispatch # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify # a different tld_length, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk". def domain(tld_length = @@tld_length) - return nil unless named_host?(host) - - host.split('.').last(1 + tld_length).join('.') + ActionDispatch::Http::URL.extract_domain(host, tld_length) end # Returns all the \subdomains as an array, so ["dev", "www"] would be @@ -79,20 +101,17 @@ module ActionDispatch # such as 2 to catch ["www"] instead of ["www", "rubyonrails"] # in "www.rubyonrails.co.uk". def subdomains(tld_length = @@tld_length) - return [] unless named_host?(host) - parts = host.split('.') - parts[0..-(tld_length+2)] + ActionDispatch::Http::URL.extract_subdomains(host, tld_length) end + # Returns all the \subdomains as a string, so "dev.www" would be + # returned for "dev.www.rubyonrails.org". You can specify a different tld_length, + # such as 2 to catch ["www"] instead of "www.rubyonrails" + # in "www.rubyonrails.co.uk". def subdomain(tld_length = @@tld_length) - subdomains(tld_length).join('.') + subdomains(tld_length) end - private - - def named_host?(host) - !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) - end end end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 32f41934f1..d823fd710e 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -485,7 +485,8 @@ module ActionDispatch Generator.new(options, recall, self, extras).generate end - RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash, :script_name] + RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length, + :trailing_slash, :script_name, :anchor, :params, :only_path ] def _generate_prefix(options = {}) nil @@ -504,11 +505,8 @@ module ActionDispatch rewritten_url << (options[:protocol] || "http") rewritten_url << "://" unless rewritten_url.match("://") rewritten_url << rewrite_authentication(options) - - raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host] - - rewritten_url << options[:host] - rewritten_url << ":#{options.delete(:port)}" if options.key?(:port) + rewritten_url << host_from_options(options) + rewritten_url << ":#{options.delete(:port)}" if options[:port] end script_name = options.delete(:script_name) @@ -562,6 +560,34 @@ module ActionDispatch end private + + def host_from_options(options) + computed_host = subdomain_and_domain(options) || options[:host] + unless computed_host + raise ArgumentError, "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" + end + computed_host + end + + def subdomain_and_domain(options) + tld_length = options[:tld_length] || ActionDispatch::Http::URL.tld_length + + current_domain = ActionDispatch::Http::URL.extract_domain(options[:host], tld_length) + current_subdomain = ActionDispatch::Http::URL.extract_subdomain(options[:host], tld_length) + + domain_parts = if options[:subdomain] && options[:domain] + [options[:subdomain], options[:domain]] + elsif options[:subdomain] + [options[:subdomain], current_domain] + elsif options[:domain] + [current_subdomain, options[:domain]] + else + nil + end + + domain_parts ? domain_parts.join('.') : nil + end + def handle_positional_args(options) return unless args = options.delete(:_positional_args) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index bfdea41f60..6c3fc5126a 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -115,6 +115,12 @@ module ActionDispatch # * :host - Specifies the host the link should be targeted at. # If :only_path is false, this option must be # provided either explicitly, or via +default_url_options+. + # * :subdomain - Specifies the subdomain of the link, using the +tld_length+ + # to split the domain from the host. + # * :domain - Specifies the domain of the link, using the +tld_length+ + # to split the subdomain from the host. + # * :tld_length - Optionally specify the tld length (only used if :subdomain + # or :domain are supplied). # * :port - Optionally specify the port to connect to. # * :anchor - An anchor name to be appended to the path. # * :trailing_slash - If true, adds a trailing slash, as in "/archive/2009/" diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index 4c07ca4cc3..1f62d29e80 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -17,7 +17,7 @@ module AbstractController end def test_exception_is_thrown_without_host - assert_raise RuntimeError do + assert_raise ArgumentError do W.new.url_for :controller => 'c', :action => 'a', :id => 'i' end end @@ -60,6 +60,27 @@ module AbstractController ) end + def test_subdomain_may_be_changed + add_host! + assert_equal('http://api.basecamphq.com/c/a/i', + W.new.url_for(:subdomain => 'api', :controller => 'c', :action => 'a', :id => 'i') + ) + end + + def test_domain_may_be_changed + add_host! + assert_equal('http://www.37signals.com/c/a/i', + W.new.url_for(:domain => '37signals.com', :controller => 'c', :action => 'a', :id => 'i') + ) + end + + def test_tld_length_may_be_changed + add_host! + assert_equal('http://mobile.www.basecamphq.com/c/a/i', + W.new.url_for(:subdomain => 'mobile', :tld_length => 2, :controller => 'c', :action => 'a', :id => 'i') + ) + end + def test_port add_host! assert_equal('http://www.basecamphq.com:3000/c/a/i', diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 4764a8c2a8..d140ea8358 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -164,12 +164,12 @@ class RequestTest < ActiveSupport::TestCase assert !request.standard_port? end - test "port string" do + test "optional port" do request = stub_request 'HTTP_HOST' => 'www.example.org:80' - assert_equal "", request.port_string + assert_equal nil, request.optional_port request = stub_request 'HTTP_HOST' => 'www.example.org:8080' - assert_equal ":8080", request.port_string + assert_equal 8080, request.optional_port end test "full path" do -- cgit v1.2.3 From 56b12140246303440da18c0c5ea139b3b17b0282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 23 Nov 2010 10:05:47 +0100 Subject: Speed up subdomain and domain calculus. --- actionpack/lib/action_dispatch/routing/route_set.rb | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index d823fd710e..ebced9cabe 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -570,22 +570,14 @@ module ActionDispatch end def subdomain_and_domain(options) + return nil unless options[:subdomain] || options[:domain] tld_length = options[:tld_length] || ActionDispatch::Http::URL.tld_length - current_domain = ActionDispatch::Http::URL.extract_domain(options[:host], tld_length) - current_subdomain = ActionDispatch::Http::URL.extract_subdomain(options[:host], tld_length) - - domain_parts = if options[:subdomain] && options[:domain] - [options[:subdomain], options[:domain]] - elsif options[:subdomain] - [options[:subdomain], current_domain] - elsif options[:domain] - [current_subdomain, options[:domain]] - else - nil - end - - domain_parts ? domain_parts.join('.') : nil + host = "" + host << (options[:subdomain] || ActionDispatch::Http::URL.extract_subdomain(options[:host], tld_length)) + host << "." + host << (options[:domain] || ActionDispatch::Http::URL.extract_domain(options[:host], tld_length)) + host end def handle_positional_args(options) -- cgit v1.2.3 From da583df50c32d50261b682664fe43fd5e2f58f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 23 Nov 2010 10:09:24 +0100 Subject: Remove bazillion warnings from AP suite. --- actionpack/lib/action_dispatch/testing/integration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index e0a17130f8..8fe74c3c80 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -364,7 +364,7 @@ module ActionDispatch end def respond_to?(method, include_private = false) - @integration_session.respond_to?(method, include_private) || super + integration_session.respond_to?(method, include_private) || super end # Delegate unhandled messages to the current session instance. -- cgit v1.2.3 From fd64bba648762cfa6ffb603e0298502be873aa6f Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Tue, 23 Nov 2010 17:53:59 +0100 Subject: i18n guide: fix RedCloth artifacts that were rendering bad format and broken links on 2.3 warnings --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 1a83b84004..25c24ac7d7 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -127,7 +127,7 @@ If you want to translate your Rails application to a *single language other than However, you would probably like to *provide support for more locales* in your application. In such case, you need to set and pass the locale between requests. -WARNING: You may be tempted to store the chosen locale in a _session_ or a _cookie_. *Do not do so*. The locale should be transparent and a part of the URL. This way you don't break people's basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you're being "_RESTful_":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. There may be some exceptions to this rule, which are discussed below. +WARNING: You may be tempted to store the chosen locale in a _session_ or a cookie. *Do not do so*. The locale should be transparent and a part of the URL. This way you don't break people's basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you're being "RESTful":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. There may be some exceptions to this rule, which are discussed below. The _setting part_ is easy. You can set the locale in a +before_filter+ in the +ApplicationController+ like this: -- cgit v1.2.3 From 14055ea28285107af04ed0ce4ef0ec542a9a9530 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 20 Nov 2010 07:38:08 +0800 Subject: No need to define a local var here. --- activerecord/lib/active_record/base.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index aa028c6f36..f9743b4fea 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1569,8 +1569,7 @@ MSG # Returns true if the specified +attribute+ has been set by the user or by a database load and is neither # nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings). def attribute_present?(attribute) - value = read_attribute(attribute) - !value.blank? + !read_attribute(attribute).blank? end # Returns the column object for the named attribute. -- cgit v1.2.3 From a9e963d51d262a0693f0b83508c40a250421f826 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 20 Nov 2010 07:38:58 +0800 Subject: Remove confusing parenthesis. --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index f9743b4fea..18d30d2540 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1595,7 +1595,7 @@ MSG # Delegates to == def eql?(comparison_object) - self == (comparison_object) + self == comparison_object end # Delegates to id in order to allow two records of the same type and id to work with something like: -- cgit v1.2.3 From 9c161599ac1e37eedd56bece4d975dde8cdaa151 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 20 Nov 2010 07:46:56 +0800 Subject: Remove uneeded local var definition. --- activerecord/lib/active_record/nested_attributes.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index f1d3eaed38..a2101a02eb 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -322,9 +322,8 @@ module ActiveRecord def assign_nested_attributes_for_one_to_one_association(association_name, attributes) options = self.nested_attributes_options[association_name] attributes = attributes.with_indifferent_access - check_existing_record = (options[:update_only] || !attributes['id'].blank?) - if check_existing_record && (record = send(association_name)) && + if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) && (options[:update_only] || record.id.to_s == attributes['id'].to_s) assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) -- cgit v1.2.3 From 861cdc4c59dabdc8cca42a9f29b7cccb3cd23505 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 20 Nov 2010 07:48:49 +0800 Subject: Remove unneeded local var. --- activerecord/lib/active_record/nested_attributes.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index a2101a02eb..15f83a8579 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -446,8 +446,7 @@ module ActiveRecord end def raise_nested_attributes_record_not_found(association_name, record_id) - reflection = self.class.reflect_on_association(association_name) - raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}" + raise RecordNotFound, "Couldn't find #{self.class.reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}" end end end -- cgit v1.2.3 From b8df3a9197252ec62f390ef1f8cd0e0e827c6252 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 21 Nov 2010 00:41:39 +0800 Subject: Use params default. --- activerecord/lib/active_record/connection_adapters/abstract_adapter.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index f3fba9a3a9..0282493219 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -204,8 +204,7 @@ module ActiveRecord protected - def log(sql, name) - name ||= "SQL" + def log(sql, name = "SQL") @instrumenter.instrument("sql.active_record", :sql => sql, :name => name, :connection_id => object_id) do yield -- cgit v1.2.3 From 1b531b7ee2054beadb23853d79b15d588b9ffd88 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 21 Nov 2010 00:35:11 +0800 Subject: Remove explicit return. --- activerecord/lib/active_record/associations/has_many_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 830a82980d..a682ec52d8 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -46,7 +46,7 @@ module ActiveRecord count = [ @reflection.options[:limit], count ].min end - return count + count end def has_cached_counter? -- cgit v1.2.3 From 63c9185b62076f416c63b472a356bf9faac143db Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 21 Nov 2010 00:38:35 +0800 Subject: Remove explicit return and avoid creating local var. --- activerecord/lib/active_record/associations/has_many_association.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index a682ec52d8..6423536fb9 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -112,8 +112,7 @@ module ActiveRecord end def we_can_set_the_inverse_on_this?(record) - inverse = @reflection.inverse_of - return !inverse.nil? + !@reflection.inverse_of.nil? end end end -- cgit v1.2.3 From 6ffe0ef55bbabf59a533402a6420942c7397e441 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 21 Nov 2010 00:43:28 +0800 Subject: Avoid creating local var. --- activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 5ca1923d89..c2cd9e8d5e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -40,8 +40,7 @@ module ActiveRecord if @connection.respond_to?(:encoding) @connection.encoding.to_s else - encoding = @connection.execute('PRAGMA encoding') - encoding[0]['encoding'] + @connection.execute('PRAGMA encoding')[0]['encoding'] end end -- cgit v1.2.3 From d29d793c9096a732274298cdba07c654e9128484 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 21 Nov 2010 00:51:01 +0800 Subject: Don't create local vars. --- activerecord/lib/active_record/locking/optimistic.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index bf626301f1..9e1a33a6bf 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -110,12 +110,9 @@ module ActiveRecord return super unless locking_enabled? if persisted? - lock_col = self.class.locking_column - previous_value = send(lock_col).to_i - table = self.class.arel_table predicate = table[self.class.primary_key].eq(id) - predicate = predicate.and(table[self.class.locking_column].eq(previous_value)) + predicate = predicate.and(table[self.class.locking_column].eq(send(self.class.locking_column).to_i)) affected_rows = self.class.unscoped.where(predicate).delete_all -- cgit v1.2.3 From e2bad8a2e7e020901ddb74c3404a1c339b5a99f9 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 21 Nov 2010 00:46:28 +0800 Subject: No need to create a variables to use them once. --- activerecord/lib/active_record/validations/uniqueness.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 3eba7510ac..853808eebf 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -14,17 +14,14 @@ module ActiveRecord def validate_each(record, attribute, value) finder_class = find_finder_class_for(record) - table = finder_class.unscoped - - table_name = record.class.quoted_table_name if value && record.class.serialized_attributes.key?(attribute.to_s) value = YAML.dump value end - sql, params = mount_sql_and_params(finder_class, table_name, attribute, value) + sql, params = mount_sql_and_params(finder_class, record.class.quoted_table_name, attribute, value) - relation = table.where(sql, *params) + relation = finder_class.unscoped.where(sql, *params) Array.wrap(options[:scope]).each do |scope_item| scope_value = record.send(scope_item) -- cgit v1.2.3 From 9f35799221c8a3c06b3f34a38525654b59598cfd Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 20 Nov 2010 13:37:54 -0300 Subject: Refactor && simplify count_records. --- activerecord/lib/active_record/associations/has_many_association.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 6423536fb9..23831e0b08 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -42,11 +42,7 @@ module ActiveRecord # documented side-effect of the method that may avoid an extra SELECT. @target ||= [] and loaded if count == 0 - if @reflection.options[:limit] - count = [ @reflection.options[:limit], count ].min - end - - count + @reflection.options[:limit] ? [@reflection.options[:limit], count].min : count end def has_cached_counter? -- cgit v1.2.3 From 0250c3eca40f5f2b3da698b11ff4f01f58db5a69 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 23 Nov 2010 22:51:51 +0100 Subject: copy-edits RDoc of 2fe43b6 --- actionpack/lib/action_dispatch/routing/url_for.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 6c3fc5126a..d4db78a25a 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -119,8 +119,9 @@ module ActionDispatch # to split the domain from the host. # * :domain - Specifies the domain of the link, using the +tld_length+ # to split the subdomain from the host. - # * :tld_length - Optionally specify the tld length (only used if :subdomain - # or :domain are supplied). + # * :tld_length - Number of labels the TLD id composed of, only used if + # :subdomain or :domain are supplied. Defaults to + # ActionDispatch::Http::URL.tld_length, which in turn defaults to 1. # * :port - Optionally specify the port to connect to. # * :anchor - An anchor name to be appended to the path. # * :trailing_slash - If true, adds a trailing slash, as in "/archive/2009/" -- cgit v1.2.3 From 769575300acb778ce812208073952109bc45a9fd Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 24 Nov 2010 09:19:27 +1100 Subject: Fix formatting issue with rake routes output for the namespace method --- actionpack/lib/action_dispatch/routing/mapper.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 879ccc5791..432a574419 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -588,13 +588,13 @@ module ActionDispatch # # This generates the following routes: # - # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"} - # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"} - # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"} - # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"} - # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"} - # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"} - # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"} + # admin_posts GET /admin/posts(.:format) {:action=>"index", :controller=>"admin/posts"} + # admin_posts POST /admin/posts(.:format) {:action=>"create", :controller=>"admin/posts"} + # new_admin_post GET /admin/posts/new(.:format) {:action=>"new", :controller=>"admin/posts"} + # edit_admin_post GET /admin/posts/:id/edit(.:format) {:action=>"edit", :controller=>"admin/posts"} + # admin_post GET /admin/posts/:id(.:format) {:action=>"show", :controller=>"admin/posts"} + # admin_post PUT /admin/posts/:id(.:format) {:action=>"update", :controller=>"admin/posts"} + # admin_post DELETE /admin/posts/:id(.:format) {:action=>"destroy", :controller=>"admin/posts"} # === Supported options # # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+ all default to the name of the namespace. -- cgit v1.2.3 From 04af510b5678ea7bd4cd170257e7e3ef4423f834 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 24 Nov 2010 09:21:25 +1100 Subject: Paths in ActionDispatch::Scoping documentation should be for /admin/posts, not /admin/photos --- actionpack/lib/action_dispatch/routing/mapper.rb | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 432a574419..37d14944d6 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -439,13 +439,13 @@ module ActionDispatch # This will create a number of routes for each of the posts and comments # controller. For Admin::PostsController, Rails will create: # - # GET /admin/photos - # GET /admin/photos/new - # POST /admin/photos - # GET /admin/photos/1 - # GET /admin/photos/1/edit - # PUT /admin/photos/1 - # DELETE /admin/photos/1 + # GET /admin/posts + # GET /admin/posts/new + # POST /admin/posts + # GET /admin/posts/1 + # GET /admin/posts/1/edit + # PUT /admin/posts/1 + # DELETE /admin/posts/1 # # If you want to route /posts (without the prefix /admin) to # Admin::PostsController, you could use @@ -473,13 +473,13 @@ module ActionDispatch # not use scope. In the last case, the following paths map to # PostsController: # - # GET /admin/photos - # GET /admin/photos/new - # POST /admin/photos - # GET /admin/photos/1 - # GET /admin/photos/1/edit - # PUT /admin/photos/1 - # DELETE /admin/photos/1 + # GET /admin/posts + # GET /admin/posts/new + # POST /admin/posts + # GET /admin/posts/1 + # GET /admin/posts/1/edit + # PUT /admin/posts/1 + # DELETE /admin/posts/1 module Scoping def initialize(*args) #:nodoc: @scope = {} -- cgit v1.2.3 From 2974f57aaedd22f44b387ec72ca9f42a2982bb02 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 24 Nov 2010 09:25:01 +1100 Subject: Remove non-sensical first couple of lines for scope method documentation --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 37d14944d6..8b1578769d 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -486,8 +486,6 @@ module ActionDispatch super end - # Used to route /photos (without the prefix /admin) - # to Admin::PostsController: # === Supported options # [:module] # If you want to route /posts (without the prefix /admin) to -- cgit v1.2.3 From 01af50d8b6be7b167c30f29c7407ce88bdfc9b2a Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 24 Nov 2010 09:27:12 +1100 Subject: Add :module option documentation for the resources method --- actionpack/lib/action_dispatch/routing/mapper.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 8b1578769d..1f3a831b7f 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -967,6 +967,7 @@ module ActionDispatch # GET /photos/:id/edit # PUT /photos/:id # DELETE /photos/:id + # # === Supported options # [:path_names] # Allows you to change the paths of the seven default actions. @@ -975,6 +976,13 @@ module ActionDispatch # resources :posts, :path_names => { :new => "brand_new" } # # The above example will now change /posts/new to /posts/brand_new + # + # [:module] + # Set the module where the controller can be found. Defaults to nothing. + # + # resources :posts, :module => "admin" + # + # All requests to the posts resources will now go to +Admin::PostsController+. def resources(*resources, &block) options = resources.extract_options! -- cgit v1.2.3 From fd47a4bf438e37a20756e0341cd7cd4e472fd3cb Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 24 Nov 2010 09:28:21 +1100 Subject: Document the :path option for resources :posts --- actionpack/lib/action_dispatch/routing/mapper.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 1f3a831b7f..f4d31eeff1 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -983,6 +983,14 @@ module ActionDispatch # resources :posts, :module => "admin" # # All requests to the posts resources will now go to +Admin::PostsController+. + # + # [:path] + # + # Set a path prefix for this resource. + # + # resources :posts, :path => "admin" + # + # All actions for this resource will now be at +/admin/posts+. def resources(*resources, &block) options = resources.extract_options! -- cgit v1.2.3 From ca7b0a0d1a424aec0973fe22c299b8f04e309784 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 10:13:43 -0800 Subject: dup is working better --- activerecord/lib/active_record/base.rb | 12 +++++--- activerecord/test/cases/base_test.rb | 4 --- activerecord/test/cases/duplication_test.rb | 43 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 activerecord/test/cases/duplication_test.rb diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 9e15784f61..0d3df938e6 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1420,7 +1420,7 @@ MSG @attributes = coder['attributes'] @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {} @readonly = @destroyed = @marked_for_destruction = false - @persisted = true + @persisted = false _run_find_callbacks _run_initialize_callbacks end @@ -1615,11 +1615,15 @@ MSG @attributes.frozen? end + def initialize_dup(other) + super + init_with 'attributes' => other.attributes + self + end + # Returns duplicated record with unfreezed attributes. def dup - obj = super - obj.instance_variable_set('@attributes', @attributes.dup) - obj + super end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 26f388ca46..c8efabed30 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1443,10 +1443,6 @@ class BasicsTest < ActiveRecord::TestCase ActiveRecord::Base.logger = original_logger end - def test_dup - assert !Minimalistic.new.freeze.dup.frozen? - end - def test_compute_type_success assert_equal Author, ActiveRecord::Base.send(:compute_type, 'Author') end diff --git a/activerecord/test/cases/duplication_test.rb b/activerecord/test/cases/duplication_test.rb new file mode 100644 index 0000000000..610894a03e --- /dev/null +++ b/activerecord/test/cases/duplication_test.rb @@ -0,0 +1,43 @@ +require "cases/helper" +require 'models/topic' + +module ActiveRecord + class DuplicationTest < ActiveRecord::TestCase + fixtures :topics + + def test_dup + assert !Minimalistic.new.freeze.dup.frozen? + end + + def test_dup_not_persisted + topic = Topic.first + duped = topic.dup + + assert !duped.persisted?, 'topic not persisted' + assert duped.new_record?, 'topic is new' + end + + def test_dup_has_no_id + topic = Topic.first + duped = topic.dup + assert_nil duped.id + end + + def test_clone_persisted + topic = Topic.first + cloned = topic.clone + assert cloned.persisted?, 'topic persisted' + assert !cloned.new_record?, 'topic is not new' + end + + def test_clone_keeps_frozen + topic = Topic.first + topic.freeze + + cloned = topic.clone + assert cloned.persisted?, 'topic persisted' + assert !cloned.new_record?, 'topic is not new' + assert cloned.frozen?, 'topic is frozen' + end + end +end -- cgit v1.2.3 From 5badf60d128cb958fa7a0e3f140517b71b88c7ac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 10:58:19 -0800 Subject: dup keeps changes --- activerecord/lib/active_record/base.rb | 49 +++++++++++++---------------- activerecord/test/cases/duplication_test.rb | 19 +++++++++-- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 0d3df938e6..be8ebd4d59 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1382,30 +1382,6 @@ MSG result end - # Cloned objects have no id assigned and are treated as new records. Note that this is a "shallow" clone - # as it copies the object's attributes only, not its associations. The extent of a "deep" clone is - # application specific and is therefore left to the application to implement according to its need. - def initialize_copy(other) - _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) - cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) - cloned_attributes.delete(self.class.primary_key) - - @attributes = cloned_attributes - - @changed_attributes = {} - attributes_from_column_definition.each do |attr, orig_value| - @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) - end - - clear_aggregation_cache - clear_association_cache - @attributes_cache = {} - @persisted = false - ensure_proper_type - - populate_with_current_scope_attributes - end - # Initialize an empty model object from +coder+. +coder+ must contain # the attributes necessary for initializing an empty model object. For # example: @@ -1420,7 +1396,7 @@ MSG @attributes = coder['attributes'] @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {} @readonly = @destroyed = @marked_for_destruction = false - @persisted = false + @persisted = true _run_find_callbacks _run_initialize_callbacks end @@ -1615,15 +1591,32 @@ MSG @attributes.frozen? end + # Duped objects have no id assigned and are treated as new records. Note + # that this is a "shallow" clone as it copies the object's attributes + # only, not its associations. The extent of a "deep" dup is application + # specific and is therefore left to the application to implement according + # to its need. def initialize_dup(other) super - init_with 'attributes' => other.attributes + cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) + cloned_attributes.delete(self.class.primary_key) + + @attributes = cloned_attributes + @changed_attributes = other.changed_attributes.dup + @attributes_cache = {} + @persisted = false + + _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) + clear_aggregation_cache + clear_association_cache + ensure_proper_type + populate_with_current_scope_attributes self end - # Returns duplicated record with unfreezed attributes. - def dup + def initialize_clone(other) super + @persisted = other.persisted? end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back diff --git a/activerecord/test/cases/duplication_test.rb b/activerecord/test/cases/duplication_test.rb index 610894a03e..f9d614230b 100644 --- a/activerecord/test/cases/duplication_test.rb +++ b/activerecord/test/cases/duplication_test.rb @@ -6,7 +6,7 @@ module ActiveRecord fixtures :topics def test_dup - assert !Minimalistic.new.freeze.dup.frozen? + assert !Topic.new.freeze.dup.frozen? end def test_dup_not_persisted @@ -26,6 +26,7 @@ module ActiveRecord def test_clone_persisted topic = Topic.first cloned = topic.clone + assert topic.persisted?, 'topic persisted' assert cloned.persisted?, 'topic persisted' assert !cloned.new_record?, 'topic is not new' end @@ -37,7 +38,21 @@ module ActiveRecord cloned = topic.clone assert cloned.persisted?, 'topic persisted' assert !cloned.new_record?, 'topic is not new' - assert cloned.frozen?, 'topic is frozen' + assert cloned.frozen?, 'topic should be frozen' + end + + def test_dup_with_modified_attributes + topic = Topic.first + topic.author_name = 'Aaron' + duped = topic.dup + assert_equal 'Aaron', duped.author_name + end + + def test_dup_with_changes + topic = Topic.first + topic.author_name = 'Aaron' + duped = topic.dup + assert_equal topic.changes, duped.changes end end end -- cgit v1.2.3 From 035d00b665a645a12ecd1f9c70dba06bbd4f6201 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 10:59:23 -0800 Subject: making sure changes to dup will not touch original --- activerecord/test/cases/duplication_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/activerecord/test/cases/duplication_test.rb b/activerecord/test/cases/duplication_test.rb index f9d614230b..c6f7e3ef16 100644 --- a/activerecord/test/cases/duplication_test.rb +++ b/activerecord/test/cases/duplication_test.rb @@ -54,5 +54,15 @@ module ActiveRecord duped = topic.dup assert_equal topic.changes, duped.changes end + + def test_dup_topics_are_independent + topic = Topic.first + topic.author_name = 'Aaron' + duped = topic.dup + + duped.author_name = 'meow' + + assert_not_equal topic.changes, duped.changes + end end end -- cgit v1.2.3 From 4c1f76eaab670ffa95d185374ea91f0d2e2818c7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 10:59:58 -0800 Subject: initialize_clone can go away --- activerecord/lib/active_record/base.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index be8ebd4d59..6f0e71cc7b 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1614,11 +1614,6 @@ MSG self end - def initialize_clone(other) - super - @persisted = other.persisted? - end - # Returns +true+ if the record is read only. Records loaded through joins with piggy-back # attributes will be marked as read only since they cannot be saved. def readonly? -- cgit v1.2.3 From 28f4df0908180783f8cf863a8bbb30c1c139bd8d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 11:10:56 -0800 Subject: testing duped attributes are independent --- activerecord/test/cases/duplication_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/activerecord/test/cases/duplication_test.rb b/activerecord/test/cases/duplication_test.rb index c6f7e3ef16..1ca6e72db0 100644 --- a/activerecord/test/cases/duplication_test.rb +++ b/activerecord/test/cases/duplication_test.rb @@ -41,6 +41,13 @@ module ActiveRecord assert cloned.frozen?, 'topic should be frozen' end + def test_clone_is_shallow + topic = Topic.first + cloned = topic.clone + topic.author_name = 'Aaron' + assert_equal 'Aaron', cloned.author_name + end + def test_dup_with_modified_attributes topic = Topic.first topic.author_name = 'Aaron' @@ -64,5 +71,16 @@ module ActiveRecord assert_not_equal topic.changes, duped.changes end + + def test_dup_attributes_are_independent + topic = Topic.first + duped = topic.dup + + duped.author_name = 'meow' + topic.author_name = 'Aaron' + + assert_equal 'Aaron', topic.author_name + assert_equal 'meow', duped.author_name + end end end -- cgit v1.2.3 From c5858a6df3efefbab8925623b1e6c064c476fb26 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 11:12:46 -0800 Subject: adding a specific case for clone testing --- activerecord/test/cases/clone_test.rb | 33 +++++++++++++++++++++++++++++ activerecord/test/cases/duplication_test.rb | 25 ---------------------- 2 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 activerecord/test/cases/clone_test.rb diff --git a/activerecord/test/cases/clone_test.rb b/activerecord/test/cases/clone_test.rb new file mode 100644 index 0000000000..d91646efca --- /dev/null +++ b/activerecord/test/cases/clone_test.rb @@ -0,0 +1,33 @@ +require "cases/helper" +require 'models/topic' + +module ActiveRecord + class CloneTest < ActiveRecord::TestCase + fixtures :topics + + def test_persisted + topic = Topic.first + cloned = topic.clone + assert topic.persisted?, 'topic persisted' + assert cloned.persisted?, 'topic persisted' + assert !cloned.new_record?, 'topic is not new' + end + + def test_stays_frozen + topic = Topic.first + topic.freeze + + cloned = topic.clone + assert cloned.persisted?, 'topic persisted' + assert !cloned.new_record?, 'topic is not new' + assert cloned.frozen?, 'topic should be frozen' + end + + def test_shallow + topic = Topic.first + cloned = topic.clone + topic.author_name = 'Aaron' + assert_equal 'Aaron', cloned.author_name + end + end +end diff --git a/activerecord/test/cases/duplication_test.rb b/activerecord/test/cases/duplication_test.rb index 1ca6e72db0..ecea843bbf 100644 --- a/activerecord/test/cases/duplication_test.rb +++ b/activerecord/test/cases/duplication_test.rb @@ -23,31 +23,6 @@ module ActiveRecord assert_nil duped.id end - def test_clone_persisted - topic = Topic.first - cloned = topic.clone - assert topic.persisted?, 'topic persisted' - assert cloned.persisted?, 'topic persisted' - assert !cloned.new_record?, 'topic is not new' - end - - def test_clone_keeps_frozen - topic = Topic.first - topic.freeze - - cloned = topic.clone - assert cloned.persisted?, 'topic persisted' - assert !cloned.new_record?, 'topic is not new' - assert cloned.frozen?, 'topic should be frozen' - end - - def test_clone_is_shallow - topic = Topic.first - cloned = topic.clone - topic.author_name = 'Aaron' - assert_equal 'Aaron', cloned.author_name - end - def test_dup_with_modified_attributes topic = Topic.first topic.author_name = 'Aaron' -- cgit v1.2.3 From 6a8f1b8b402b31ae43872c9d1f37b931c85799e7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 11:13:24 -0800 Subject: renaming duplication test to dup test --- activerecord/test/cases/dup_test.rb | 61 +++++++++++++++++++++++++++++ activerecord/test/cases/duplication_test.rb | 61 ----------------------------- 2 files changed, 61 insertions(+), 61 deletions(-) create mode 100644 activerecord/test/cases/dup_test.rb delete mode 100644 activerecord/test/cases/duplication_test.rb diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb new file mode 100644 index 0000000000..fa528c4936 --- /dev/null +++ b/activerecord/test/cases/dup_test.rb @@ -0,0 +1,61 @@ +require "cases/helper" +require 'models/topic' + +module ActiveRecord + class DupTest < ActiveRecord::TestCase + fixtures :topics + + def test_dup + assert !Topic.new.freeze.dup.frozen? + end + + def test_dup_not_persisted + topic = Topic.first + duped = topic.dup + + assert !duped.persisted?, 'topic not persisted' + assert duped.new_record?, 'topic is new' + end + + def test_dup_has_no_id + topic = Topic.first + duped = topic.dup + assert_nil duped.id + end + + def test_dup_with_modified_attributes + topic = Topic.first + topic.author_name = 'Aaron' + duped = topic.dup + assert_equal 'Aaron', duped.author_name + end + + def test_dup_with_changes + topic = Topic.first + topic.author_name = 'Aaron' + duped = topic.dup + assert_equal topic.changes, duped.changes + end + + def test_dup_topics_are_independent + topic = Topic.first + topic.author_name = 'Aaron' + duped = topic.dup + + duped.author_name = 'meow' + + assert_not_equal topic.changes, duped.changes + end + + def test_dup_attributes_are_independent + topic = Topic.first + duped = topic.dup + + duped.author_name = 'meow' + topic.author_name = 'Aaron' + + assert_equal 'Aaron', topic.author_name + assert_equal 'meow', duped.author_name + end + end +end diff --git a/activerecord/test/cases/duplication_test.rb b/activerecord/test/cases/duplication_test.rb deleted file mode 100644 index ecea843bbf..0000000000 --- a/activerecord/test/cases/duplication_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -require "cases/helper" -require 'models/topic' - -module ActiveRecord - class DuplicationTest < ActiveRecord::TestCase - fixtures :topics - - def test_dup - assert !Topic.new.freeze.dup.frozen? - end - - def test_dup_not_persisted - topic = Topic.first - duped = topic.dup - - assert !duped.persisted?, 'topic not persisted' - assert duped.new_record?, 'topic is new' - end - - def test_dup_has_no_id - topic = Topic.first - duped = topic.dup - assert_nil duped.id - end - - def test_dup_with_modified_attributes - topic = Topic.first - topic.author_name = 'Aaron' - duped = topic.dup - assert_equal 'Aaron', duped.author_name - end - - def test_dup_with_changes - topic = Topic.first - topic.author_name = 'Aaron' - duped = topic.dup - assert_equal topic.changes, duped.changes - end - - def test_dup_topics_are_independent - topic = Topic.first - topic.author_name = 'Aaron' - duped = topic.dup - - duped.author_name = 'meow' - - assert_not_equal topic.changes, duped.changes - end - - def test_dup_attributes_are_independent - topic = Topic.first - duped = topic.dup - - duped.author_name = 'meow' - topic.author_name = 'Aaron' - - assert_equal 'Aaron', topic.author_name - assert_equal 'meow', duped.author_name - end - end -end -- cgit v1.2.3 From 93d78b831831a1c8e324d4c5404b99e81fe77725 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 11:30:14 -0800 Subject: fixing more dup tests --- activerecord/lib/active_record/base.rb | 8 +++---- activerecord/test/cases/base_test.rb | 43 +++++++++++++++++----------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 6f0e71cc7b..f9de4b7918 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1598,20 +1598,20 @@ MSG # to its need. def initialize_dup(other) super + _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) @attributes = cloned_attributes @changed_attributes = other.changed_attributes.dup - @attributes_cache = {} - @persisted = false - _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) clear_aggregation_cache clear_association_cache + @attributes_cache = {} + @persisted = false + ensure_proper_type populate_with_current_scope_attributes - self end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index c8efabed30..e3f4f2bd08 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -669,36 +669,36 @@ class BasicsTest < ActiveRecord::TestCase assert_equal true, Topic.find(1).persisted? end - def test_clone + def test_dup topic = Topic.find(1) - cloned_topic = nil - assert_nothing_raised { cloned_topic = topic.clone } - assert_equal topic.title, cloned_topic.title - assert !cloned_topic.persisted? + duped_topic = nil + assert_nothing_raised { duped_topic = topic.dup } + assert_equal topic.title, duped_topic.title + assert !duped_topic.persisted? - # test if the attributes have been cloned + # test if the attributes have been duped topic.title = "a" - cloned_topic.title = "b" + duped_topic.title = "b" assert_equal "a", topic.title - assert_equal "b", cloned_topic.title + assert_equal "b", duped_topic.title - # test if the attribute values have been cloned + # test if the attribute values have been duped topic.title = {"a" => "b"} - cloned_topic = topic.clone - cloned_topic.title["a"] = "c" + duped_topic = topic.dup + duped_topic.title["a"] = "c" assert_equal "b", topic.title["a"] - # test if attributes set as part of after_initialize are cloned correctly - assert_equal topic.author_email_address, cloned_topic.author_email_address + # test if attributes set as part of after_initialize are duped correctly + assert_equal topic.author_email_address, duped_topic.author_email_address # test if saved clone object differs from original - cloned_topic.save - assert cloned_topic.persisted? - assert_not_equal cloned_topic.id, topic.id + duped_topic.save + assert duped_topic.persisted? + assert_not_equal duped_topic.id, topic.id - cloned_topic.reload + duped_topic.reload # FIXME: I think this is poor behavior, and will fix it with #5686 - assert_equal({'a' => 'c'}.to_s, cloned_topic.title) + assert_equal({'a' => 'c'}.to_s, duped_topic.title) end def test_clone_with_aggregate_of_same_name_as_attribute @@ -721,12 +721,13 @@ class BasicsTest < ActiveRecord::TestCase assert_not_equal clone.id, dev.id end - def test_clone_does_not_clone_associations + def test_dup_does_not_copy_associations author = authors(:david) assert_not_equal [], author.posts + author.send(:clear_association_cache) - author_clone = author.clone - assert_equal [], author_clone.posts + author_dup = author.dup + assert_equal [], author_dup.posts end def test_clone_preserves_subtype -- cgit v1.2.3 From 064c28d6c290cb9b6222b2348e38e713b82a89d6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 11:57:33 -0800 Subject: fixing dup regressions --- activerecord/lib/active_record/base.rb | 12 +++++++---- activerecord/test/cases/base_test.rb | 32 ++++++++++++++--------------- activerecord/test/cases/dirty_test.rb | 8 ++++---- activerecord/test/cases/dup_test.rb | 9 +++++--- activerecord/test/cases/inheritance_test.rb | 2 +- 5 files changed, 35 insertions(+), 28 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index f9de4b7918..7cc4f957fe 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1592,8 +1592,8 @@ MSG end # Duped objects have no id assigned and are treated as new records. Note - # that this is a "shallow" clone as it copies the object's attributes - # only, not its associations. The extent of a "deep" dup is application + # that this is a "shallow" copy as it copies the object's attributes + # only, not its associations. The extent of a "deep" copy is application # specific and is therefore left to the application to implement according # to its need. def initialize_dup(other) @@ -1602,8 +1602,12 @@ MSG cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) - @attributes = cloned_attributes - @changed_attributes = other.changed_attributes.dup + @attributes = cloned_attributes + + @changed_attributes = {} + attributes_from_column_definition.each do |attr, orig_value| + @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) + end clear_aggregation_cache clear_association_cache diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index e3f4f2bd08..c3ba1f0c35 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -701,24 +701,24 @@ class BasicsTest < ActiveRecord::TestCase assert_equal({'a' => 'c'}.to_s, duped_topic.title) end - def test_clone_with_aggregate_of_same_name_as_attribute + def test_dup_with_aggregate_of_same_name_as_attribute dev = DeveloperWithAggregate.find(1) assert_kind_of DeveloperSalary, dev.salary - clone = nil - assert_nothing_raised { clone = dev.clone } - assert_kind_of DeveloperSalary, clone.salary - assert_equal dev.salary.amount, clone.salary.amount - assert !clone.persisted? + dup = nil + assert_nothing_raised { dup = dev.dup } + assert_kind_of DeveloperSalary, dup.salary + assert_equal dev.salary.amount, dup.salary.amount + assert !dup.persisted? - # test if the attributes have been cloned - original_amount = clone.salary.amount + # test if the attributes have been dupd + original_amount = dup.salary.amount dev.salary.amount = 1 - assert_equal original_amount, clone.salary.amount + assert_equal original_amount, dup.salary.amount - assert clone.save - assert clone.persisted? - assert_not_equal clone.id, dev.id + assert dup.save + assert dup.persisted? + assert_not_equal dup.id, dev.id end def test_dup_does_not_copy_associations @@ -766,22 +766,22 @@ class BasicsTest < ActiveRecord::TestCase assert !cloned_developer.salary_changed? # ... and cloned instance should behave same end - def test_clone_of_saved_object_marks_attributes_as_dirty + def test_dup_of_saved_object_marks_attributes_as_dirty developer = Developer.create! :name => 'Bjorn', :salary => 100000 assert !developer.name_changed? assert !developer.salary_changed? - cloned_developer = developer.clone + cloned_developer = developer.dup assert cloned_developer.name_changed? # both attributes differ from defaults assert cloned_developer.salary_changed? end - def test_clone_of_saved_object_marks_as_dirty_only_changed_attributes + def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes developer = Developer.create! :name => 'Bjorn' assert !developer.name_changed? # both attributes of saved object should be threated as not changed assert !developer.salary_changed? - cloned_developer = developer.clone + cloned_developer = developer.dup assert cloned_developer.name_changed? # ... but on cloned object should be assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be threated as not changed on cloned instance end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index b1a54af192..a6738fb654 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -338,13 +338,13 @@ class DirtyTest < ActiveRecord::TestCase assert !pirate.changed? end - def test_cloned_objects_should_not_copy_dirty_flag_from_creator + def test_dup_objects_should_not_copy_dirty_flag_from_creator pirate = Pirate.create!(:catchphrase => "shiver me timbers") - pirate_clone = pirate.clone - pirate_clone.reset_catchphrase! + pirate_dup = pirate.dup + pirate_dup.reset_catchphrase! pirate.catchphrase = "I love Rum" assert pirate.catchphrase_changed? - assert !pirate_clone.catchphrase_changed? + assert !pirate_dup.catchphrase_changed? end def test_reverted_changes_are_not_dirty diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb index fa528c4936..768474e4ac 100644 --- a/activerecord/test/cases/dup_test.rb +++ b/activerecord/test/cases/dup_test.rb @@ -31,9 +31,12 @@ module ActiveRecord end def test_dup_with_changes - topic = Topic.first - topic.author_name = 'Aaron' - duped = topic.dup + dbtopic = Topic.first + topic = Topic.new + + topic.attributes = dbtopic.attributes + + duped = dbtopic.dup assert_equal topic.changes, duped.changes end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 31679b2efe..c3da9cdf53 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -16,7 +16,7 @@ class InheritanceTest < ActiveRecord::TestCase def test_class_with_blank_sti_name company = Company.find(:first) - company = company.clone + company = company.dup company.extend(Module.new { def read_attribute(name) return ' ' if name == 'type' -- cgit v1.2.3 From fe4388eb15d44612710f2fc2f81c90a890278b23 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 12:00:17 -0800 Subject: converting clone test to dup test --- activerecord/test/cases/autosave_association_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index b13cb2d7a2..fbf7121468 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -163,15 +163,15 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas firm.account = Account.find(:first) assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! } - firm = Firm.find(:first).clone + firm = Firm.find(:first).dup firm.account = Account.find(:first) assert_queries(2) { firm.save! } - firm = Firm.find(:first).clone - firm.account = Account.find(:first).clone + firm = Firm.find(:first).dup + firm.account = Account.find(:first).dup assert_queries(2) { firm.save! } end - + def test_callbacks_firing_order_on_create eye = Eye.create(:iris_attributes => {:color => 'honey'}) assert_equal [true, false], eye.after_create_callbacks_stack -- cgit v1.2.3 From d717cb29136b8e4f557e6f6ddf076ae3de8476fc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 13:38:20 -0800 Subject: clone and dup are working on 1.8 --- activerecord/lib/active_record/base.rb | 15 ++++++++++++--- activerecord/test/cases/dup_test.rb | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 7cc4f957fe..d2fa3bed35 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1591,19 +1591,28 @@ MSG @attributes.frozen? end + # Backport dup from 1.9 so that initialize_dup() gets called + unless Object.respond_to?(:initialize_dup) + def dup # :nodoc: + copy = super + copy.initialize_dup(self) + copy + end + end + # Duped objects have no id assigned and are treated as new records. Note # that this is a "shallow" copy as it copies the object's attributes # only, not its associations. The extent of a "deep" copy is application # specific and is therefore left to the application to implement according # to its need. def initialize_dup(other) - super - _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) @attributes = cloned_attributes + _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks) + @changed_attributes = {} attributes_from_column_definition.each do |attr, orig_value| @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) @@ -1612,7 +1621,7 @@ MSG clear_aggregation_cache clear_association_cache @attributes_cache = {} - @persisted = false + @persisted = false ensure_proper_type populate_with_current_scope_attributes diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb index 768474e4ac..a1fc639290 100644 --- a/activerecord/test/cases/dup_test.rb +++ b/activerecord/test/cases/dup_test.rb @@ -9,6 +9,21 @@ module ActiveRecord assert !Topic.new.freeze.dup.frozen? end + def test_not_readonly + topic = Topic.first + + duped = topic.dup + assert !topic.readonly?, 'should not be readonly' + end + + def test_is_readonly + topic = Topic.first + topic.readonly! + + duped = topic.dup + assert topic.readonly?, 'should be readonly' + end + def test_dup_not_persisted topic = Topic.first duped = topic.dup -- cgit v1.2.3 From 0456feab1198456069d4b5a9da221e6fd818e3da Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 14:13:03 -0800 Subject: updating changelog for dup and clone semantics --- activerecord/CHANGELOG | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index a3e3051b96..f46db909ba 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,16 @@ *Rails 3.1.0 (unreleased)* +* ActiveRecord::Base#dup and ActiveRecord::Base#clone semantics have changed +to closer match normal Ruby dup and clone semantics. + +* Calling ActiveRecord::Base#clone will result in a shallow copy of the record, +including copying the frozen state. No callbacks will be called. + +* Calling ActiveRecord::Base#dup will duplicate the record, including calling +after initialize hooks. Frozen state will not be copied, and all associations +will be cleared. A duped record will return true for new_record?, have a nil +id field, and is saveable. + * Migrations can be defined as reversible, meaning that the migration system will figure out how to reverse your migration. To use reversible migrations, just define the "change" method. For example: -- cgit v1.2.3 From e4a9af186a7316e2de018ff9306442b9fe0f2400 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Wed, 24 Nov 2010 09:31:29 +1100 Subject: Add mention of nested resource to resources documentation --- actionpack/lib/action_dispatch/routing/mapper.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index f4d31eeff1..fb1f0d3f0c 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -968,6 +968,21 @@ module ActionDispatch # PUT /photos/:id # DELETE /photos/:id # + # Resources can also be nested infinitely by using this block syntax: + # + # resources :photos do + # resources :comments + # end + # + # This generates the following comments routes: + # + # GET /photos/:id/comments/new + # POST /photos/:id/comments + # GET /photos/:id/comments/:id + # GET /photos/:id/comments/:id/edit + # PUT /photos/:id/comments/:id + # DELETE /photos/:id/comments/:id + # # === Supported options # [:path_names] # Allows you to change the paths of the seven default actions. -- cgit v1.2.3 From d33dcba72d19beffc4a359f2fb89659f24122e9a Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Tue, 23 Nov 2010 14:58:10 -0500 Subject: Do not send id for quoting twice if the primary key is string. [#6022 state:resolved] --- activerecord/lib/active_record/relation/predicate_builder.rb | 3 ++- activerecord/test/cases/relations_test.rb | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 32c7d08daa..7e2ce06dae 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -26,7 +26,8 @@ module ActiveRecord when Range, Arel::Relation attribute.in(value) when ActiveRecord::Base - attribute.eq(value.quoted_id) + sanitized_id = attribute.class == Arel::Attributes::String ? value.id : value.quoted_id + attribute.eq(sanitized_id) when Class # FIXME: I think we need to deprecate this behavior attribute.eq(value.name) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 535bcd4396..1682f34a1d 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -14,11 +14,18 @@ require 'models/bird' require 'models/car' require 'models/engine' require 'models/tyre' +require 'models/minivan' class RelationTest < ActiveRecord::TestCase fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, - :tags, :taggings, :cars + :tags, :taggings, :cars, :minivans + + def test_do_not_double_quote_string_id + van = Minivan.last + assert van + assert_equal van.id, Minivan.where(:minivan_id => van).to_a.first.minivan_id + end def test_bind_values relation = Post.scoped -- cgit v1.2.3 From 8e8fb8a4291cc288b1189338f0de643c409eb028 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 14:42:55 -0800 Subject: just wrap as a sql literal --- activerecord/lib/active_record/relation/predicate_builder.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 7e2ce06dae..70d84619a1 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -26,8 +26,7 @@ module ActiveRecord when Range, Arel::Relation attribute.in(value) when ActiveRecord::Base - sanitized_id = attribute.class == Arel::Attributes::String ? value.id : value.quoted_id - attribute.eq(sanitized_id) + attribute.eq(Arel.sql(value.quoted_id)) when Class # FIXME: I think we need to deprecate this behavior attribute.eq(value.name) -- cgit v1.2.3 From 8882e65ac8cd499f09bacee4bc4f3f4c328fae05 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 24 Nov 2010 05:49:41 +0800 Subject: No need to return anything --- .../lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb index 15f8e10b7f..e52797042f 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb @@ -79,7 +79,6 @@ module ActionView sources.each do |source| asset_file_path!(path_to_asset(source, false)) end - return sources end def collect_asset_files(*path) -- cgit v1.2.3 From a551d2ec62f205a755d3b760a9943f20addafe35 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 17:28:26 -0800 Subject: fixing variable names. oops! --- activerecord/test/cases/dup_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb index a1fc639290..46abe7792c 100644 --- a/activerecord/test/cases/dup_test.rb +++ b/activerecord/test/cases/dup_test.rb @@ -13,7 +13,7 @@ module ActiveRecord topic = Topic.first duped = topic.dup - assert !topic.readonly?, 'should not be readonly' + assert !duped.readonly?, 'should not be readonly' end def test_is_readonly @@ -21,7 +21,7 @@ module ActiveRecord topic.readonly! duped = topic.dup - assert topic.readonly?, 'should be readonly' + assert duped.readonly?, 'should be readonly' end def test_dup_not_persisted -- cgit v1.2.3 From 1aaa8edeb958a263c7a256344f442867c4b90c5f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 17:34:18 -0800 Subject: breaking classes up in to respective files --- activerecord/lib/active_record/associations.rb | 575 +-------------------- .../associations/class_methods/join_dependency.rb | 216 ++++++++ .../join_dependency/join_association.rb | 278 ++++++++++ .../class_methods/join_dependency/join_base.rb | 34 ++ .../class_methods/join_dependency/join_part.rb | 76 +++ 5 files changed, 605 insertions(+), 574 deletions(-) create mode 100644 activerecord/lib/active_record/associations/class_methods/join_dependency.rb create mode 100644 activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb create mode 100644 activerecord/lib/active_record/associations/class_methods/join_dependency/join_base.rb create mode 100644 activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 7da38cd03f..0d9171d876 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -5,6 +5,7 @@ require 'active_support/core_ext/object/blank' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/module/remove_method' require 'active_support/core_ext/class/attribute' +require 'active_record/associations/class_methods/join_dependency' module ActiveRecord class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc: @@ -1832,580 +1833,6 @@ module ActiveRecord Array.wrap(extensions) end end - - class JoinDependency # :nodoc: - attr_reader :join_parts, :reflections, :table_aliases - - def initialize(base, associations, joins) - @join_parts = [JoinBase.new(base, joins)] - @associations = {} - @reflections = [] - @table_aliases = Hash.new(0) - @table_aliases[base.table_name] = 1 - build(associations) - end - - def graft(*associations) - associations.each do |association| - join_associations.detect {|a| association == a} || - build(association.reflection.name, association.find_parent_in(self) || join_base, association.join_type) - end - self - end - - def join_associations - join_parts.last(join_parts.length - 1) - end - - def join_base - join_parts.first - end - - def count_aliases_from_table_joins(name) - # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase - quoted_name = join_base.active_record.connection.quote_table_name(name.downcase).downcase - join_sql = join_base.table_joins.to_s.downcase - join_sql.blank? ? 0 : - # Table names - join_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size + - # Table aliases - join_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size - end - - def instantiate(rows) - primary_key = join_base.aliased_primary_key - parents = {} - - records = rows.map { |model| - primary_id = model[primary_key] - parent = parents[primary_id] ||= join_base.instantiate(model) - construct(parent, @associations, join_associations.dup, model) - parent - }.uniq - - remove_duplicate_results!(join_base.active_record, records, @associations) - records - end - - def remove_duplicate_results!(base, records, associations) - case associations - when Symbol, String - reflection = base.reflections[associations] - remove_uniq_by_reflection(reflection, records) - when Array - associations.each do |association| - remove_duplicate_results!(base, records, association) - end - when Hash - associations.keys.each do |name| - reflection = base.reflections[name] - remove_uniq_by_reflection(reflection, records) - - parent_records = [] - records.each do |record| - if descendant = record.send(reflection.name) - if reflection.collection? - parent_records.concat descendant.target.uniq - else - parent_records << descendant - end - end - end - - remove_duplicate_results!(reflection.klass, parent_records, associations[name]) unless parent_records.empty? - end - end - end - - protected - - def cache_joined_association(association) - associations = [] - parent = association.parent - while parent != join_base - associations.unshift(parent.reflection.name) - parent = parent.parent - end - ref = @associations - associations.each do |key| - ref = ref[key] - end - ref[association.reflection.name] ||= {} - end - - def build(associations, parent = nil, join_type = Arel::InnerJoin) - parent ||= join_parts.last - case associations - when Symbol, String - reflection = parent.reflections[associations.to_s.intern] or - raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?" - unless join_association = find_join_association(reflection, parent) - @reflections << reflection - join_association = build_join_association(reflection, parent) - join_association.join_type = join_type - @join_parts << join_association - cache_joined_association(join_association) - end - join_association - when Array - associations.each do |association| - build(association, parent, join_type) - end - when Hash - associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name| - join_association = build(name, parent, join_type) - build(associations[name], join_association, join_type) - end - else - raise ConfigurationError, associations.inspect - end - end - - def find_join_association(name_or_reflection, parent) - if String === name_or_reflection - name_or_reflection = name_or_reflection.to_sym - end - - join_associations.detect { |j| - j.reflection == name_or_reflection && j.parent == parent - } - end - - def remove_uniq_by_reflection(reflection, records) - if reflection && reflection.collection? - records.each { |record| record.send(reflection.name).target.uniq! } - end - end - - def build_join_association(reflection, parent) - JoinAssociation.new(reflection, self, parent) - end - - def construct(parent, associations, join_parts, row) - case associations - when Symbol, String - name = associations.to_s - - join_part = join_parts.detect { |j| - j.reflection.name.to_s == name && - j.parent_table_name == parent.class.table_name } - - raise(ConfigurationError, "No such association") unless join_part - - join_parts.delete(join_part) - construct_association(parent, join_part, row) - when Array - associations.each do |association| - construct(parent, association, join_parts, row) - end - when Hash - associations.sort_by { |k,_| k.to_s }.each do |name, assoc| - association = construct(parent, name, join_parts, row) - construct(association, assoc, join_parts, row) if association - end - else - raise ConfigurationError, associations.inspect - end - end - - def construct_association(record, join_part, row) - return if record.id.to_s != join_part.parent.record_id(row).to_s - - macro = join_part.reflection.macro - if macro == :has_one - return if record.instance_variable_defined?("@#{join_part.reflection.name}") - association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil? - set_target_and_inverse(join_part, association, record) - else - return if row[join_part.aliased_primary_key].nil? - association = join_part.instantiate(row) - case macro - when :has_many, :has_and_belongs_to_many - collection = record.send(join_part.reflection.name) - collection.loaded - collection.target.push(association) - collection.__send__(:set_inverse_instance, association, record) - when :belongs_to - set_target_and_inverse(join_part, association, record) - else - raise ConfigurationError, "unknown macro: #{join_part.reflection.macro}" - end - end - association - end - - def set_target_and_inverse(join_part, association, record) - association_proxy = record.send("set_#{join_part.reflection.name}_target", association) - association_proxy.__send__(:set_inverse_instance, association, record) - end - - # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited - # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which - # everything else is being joined onto. A JoinAssociation represents an association which - # is joining to the base. A JoinAssociation may result in more than one actual join - # operations (for example a has_and_belongs_to_many JoinAssociation would result in - # two; one for the join table and one for the target table). - class JoinPart # :nodoc: - # The Active Record class which this join part is associated 'about'; for a JoinBase - # this is the actual base model, for a JoinAssociation this is the target model of the - # association. - attr_reader :active_record - - delegate :table_name, :column_names, :primary_key, :reflections, :sanitize_sql, :arel_engine, :to => :active_record - - def initialize(active_record) - @active_record = active_record - @cached_record = {} - end - - def ==(other) - raise NotImplementedError - end - - # An Arel::Table for the active_record - def table - raise NotImplementedError - end - - # The prefix to be used when aliasing columns in the active_record's table - def aliased_prefix - raise NotImplementedError - end - - # The alias for the active_record's table - def aliased_table_name - raise NotImplementedError - end - - # The alias for the primary key of the active_record's table - def aliased_primary_key - "#{aliased_prefix}_r0" - end - - # An array of [column_name, alias] pairs for the table - def column_names_with_alias - unless defined?(@column_names_with_alias) - @column_names_with_alias = [] - - ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i| - @column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"] - end - end - - @column_names_with_alias - end - - def extract_record(row) - Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}] - end - - def record_id(row) - row[aliased_primary_key] - end - - def instantiate(row) - @cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row)) - end - end - - class JoinBase < JoinPart # :nodoc: - # Extra joins provided when the JoinDependency was created - attr_reader :table_joins - - def initialize(active_record, joins = nil) - super(active_record) - @table_joins = joins - end - - def ==(other) - other.class == self.class && - other.active_record == active_record - end - - def aliased_prefix - "t0" - end - - def table - Arel::Table.new(table_name, :engine => arel_engine, :columns => active_record.columns) - end - - def aliased_table_name - active_record.table_name - end - end - - class JoinAssociation < JoinPart # :nodoc: - # The reflection of the association represented - attr_reader :reflection - - # The JoinDependency object which this JoinAssociation exists within. This is mainly - # relevant for generating aliases which do not conflict with other joins which are - # part of the query. - attr_reader :join_dependency - - # A JoinBase instance representing the active record we are joining onto. - # (So in Author.has_many :posts, the Author would be that base record.) - attr_reader :parent - - # What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin - attr_accessor :join_type - - # These implement abstract methods from the superclass - attr_reader :aliased_prefix, :aliased_table_name - - delegate :options, :through_reflection, :source_reflection, :to => :reflection - delegate :table, :table_name, :to => :parent, :prefix => true - - def initialize(reflection, join_dependency, parent = nil) - reflection.check_validity! - - if reflection.options[:polymorphic] - raise EagerLoadPolymorphicError.new(reflection) - end - - super(reflection.klass) - - @reflection = reflection - @join_dependency = join_dependency - @parent = parent - @join_type = Arel::InnerJoin - - # This must be done eagerly upon initialisation because the alias which is produced - # depends on the state of the join dependency, but we want it to work the same way - # every time. - allocate_aliases - end - - def ==(other) - other.class == self.class && - other.reflection == reflection && - other.parent == parent - end - - def find_parent_in(other_join_dependency) - other_join_dependency.join_parts.detect do |join_part| - self.parent == join_part - end - end - - def join_to(relation) - send("join_#{reflection.macro}_to", relation) - end - - def join_relation(joining_relation) - self.join_type = Arel::OuterJoin - joining_relation.joins(self) - end - - def table - @table ||= Arel::Table.new( - table_name, :as => aliased_table_name, - :engine => arel_engine, :columns => active_record.columns - ) - end - - # More semantic name given we are talking about associations - alias_method :target_table, :table - - protected - - def aliased_table_name_for(name, suffix = nil) - if @join_dependency.table_aliases[name].zero? - @join_dependency.table_aliases[name] = @join_dependency.count_aliases_from_table_joins(name) - end - - if !@join_dependency.table_aliases[name].zero? # We need an alias - name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}" - @join_dependency.table_aliases[name] += 1 - if @join_dependency.table_aliases[name] == 1 # First time we've seen this name - # Also need to count the aliases from the table_aliases to avoid incorrect count - @join_dependency.table_aliases[name] += @join_dependency.count_aliases_from_table_joins(name) - end - table_index = @join_dependency.table_aliases[name] - name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index}" if table_index > 1 - else - @join_dependency.table_aliases[name] += 1 - end - - name - end - - def pluralize(table_name) - ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name - end - - def interpolate_sql(sql) - instance_eval("%@#{sql.gsub('@', '\@')}@", __FILE__, __LINE__) - end - - private - - def allocate_aliases - @aliased_prefix = "t#{ join_dependency.join_parts.size }" - @aliased_table_name = aliased_table_name_for(table_name) - - if reflection.macro == :has_and_belongs_to_many - @aliased_join_table_name = aliased_table_name_for(reflection.options[:join_table], "_join") - elsif [:has_many, :has_one].include?(reflection.macro) && reflection.options[:through] - @aliased_join_table_name = aliased_table_name_for(reflection.through_reflection.klass.table_name, "_join") - end - end - - def process_conditions(conditions, table_name) - Arel.sql(interpolate_sql(sanitize_sql(conditions, table_name))) - end - - def join_target_table(relation, *conditions) - relation = relation.join(target_table, join_type) - - # If the target table is an STI model then we must be sure to only include records of - # its type and its sub-types. - unless active_record.descends_from_active_record? - sti_column = target_table[active_record.inheritance_column] - - sti_condition = sti_column.eq(active_record.sti_name) - active_record.descendants.each do |subclass| - sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) - end - - conditions << sti_condition - end - - # If the reflection has conditions, add them - if options[:conditions] - conditions << process_conditions(options[:conditions], aliased_table_name) - end - - relation = relation.on(*conditions) - end - - def join_has_and_belongs_to_many_to(relation) - join_table = Arel::Table.new( - options[:join_table], :engine => arel_engine, - :as => @aliased_join_table_name - ) - - fk = options[:foreign_key] || reflection.active_record.to_s.foreign_key - klass_fk = options[:association_foreign_key] || reflection.klass.to_s.foreign_key - - relation = relation.join(join_table, join_type) - relation = relation.on( - join_table[fk]. - eq(parent_table[reflection.active_record.primary_key]) - ) - - join_target_table( - relation, - target_table[reflection.klass.primary_key]. - eq(join_table[klass_fk]) - ) - end - - def join_has_many_to(relation) - if reflection.options[:through] - join_has_many_through_to(relation) - elsif reflection.options[:as] - join_has_many_polymorphic_to(relation) - else - foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key - primary_key = options[:primary_key] || parent.primary_key - - join_target_table( - relation, - target_table[foreign_key]. - eq(parent_table[primary_key]) - ) - end - end - alias :join_has_one_to :join_has_many_to - - def join_has_many_through_to(relation) - join_table = Arel::Table.new( - through_reflection.klass.table_name, :engine => arel_engine, - :as => @aliased_join_table_name - ) - - jt_conditions = [] - jt_foreign_key = first_key = second_key = nil - - if through_reflection.options[:as] # has_many :through against a polymorphic join - as_key = through_reflection.options[:as].to_s - jt_foreign_key = as_key + '_id' - - jt_conditions << - join_table[as_key + '_type']. - eq(parent.active_record.base_class.name) - else - jt_foreign_key = through_reflection.primary_key_name - end - - case source_reflection.macro - when :has_many - second_key = options[:foreign_key] || primary_key - - if source_reflection.options[:as] - first_key = "#{source_reflection.options[:as]}_id" - else - first_key = through_reflection.klass.base_class.to_s.foreign_key - end - - unless through_reflection.klass.descends_from_active_record? - jt_conditions << - join_table[through_reflection.active_record.inheritance_column]. - eq(through_reflection.klass.sti_name) - end - when :belongs_to - first_key = primary_key - - if reflection.options[:source_type] - second_key = source_reflection.association_foreign_key - - jt_conditions << - join_table[reflection.source_reflection.options[:foreign_type]]. - eq(reflection.options[:source_type]) - else - second_key = source_reflection.primary_key_name - end - end - - jt_conditions << - parent_table[parent.primary_key]. - eq(join_table[jt_foreign_key]) - - if through_reflection.options[:conditions] - jt_conditions << process_conditions(through_reflection.options[:conditions], aliased_table_name) - end - - relation = relation.join(join_table, join_type).on(*jt_conditions) - - join_target_table( - relation, - target_table[first_key].eq(join_table[second_key]) - ) - end - - def join_has_many_polymorphic_to(relation) - join_target_table( - relation, - target_table["#{reflection.options[:as]}_id"]. - eq(parent_table[parent.primary_key]), - target_table["#{reflection.options[:as]}_type"]. - eq(parent.active_record.base_class.name) - ) - end - - def join_belongs_to_to(relation) - foreign_key = options[:foreign_key] || reflection.primary_key_name - primary_key = options[:primary_key] || reflection.klass.primary_key - - join_target_table( - relation, - target_table[primary_key].eq(parent_table[foreign_key]) - ) - end - end - end end end end diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb new file mode 100644 index 0000000000..79fdb2d4cb --- /dev/null +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -0,0 +1,216 @@ +require 'active_record/associations/class_methods/join_dependency/join_part' +require 'active_record/associations/class_methods/join_dependency/join_base' +require 'active_record/associations/class_methods/join_dependency/join_association' + +module ActiveRecord + module Associations + module ClassMethods + class JoinDependency # :nodoc: + attr_reader :join_parts, :reflections, :table_aliases + + def initialize(base, associations, joins) + @join_parts = [JoinBase.new(base, joins)] + @associations = {} + @reflections = [] + @table_aliases = Hash.new(0) + @table_aliases[base.table_name] = 1 + build(associations) + end + + def graft(*associations) + associations.each do |association| + join_associations.detect {|a| association == a} || + build(association.reflection.name, association.find_parent_in(self) || join_base, association.join_type) + end + self + end + + def join_associations + join_parts.last(join_parts.length - 1) + end + + def join_base + join_parts.first + end + + def count_aliases_from_table_joins(name) + # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase + quoted_name = join_base.active_record.connection.quote_table_name(name.downcase).downcase + join_sql = join_base.table_joins.to_s.downcase + join_sql.blank? ? 0 : + # Table names + join_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size + + # Table aliases + join_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size + end + + def instantiate(rows) + primary_key = join_base.aliased_primary_key + parents = {} + + records = rows.map { |model| + primary_id = model[primary_key] + parent = parents[primary_id] ||= join_base.instantiate(model) + construct(parent, @associations, join_associations.dup, model) + parent + }.uniq + + remove_duplicate_results!(join_base.active_record, records, @associations) + records + end + + def remove_duplicate_results!(base, records, associations) + case associations + when Symbol, String + reflection = base.reflections[associations] + remove_uniq_by_reflection(reflection, records) + when Array + associations.each do |association| + remove_duplicate_results!(base, records, association) + end + when Hash + associations.keys.each do |name| + reflection = base.reflections[name] + remove_uniq_by_reflection(reflection, records) + + parent_records = [] + records.each do |record| + if descendant = record.send(reflection.name) + if reflection.collection? + parent_records.concat descendant.target.uniq + else + parent_records << descendant + end + end + end + + remove_duplicate_results!(reflection.klass, parent_records, associations[name]) unless parent_records.empty? + end + end + end + + protected + + def cache_joined_association(association) + associations = [] + parent = association.parent + while parent != join_base + associations.unshift(parent.reflection.name) + parent = parent.parent + end + ref = @associations + associations.each do |key| + ref = ref[key] + end + ref[association.reflection.name] ||= {} + end + + def build(associations, parent = nil, join_type = Arel::InnerJoin) + parent ||= join_parts.last + case associations + when Symbol, String + reflection = parent.reflections[associations.to_s.intern] or + raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?" + unless join_association = find_join_association(reflection, parent) + @reflections << reflection + join_association = build_join_association(reflection, parent) + join_association.join_type = join_type + @join_parts << join_association + cache_joined_association(join_association) + end + join_association + when Array + associations.each do |association| + build(association, parent, join_type) + end + when Hash + associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name| + join_association = build(name, parent, join_type) + build(associations[name], join_association, join_type) + end + else + raise ConfigurationError, associations.inspect + end + end + + def find_join_association(name_or_reflection, parent) + if String === name_or_reflection + name_or_reflection = name_or_reflection.to_sym + end + + join_associations.detect { |j| + j.reflection == name_or_reflection && j.parent == parent + } + end + + def remove_uniq_by_reflection(reflection, records) + if reflection && reflection.collection? + records.each { |record| record.send(reflection.name).target.uniq! } + end + end + + def build_join_association(reflection, parent) + JoinAssociation.new(reflection, self, parent) + end + + def construct(parent, associations, join_parts, row) + case associations + when Symbol, String + name = associations.to_s + + join_part = join_parts.detect { |j| + j.reflection.name.to_s == name && + j.parent_table_name == parent.class.table_name } + + raise(ConfigurationError, "No such association") unless join_part + + join_parts.delete(join_part) + construct_association(parent, join_part, row) + when Array + associations.each do |association| + construct(parent, association, join_parts, row) + end + when Hash + associations.sort_by { |k,_| k.to_s }.each do |name, assoc| + association = construct(parent, name, join_parts, row) + construct(association, assoc, join_parts, row) if association + end + else + raise ConfigurationError, associations.inspect + end + end + + def construct_association(record, join_part, row) + return if record.id.to_s != join_part.parent.record_id(row).to_s + + macro = join_part.reflection.macro + if macro == :has_one + return if record.instance_variable_defined?("@#{join_part.reflection.name}") + association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil? + set_target_and_inverse(join_part, association, record) + else + return if row[join_part.aliased_primary_key].nil? + association = join_part.instantiate(row) + case macro + when :has_many, :has_and_belongs_to_many + collection = record.send(join_part.reflection.name) + collection.loaded + collection.target.push(association) + collection.__send__(:set_inverse_instance, association, record) + when :belongs_to + set_target_and_inverse(join_part, association, record) + else + raise ConfigurationError, "unknown macro: #{join_part.reflection.macro}" + end + end + association + end + + def set_target_and_inverse(join_part, association, record) + association_proxy = record.send("set_#{join_part.reflection.name}_target", association) + association_proxy.__send__(:set_inverse_instance, association, record) + end + end + end + end +end diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb new file mode 100644 index 0000000000..5e5c01c77a --- /dev/null +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_association.rb @@ -0,0 +1,278 @@ +module ActiveRecord + module Associations + module ClassMethods + class JoinDependency # :nodoc: + class JoinAssociation < JoinPart # :nodoc: + # The reflection of the association represented + attr_reader :reflection + + # The JoinDependency object which this JoinAssociation exists within. This is mainly + # relevant for generating aliases which do not conflict with other joins which are + # part of the query. + attr_reader :join_dependency + + # A JoinBase instance representing the active record we are joining onto. + # (So in Author.has_many :posts, the Author would be that base record.) + attr_reader :parent + + # What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin + attr_accessor :join_type + + # These implement abstract methods from the superclass + attr_reader :aliased_prefix, :aliased_table_name + + delegate :options, :through_reflection, :source_reflection, :to => :reflection + delegate :table, :table_name, :to => :parent, :prefix => true + + def initialize(reflection, join_dependency, parent = nil) + reflection.check_validity! + + if reflection.options[:polymorphic] + raise EagerLoadPolymorphicError.new(reflection) + end + + super(reflection.klass) + + @reflection = reflection + @join_dependency = join_dependency + @parent = parent + @join_type = Arel::InnerJoin + + # This must be done eagerly upon initialisation because the alias which is produced + # depends on the state of the join dependency, but we want it to work the same way + # every time. + allocate_aliases + end + + def ==(other) + other.class == self.class && + other.reflection == reflection && + other.parent == parent + end + + def find_parent_in(other_join_dependency) + other_join_dependency.join_parts.detect do |join_part| + self.parent == join_part + end + end + + def join_to(relation) + send("join_#{reflection.macro}_to", relation) + end + + def join_relation(joining_relation) + self.join_type = Arel::OuterJoin + joining_relation.joins(self) + end + + def table + @table ||= Arel::Table.new( + table_name, :as => aliased_table_name, + :engine => arel_engine, :columns => active_record.columns + ) + end + + # More semantic name given we are talking about associations + alias_method :target_table, :table + + protected + + def aliased_table_name_for(name, suffix = nil) + if @join_dependency.table_aliases[name].zero? + @join_dependency.table_aliases[name] = @join_dependency.count_aliases_from_table_joins(name) + end + + if !@join_dependency.table_aliases[name].zero? # We need an alias + name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}" + @join_dependency.table_aliases[name] += 1 + if @join_dependency.table_aliases[name] == 1 # First time we've seen this name + # Also need to count the aliases from the table_aliases to avoid incorrect count + @join_dependency.table_aliases[name] += @join_dependency.count_aliases_from_table_joins(name) + end + table_index = @join_dependency.table_aliases[name] + name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index}" if table_index > 1 + else + @join_dependency.table_aliases[name] += 1 + end + + name + end + + def pluralize(table_name) + ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name + end + + def interpolate_sql(sql) + instance_eval("%@#{sql.gsub('@', '\@')}@", __FILE__, __LINE__) + end + + private + + def allocate_aliases + @aliased_prefix = "t#{ join_dependency.join_parts.size }" + @aliased_table_name = aliased_table_name_for(table_name) + + if reflection.macro == :has_and_belongs_to_many + @aliased_join_table_name = aliased_table_name_for(reflection.options[:join_table], "_join") + elsif [:has_many, :has_one].include?(reflection.macro) && reflection.options[:through] + @aliased_join_table_name = aliased_table_name_for(reflection.through_reflection.klass.table_name, "_join") + end + end + + def process_conditions(conditions, table_name) + Arel.sql(interpolate_sql(sanitize_sql(conditions, table_name))) + end + + def join_target_table(relation, *conditions) + relation = relation.join(target_table, join_type) + + # If the target table is an STI model then we must be sure to only include records of + # its type and its sub-types. + unless active_record.descends_from_active_record? + sti_column = target_table[active_record.inheritance_column] + + sti_condition = sti_column.eq(active_record.sti_name) + active_record.descendants.each do |subclass| + sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) + end + + conditions << sti_condition + end + + # If the reflection has conditions, add them + if options[:conditions] + conditions << process_conditions(options[:conditions], aliased_table_name) + end + + relation = relation.on(*conditions) + end + + def join_has_and_belongs_to_many_to(relation) + join_table = Arel::Table.new( + options[:join_table], :engine => arel_engine, + :as => @aliased_join_table_name + ) + + fk = options[:foreign_key] || reflection.active_record.to_s.foreign_key + klass_fk = options[:association_foreign_key] || reflection.klass.to_s.foreign_key + + relation = relation.join(join_table, join_type) + relation = relation.on( + join_table[fk]. + eq(parent_table[reflection.active_record.primary_key]) + ) + + join_target_table( + relation, + target_table[reflection.klass.primary_key]. + eq(join_table[klass_fk]) + ) + end + + def join_has_many_to(relation) + if reflection.options[:through] + join_has_many_through_to(relation) + elsif reflection.options[:as] + join_has_many_polymorphic_to(relation) + else + foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key + primary_key = options[:primary_key] || parent.primary_key + + join_target_table( + relation, + target_table[foreign_key]. + eq(parent_table[primary_key]) + ) + end + end + alias :join_has_one_to :join_has_many_to + + def join_has_many_through_to(relation) + join_table = Arel::Table.new( + through_reflection.klass.table_name, :engine => arel_engine, + :as => @aliased_join_table_name + ) + + jt_conditions = [] + jt_foreign_key = first_key = second_key = nil + + if through_reflection.options[:as] # has_many :through against a polymorphic join + as_key = through_reflection.options[:as].to_s + jt_foreign_key = as_key + '_id' + + jt_conditions << + join_table[as_key + '_type']. + eq(parent.active_record.base_class.name) + else + jt_foreign_key = through_reflection.primary_key_name + end + + case source_reflection.macro + when :has_many + second_key = options[:foreign_key] || primary_key + + if source_reflection.options[:as] + first_key = "#{source_reflection.options[:as]}_id" + else + first_key = through_reflection.klass.base_class.to_s.foreign_key + end + + unless through_reflection.klass.descends_from_active_record? + jt_conditions << + join_table[through_reflection.active_record.inheritance_column]. + eq(through_reflection.klass.sti_name) + end + when :belongs_to + first_key = primary_key + + if reflection.options[:source_type] + second_key = source_reflection.association_foreign_key + + jt_conditions << + join_table[reflection.source_reflection.options[:foreign_type]]. + eq(reflection.options[:source_type]) + else + second_key = source_reflection.primary_key_name + end + end + + jt_conditions << + parent_table[parent.primary_key]. + eq(join_table[jt_foreign_key]) + + if through_reflection.options[:conditions] + jt_conditions << process_conditions(through_reflection.options[:conditions], aliased_table_name) + end + + relation = relation.join(join_table, join_type).on(*jt_conditions) + + join_target_table( + relation, + target_table[first_key].eq(join_table[second_key]) + ) + end + + def join_has_many_polymorphic_to(relation) + join_target_table( + relation, + target_table["#{reflection.options[:as]}_id"]. + eq(parent_table[parent.primary_key]), + target_table["#{reflection.options[:as]}_type"]. + eq(parent.active_record.base_class.name) + ) + end + + def join_belongs_to_to(relation) + foreign_key = options[:foreign_key] || reflection.primary_key_name + primary_key = options[:primary_key] || reflection.klass.primary_key + + join_target_table( + relation, + target_table[primary_key].eq(parent_table[foreign_key]) + ) + end + end + end + end + end +end diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_base.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_base.rb new file mode 100644 index 0000000000..ed05003f66 --- /dev/null +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_base.rb @@ -0,0 +1,34 @@ +module ActiveRecord + module Associations + module ClassMethods + class JoinDependency # :nodoc: + class JoinBase < JoinPart # :nodoc: + # Extra joins provided when the JoinDependency was created + attr_reader :table_joins + + def initialize(active_record, joins = nil) + super(active_record) + @table_joins = joins + end + + def ==(other) + other.class == self.class && + other.active_record == active_record + end + + def aliased_prefix + "t0" + end + + def table + Arel::Table.new(table_name, :engine => arel_engine, :columns => active_record.columns) + end + + def aliased_table_name + active_record.table_name + end + end + end + end + end +end diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb new file mode 100644 index 0000000000..64d751344d --- /dev/null +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb @@ -0,0 +1,76 @@ +module ActiveRecord + module Associations + module ClassMethods + class JoinDependency # :nodoc: + # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited + # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which + # everything else is being joined onto. A JoinAssociation represents an association which + # is joining to the base. A JoinAssociation may result in more than one actual join + # operations (for example a has_and_belongs_to_many JoinAssociation would result in + # two; one for the join table and one for the target table). + class JoinPart # :nodoc: + # The Active Record class which this join part is associated 'about'; for a JoinBase + # this is the actual base model, for a JoinAssociation this is the target model of the + # association. + attr_reader :active_record + + delegate :table_name, :column_names, :primary_key, :reflections, :sanitize_sql, :arel_engine, :to => :active_record + + def initialize(active_record) + @active_record = active_record + @cached_record = {} + end + + def ==(other) + raise NotImplementedError + end + + # An Arel::Table for the active_record + def table + raise NotImplementedError + end + + # The prefix to be used when aliasing columns in the active_record's table + def aliased_prefix + raise NotImplementedError + end + + # The alias for the active_record's table + def aliased_table_name + raise NotImplementedError + end + + # The alias for the primary key of the active_record's table + def aliased_primary_key + "#{aliased_prefix}_r0" + end + + # An array of [column_name, alias] pairs for the table + def column_names_with_alias + unless defined?(@column_names_with_alias) + @column_names_with_alias = [] + + ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i| + @column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"] + end + end + + @column_names_with_alias + end + + def extract_record(row) + Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}] + end + + def record_id(row) + row[aliased_primary_key] + end + + def instantiate(row) + @cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row)) + end + end + end + end + end +end -- cgit v1.2.3 From 0687b21de879d53157e52a2b688e34a1bd1e31f0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 17:52:51 -0800 Subject: removing ternary --- activerecord/lib/active_record/associations/has_many_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 23831e0b08..156279a67a 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -42,7 +42,7 @@ module ActiveRecord # documented side-effect of the method that may avoid an extra SELECT. @target ||= [] and loaded if count == 0 - @reflection.options[:limit] ? [@reflection.options[:limit], count].min : count + [@reflection.options[:limit], count].compact.min end def has_cached_counter? -- cgit v1.2.3 From e39138478b38d7a5e0a13756b1bdfa8b43226846 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Wed, 24 Nov 2010 10:10:38 +0100 Subject: port_string bought back to life as it is part of the public api MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/http/url.rb | 11 ++++++++--- actionpack/test/dispatch/request_test.rb | 10 +++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 1f7633cbea..1e7054f381 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -52,8 +52,7 @@ module ActionDispatch # Returns a \host:\port string for this request, such as "example.com" or # "example.com:8080". def host_with_port - opt_port = optional_port ? ":#{optional_port}" : nil - "#{host}#{opt_port}" + "#{host}#{port_string}" end # Returns the port number of this request as an integer. @@ -80,12 +79,18 @@ module ActionDispatch port == standard_port end - # Returns a \port suffix like "8080" if the \port number of this request + # Returns a number \port suffix like 8080 if the \port number of this request # is not the default HTTP \port 80 or HTTPS \port 443. def optional_port standard_port? ? nil : port end + # Returns a string \port suffix, including colon, like ":8080" if the \port + # number of this request is not the default HTTP \port 80 or HTTPS \port 443. + def port_string + standard_port? ? '' : ":#{port}" + end + def server_port @env['SERVER_PORT'].to_i end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index d140ea8358..8f672c1149 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -172,6 +172,14 @@ class RequestTest < ActiveSupport::TestCase assert_equal 8080, request.optional_port end + test "port string" do + request = stub_request 'HTTP_HOST' => 'www.example.org:80' + assert_equal '', request.port_string + + request = stub_request 'HTTP_HOST' => 'www.example.org:8080' + assert_equal ':8080', request.port_string + end + test "full path" do request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri', 'QUERY_STRING' => 'mapped=1' assert_equal "/path/of/some/uri?mapped=1", request.fullpath @@ -392,7 +400,7 @@ class RequestTest < ActiveSupport::TestCase mock_rack_env = { "QUERY_STRING" => "x[y]=1&x[y][][w]=2", "rack.input" => "foo" } request = nil begin - request = stub_request(mock_rack_env) + request = stub_request(mock_rack_env) request.parameters rescue TypeError => e # rack will raise a TypeError when parsing this query string -- cgit v1.2.3 From 8624065bffd203e1f590ca431d468f9b38e9fb7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 24 Nov 2010 12:38:52 +0100 Subject: Allow template handlers to store temp data. --- actionpack/lib/action_view/template.rb | 5 +++++ actionpack/test/template/lookup_context_test.rb | 29 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 6c6d659246..831a19654e 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -184,6 +184,11 @@ module ActionView end end + # Used to store template data by template handlers. + def data + @data ||= {} + end + def inspect @inspect ||= if defined?(Rails.root) diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb index 6d3b26e131..c9dd27cf2a 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionpack/test/template/lookup_context_test.rb @@ -180,6 +180,16 @@ class LookupContextTest < ActiveSupport::TestCase assert_not_equal template, old_template end + + test "data can be stored in cached templates" do + template = @lookup_context.find("hello_world", "test") + template.data["cached"] = "data" + assert_equal "Hello world!", template.source + + template = @lookup_context.find("hello_world", "test") + assert_equal "data", template.data["cached"] + assert_equal "Hello world!", template.source + end end class LookupContextWithFalseCaching < ActiveSupport::TestCase @@ -205,7 +215,7 @@ class LookupContextWithFalseCaching < ActiveSupport::TestCase assert_equal "Bar", template.source end - test "if no template was found in the second lookup, give it higher preference" do + test "if no template was found in the second lookup, with no cache, raise error" do template = @lookup_context.find("foo", "test", true) assert_equal "Foo", template.source @@ -215,7 +225,7 @@ class LookupContextWithFalseCaching < ActiveSupport::TestCase end end - test "if no template was cached in the first lookup, do not use the cache in the second" do + test "if no template was cached in the first lookup, retrieval should work in the second call" do @resolver.hash.clear assert_raise ActionView::MissingTemplate do @lookup_context.find("foo", "test", true) @@ -225,4 +235,19 @@ class LookupContextWithFalseCaching < ActiveSupport::TestCase template = @lookup_context.find("foo", "test", true) assert_equal "Foo", template.source end + + test "data can be stored as long as template was not updated" do + template = @lookup_context.find("foo", "test", true) + template.data["cached"] = "data" + assert_equal "Foo", template.source + + template = @lookup_context.find("foo", "test", true) + assert_equal "data", template.data["cached"] + assert_equal "Foo", template.source + + @resolver.hash["test/_foo.erb"][1] = Time.now.utc + template = @lookup_context.find("foo", "test", true) + assert_nil template.data["cached"] + assert_equal "Foo", template.source + end end \ No newline at end of file -- cgit v1.2.3 From 47f39d26a76430ad50dae79f212d118849b2af40 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Wed, 24 Nov 2010 16:32:02 +0800 Subject: Testing that dup is resetting the timestamps --- activerecord/test/cases/dup_test.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb index 46abe7792c..0236f9b0a1 100644 --- a/activerecord/test/cases/dup_test.rb +++ b/activerecord/test/cases/dup_test.rb @@ -51,7 +51,12 @@ module ActiveRecord topic.attributes = dbtopic.attributes + #duped has no timestamp values duped = dbtopic.dup + + #clear topic timestamp values + topic.send(:clear_timestamp_attributes) + assert_equal topic.changes, duped.changes end @@ -75,5 +80,24 @@ module ActiveRecord assert_equal 'Aaron', topic.author_name assert_equal 'meow', duped.author_name end + + def test_dup_timestamps_are_cleared + topic = Topic.first + assert_not_nil topic.updated_at + assert_not_nil topic.created_at + + # temporary change to the topic object + topic.updated_at -= 3.days + + #dup should not preserve the timestamps if present + new_topic = topic.dup + assert_nil new_topic.updated_at + assert_nil new_topic.created_at + + new_topic.save + assert_not_nil new_topic.updated_at + assert_not_nil new_topic.created_at + end + end end -- cgit v1.2.3 From c17cb7326d6af7c4226e955abd3f89db95fabb33 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Wed, 24 Nov 2010 16:32:41 +0800 Subject: Dup should reset the timestamps as it is considered a new record --- activerecord/lib/active_record/base.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index d2fa3bed35..49b30f4779 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1625,6 +1625,7 @@ MSG ensure_proper_type populate_with_current_scope_attributes + clear_timestamp_attributes end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back @@ -1831,6 +1832,16 @@ MSG create_with.each { |att,value| self.respond_to?(:"#{att}=") && self.send("#{att}=", value) } if create_with end end + + # Clear attributes and changged_attributes + def clear_timestamp_attributes + %w(created_at created_on updated_at updated_on).each do |attribute_name| + if self.has_attribute?(attribute_name) + self[attribute_name] = nil + self.changed_attributes.delete(attribute_name) + end + end + end end Base.class_eval do -- cgit v1.2.3 From 7b77a1fc71e54f6e42e97b426380303d696051c0 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Thu, 25 Nov 2010 02:53:28 +0800 Subject: Typo in the comments of the clear_timestamp_attributes method --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 49b30f4779..1e0fd7c6fd 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1833,7 +1833,7 @@ MSG end end - # Clear attributes and changged_attributes + # Clear attributes and changed_attributes def clear_timestamp_attributes %w(created_at created_on updated_at updated_on).each do |attribute_name| if self.has_attribute?(attribute_name) -- cgit v1.2.3 From 7f8ce38b0d294b5c5d38116f8de63f175f446bd4 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Thu, 25 Nov 2010 02:54:59 +0800 Subject: Document the behavior of the dup method: does not preserve timestamps --- activerecord/lib/active_record/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 1e0fd7c6fd..b7aac7a7c9 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1605,6 +1605,7 @@ MSG # only, not its associations. The extent of a "deep" copy is application # specific and is therefore left to the application to implement according # to its need. + # The dup method does not preserve the timestamps (created|updated)_(at|on). def initialize_dup(other) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) -- cgit v1.2.3 From c6030e8562cddcb71898a1dea242affe5f0464f0 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Tue, 23 Nov 2010 22:40:41 +0800 Subject: Remove the not needed setup and teardown --- actionpack/test/controller/mime_responds_test.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 0da051822a..8e7d8056a0 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -169,9 +169,6 @@ end class StarStarMimeControllerTest < ActionController::TestCase tests StarStarMimeController - def setup; super; end - def teardown; super; end - def test_javascript_with_format @request.accept = "text/javascript" get :index, :format => 'js' -- cgit v1.2.3 From e8708836252852d8bae87c80472b865812fa9776 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Tue, 23 Nov 2010 23:28:57 +0800 Subject: unregister method implementation and test --- actionpack/lib/action_dispatch/http/mime_type.rb | 12 ++++++++++++ actionpack/test/dispatch/mime_type_test.rb | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 2250cfa88a..2b8395fc09 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -177,6 +177,18 @@ module Mime keys = Mime::LOOKUP.keys.select{|k| k.include?(input)} Mime::LOOKUP.values_at(*keys).uniq end + + # This method is opposite of register method. + # + # Usage: + # + # Mime::Type.unregister("text/x-mobile", :mobile) + def unregister(string, symbol) + EXTENSION_LOOKUP.delete(symbol.to_s) + LOOKUP.delete(string) + symbol = symbol.to_s.upcase.intern + Mime.module_eval { remove_const(symbol) if const_defined?(symbol) } + end end def initialize(string, symbol = nil, synonyms = []) diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 43123e68b2..f2d2799a67 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -12,6 +12,23 @@ class MimeTypeTest < ActiveSupport::TestCase end end + test "unregister" do + begin + Mime::Type.register("text/x-mobile", :mobile) + assert defined?(Mime::MOBILE) + assert_equal Mime::MOBILE, Mime::LOOKUP['text/x-mobile'] + assert_equal Mime::MOBILE, Mime::EXTENSION_LOOKUP['mobile'] + + Mime::Type.unregister("text/x-mobile", :mobile) + assert !defined?(Mime::MOBILE), "Mime::MOBILE should not be defined" + assert !Mime::LOOKUP.has_key?('text/x-mobile'), "Mime::LOOKUP should not have key ['text/x-mobile]" + assert !Mime::EXTENSION_LOOKUP.has_key?('mobile'), "Mime::EXTENSION_LOOKUP should not have key ['mobile]" + ensure + Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } + Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} + end + end + test "parse text with trailing star" do accept = "text/*" expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT].sort_by(&:to_s) -- cgit v1.2.3 From b52a6ba16914d29785e751011e91d7bb91a2356d Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Tue, 23 Nov 2010 23:49:15 +0800 Subject: clean up test by using unregister method --- actionpack/test/controller/mime_responds_test.rb | 18 ++++++------------ actionpack/test/dispatch/mime_type_test.rb | 3 +-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 8e7d8056a0..8315f90fee 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -201,10 +201,8 @@ class RespondToControllerTest < ActionController::TestCase def teardown super - Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } - Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } - Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} - Mime::LOOKUP.reject!{|key,_| key == 'text/iphone'} + Mime::Type.unregister('text/x-mobile', :iphone) + Mime::Type.unregister('text/iphone', :mobile) end def test_html @@ -617,10 +615,8 @@ class RespondWithControllerTest < ActionController::TestCase def teardown super - Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } - Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } - Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} - Mime::LOOKUP.reject!{|key,_| key == 'text/iphone'} + Mime::Type.unregister('text/x-mobile', :iphone) + Mime::Type.unregister('text/iphone', :mobile) end def test_using_resource @@ -1006,10 +1002,8 @@ class MimeControllerLayoutsTest < ActionController::TestCase def teardown super - Mime.module_eval { remove_const :IPHONE if const_defined?(:IPHONE) } - Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } - Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} - Mime::LOOKUP.reject!{|key,_| key == 'text/iphone'} + Mime::Type.unregister('text/x-mobile', :iphone) + Mime::Type.unregister('text/iphone', :mobile) end def test_missing_layout_renders_properly diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index f2d2799a67..bf44cb95fa 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -85,8 +85,7 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal Mime::GIF, Mime::SET.last end ensure - Mime.module_eval { remove_const :GIF if const_defined?(:GIF) } - Mime::LOOKUP.reject!{|key,_| key == 'image/gif'} + Mime::Type.unregister('image/gif', :gif) end end -- cgit v1.2.3 From 5c9abb6cca4b6de7146c94779a34ae943e4ea4d8 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 25 Nov 2010 01:19:43 +0800 Subject: processing image/* is an odditity because there is a test case which expects image/* to not to be expanded. So I am leaving image/* as it is and process only text/* and application/* --- actionpack/lib/action_dispatch/http/mime_type.rb | 2 +- actionpack/test/dispatch/mime_type_test.rb | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 2b8395fc09..5ea49a23c7 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -81,7 +81,7 @@ module Mime class << self - TRAILING_STAR_REGEXP = /(\w+)\/\*/ + TRAILING_STAR_REGEXP = /(text|application)\/\*/ def lookup(string) LOOKUP[string] diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index bf44cb95fa..25e106f519 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -45,12 +45,6 @@ class MimeTypeTest < ActiveSupport::TestCase assert_equal expect, parsed.sort_by(&:to_s) end - test "parse image with trailing star" do - accept = "image/*" - parsed = Mime::Type.parse(accept) - assert parsed.include?(Mime::PNG) - end - test "parse without q" do accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*" expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::TEXT, Mime::PDF, Mime::ALL] -- cgit v1.2.3 From 18adbe9347727dc3eefe46395d52aafa347a0c73 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 25 Nov 2010 01:24:45 +0800 Subject: process text/* if it appears in the middle of HTTP_ACCEPT parameter --- actionpack/lib/action_dispatch/http/mime_type.rb | 6 +++++- actionpack/test/dispatch/mime_type_test.rb | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 5ea49a23c7..08eab5634a 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -120,7 +120,11 @@ module Mime params, q = header.split(/;\s*q=/) if params params.strip! - list << AcceptItem.new(index, params, q) unless params.empty? + if params =~ TRAILING_STAR_REGEXP + parse_data_with_trailing_star($1).each { |m| list << AcceptItem.new(index, m.to_s, q) } + else + list << AcceptItem.new(index, params, q) unless params.empty? + end end end list.sort! diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 25e106f519..9424d88498 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -29,6 +29,26 @@ class MimeTypeTest < ActiveSupport::TestCase end end + test "parse text with trailing star at the beginning" do + accept = "text/*, text/html, application/json, multipart/form-data" + expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::TEXT, Mime::YAML, Mime::JS, Mime::MULTIPART_FORM] + parsed = Mime::Type.parse(accept) + assert_equal expect.size, parsed.size + Range.new(0,expect.size-1).to_a.each do |index| + assert_equal expect[index], parsed[index], "Failed for index number #{index}" + end + end + + test "parse text with trailing star in the end" do + accept = "text/html, application/json, multipart/form-data, text/*" + expect = [Mime::HTML, Mime::JSON, Mime::MULTIPART_FORM, Mime::XML, Mime::ICS, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT] + parsed = Mime::Type.parse(accept) + assert_equal 10, parsed.size + Range.new(0,expect.size-1).to_a.each do |index| + assert_equal expect[index], parsed[index], "Failed for index number #{index}" + end + end + test "parse text with trailing star" do accept = "text/*" expect = [Mime::JSON, Mime::XML, Mime::ICS, Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT].sort_by(&:to_s) -- cgit v1.2.3 From 66212f69acc3d51af10ff76a18ff4c0bfa305ea5 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Thu, 11 Nov 2010 11:41:15 -0500 Subject: If a nested_attribute is being marked for destruction and at the same time an attr_accessor value is being assigned then the value being assigned is being ignored. This patch is a fix for that issue. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#5939 state:resolved] Signed-off-by: José Valim --- activerecord/lib/active_record/nested_attributes.rb | 7 ++----- activerecord/test/cases/nested_attributes_test.rb | 15 ++++++++++++++- activerecord/test/models/pet.rb | 8 ++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 15f83a8579..050b521b6a 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -417,11 +417,8 @@ module ActiveRecord # Updates a record with the +attributes+ or marks it for destruction if # +allow_destroy+ is +true+ and has_destroy_flag? returns +true+. def assign_to_or_mark_for_destruction(record, attributes, allow_destroy) - if has_destroy_flag?(attributes) && allow_destroy - record.mark_for_destruction - else - record.attributes = attributes.except(*UNASSIGNABLE_KEYS) - end + record.attributes = attributes.except(*UNASSIGNABLE_KEYS) + record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy end # Determines if a hash contains a truthy _destroy key. diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 92af53d56f..fb6a239545 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -827,7 +827,7 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase fixtures :owners, :pets def setup - Owner.accepts_nested_attributes_for :pets + Owner.accepts_nested_attributes_for :pets, :allow_destroy => true @owner = owners(:ashley) @pet1, @pet2 = pets(:chew), pets(:mochi) @@ -844,6 +844,19 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase @owner.update_attributes(@params) assert_equal ['Foo', 'Bar'], @owner.pets.map(&:name) end + + def test_attr_accessor_of_child_should_be_value_provided_during_update_attributes + @owner = owners(:ashley) + @pet1 = pets(:chew) + assert_equal nil, $current_user + attributes = {:pets_attributes => { "1"=> { :id => @pet1.id, + :name => "Foo2", + :current_user => "John", + :_destroy=>true }}} + @owner.update_attributes(attributes) + assert_equal 'John', $after_destroy_callback_output + end + end class TestHasOneAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase diff --git a/activerecord/test/models/pet.rb b/activerecord/test/models/pet.rb index a8bf94dd86..570db4c8d5 100644 --- a/activerecord/test/models/pet.rb +++ b/activerecord/test/models/pet.rb @@ -1,5 +1,13 @@ class Pet < ActiveRecord::Base + + attr_accessor :current_user + set_primary_key :pet_id belongs_to :owner, :touch => true has_many :toys + + after_destroy do |record| + $after_destroy_callback_output = record.current_user + end + end -- cgit v1.2.3 From fa2a5ae0339c90d023a7559e681a588219dc3903 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 15 Nov 2010 17:52:39 -0500 Subject: If a user wants json output then try best to render json output. In such cases prefer kind_of(String) over respond_to?(to_str) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [#5841 state:resolved] Signed-off-by: José Valim --- actionpack/lib/action_controller/metal/renderers.rb | 2 +- actionpack/test/controller/mime_responds_test.rb | 18 ++++++++++++++++++ actionpack/test/lib/controller/fake_models.rb | 6 ++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 67cf08445d..d6f6ab1855 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -55,7 +55,7 @@ module ActionController end add :json do |json, options| - json = json.to_json(options) unless json.respond_to?(:to_str) + json = json.to_json(options) unless json.kind_of?(String) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? self.content_type ||= Mime::JSON self.response_body = json diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index 8315f90fee..82969b2979 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -599,6 +599,17 @@ class InheritedRespondWithController < RespondWithController end end +class RenderJsonRespondWithController < RespondWithController + clear_respond_to + respond_to :json + + def index + respond_with(resource) do |format| + format.json { render :json => RenderJsonTestException.new('boom') } + end + end +end + class EmptyRespondWithController < ActionController::Base def index respond_with(Customer.new("david", 13)) @@ -914,6 +925,13 @@ class RespondWithControllerTest < ActionController::TestCase assert_equal "JSON", @response.body end + def test_render_json_object_responds_to_str_still_produce_json + @controller = RenderJsonRespondWithController.new + @request.accept = "application/json" + get :index, :format => :json + assert_equal %Q{{"message":"boom","error":"RenderJsonTestException"}}, @response.body + end + def test_no_double_render_is_raised @request.accept = "text/html" assert_raise ActionView::MissingTemplate do diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index ae0c38184d..bd18cdc1b8 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -194,3 +194,9 @@ class ArelLike a.each { |i| yield i } end end + +class RenderJsonTestException < Exception + def to_json(options = nil) + return { :error => self.class.name, :message => self.to_str }.to_json + end +end -- cgit v1.2.3 From a3ba60fd814a980cc929fcbe0f9d48fa4d0292e5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 18:08:23 -0800 Subject: reduce method calls --- activerecord/lib/active_record/associations/has_many_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 156279a67a..685d818ab3 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -108,7 +108,7 @@ module ActiveRecord end def we_can_set_the_inverse_on_this?(record) - !@reflection.inverse_of.nil? + @reflection.inverse_of end end end -- cgit v1.2.3 From d4b8d3bafa54e233d3f1ef43c43bfb460d9f2435 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 13:29:18 -0800 Subject: moving column_aliases to JoinDependency --- .../associations/class_methods/join_dependency.rb | 8 ++++++++ activerecord/lib/active_record/relation/finder_methods.rb | 11 +---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb index 79fdb2d4cb..87541e0529 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -33,6 +33,14 @@ module ActiveRecord join_parts.first end + def columns(connection) + join_parts.collect { |join_part| + join_part.column_names_with_alias.collect{ |column_name, aliased_name| + "#{connection.quote_table_name join_part.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}" + } + }.flatten.join(", ") + end + def count_aliases_from_table_joins(name) # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase quoted_name = join_base.active_record.connection.quote_table_name(name.downcase).downcase diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 4192456447..74ec83091c 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -202,7 +202,7 @@ module ActiveRecord end def construct_relation_for_association_find(join_dependency) - relation = except(:includes, :eager_load, :preload, :select).select(column_aliases(join_dependency)) + relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns(connection)) apply_join_dependency(relation, join_dependency) end @@ -349,17 +349,8 @@ module ActiveRecord end end - def column_aliases(join_dependency) - join_dependency.join_parts.collect { |join_part| - join_part.column_names_with_alias.collect{ |column_name, aliased_name| - "#{connection.quote_table_name join_part.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}" - } - }.flatten.join(", ") - end - def using_limitable_reflections?(reflections) reflections.none? { |r| r.collection? } end - end end -- cgit v1.2.3 From afe51afcc6b7c0245fddbd879d369818b54e460a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 13:32:01 -0800 Subject: remove useless join --- .../lib/active_record/associations/class_methods/join_dependency.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb index 87541e0529..7c7fa964f8 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -38,7 +38,7 @@ module ActiveRecord join_part.column_names_with_alias.collect{ |column_name, aliased_name| "#{connection.quote_table_name join_part.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}" } - }.flatten.join(", ") + }.flatten end def count_aliases_from_table_joins(name) -- cgit v1.2.3 From cdf6cf01cb47bdcbc1e011c8f5f72b161f12bf9c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 13:40:23 -0800 Subject: use ARel rather than generate SQL strings --- .../lib/active_record/associations/class_methods/join_dependency.rb | 5 +++-- activerecord/lib/active_record/relation/finder_methods.rb | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb index 7c7fa964f8..b1521b3706 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -33,10 +33,11 @@ module ActiveRecord join_parts.first end - def columns(connection) + def columns join_parts.collect { |join_part| + table = Arel::Nodes::TableAlias.new join_part.aliased_table_name, nil join_part.column_names_with_alias.collect{ |column_name, aliased_name| - "#{connection.quote_table_name join_part.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}" + table[column_name].as aliased_name } }.flatten end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 74ec83091c..23ae0b4325 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -202,7 +202,7 @@ module ActiveRecord end def construct_relation_for_association_find(join_dependency) - relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns(connection)) + relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns) apply_join_dependency(relation, join_dependency) end -- cgit v1.2.3 From 34d21b87bb237bf55214bd476be71116a2a5258f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 13:53:55 -0800 Subject: adding a factory method to the join part for generating a table alias --- .../lib/active_record/associations/class_methods/join_dependency.rb | 2 +- .../associations/class_methods/join_dependency/join_part.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb index b1521b3706..19d2d55ca0 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -35,7 +35,7 @@ module ActiveRecord def columns join_parts.collect { |join_part| - table = Arel::Nodes::TableAlias.new join_part.aliased_table_name, nil + table = join_part.aliased_table join_part.column_names_with_alias.collect{ |column_name, aliased_name| table[column_name].as aliased_name } diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb index 64d751344d..5d55ca202e 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb @@ -21,6 +21,10 @@ module ActiveRecord @cached_record = {} end + def aliased_table + Arel::Nodes::TableAlias.new aliased_table_name, table + end + def ==(other) raise NotImplementedError end -- cgit v1.2.3 From 38eb01863c9281d142c6494bae485b9c215ec9b7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 14:11:12 -0800 Subject: initialize instance variables in initialize... o_O --- .../associations/class_methods/join_dependency/join_part.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb index 5d55ca202e..0b093b65e9 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency/join_part.rb @@ -19,6 +19,7 @@ module ActiveRecord def initialize(active_record) @active_record = active_record @cached_record = {} + @column_names_with_alias = nil end def aliased_table @@ -51,14 +52,13 @@ module ActiveRecord # An array of [column_name, alias] pairs for the table def column_names_with_alias - unless defined?(@column_names_with_alias) + unless @column_names_with_alias @column_names_with_alias = [] ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i| @column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"] end end - @column_names_with_alias end -- cgit v1.2.3 From ee74f2c6238dbaca00e9b667c3c239f3cae8aca5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 14:16:38 -0800 Subject: alias should be a SQL literal --- .../lib/active_record/associations/class_methods/join_dependency.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb index 19d2d55ca0..6ab7bd0b06 100644 --- a/activerecord/lib/active_record/associations/class_methods/join_dependency.rb +++ b/activerecord/lib/active_record/associations/class_methods/join_dependency.rb @@ -37,7 +37,7 @@ module ActiveRecord join_parts.collect { |join_part| table = join_part.aliased_table join_part.column_names_with_alias.collect{ |column_name, aliased_name| - table[column_name].as aliased_name + table[column_name].as Arel.sql(aliased_name) } }.flatten end -- cgit v1.2.3 From d8692985feb4db9fe8d113549535b658fe6058e5 Mon Sep 17 00:00:00 2001 From: raggi Date: Thu, 25 Nov 2010 06:21:55 +0800 Subject: Don't depend on rubygems loading thread (for Mutex) --- .../lib/active_record/connection_adapters/abstract/connection_pool.rb | 1 + activerecord/test/cases/locking_test.rb | 1 + activesupport/lib/active_support/core_ext/module/synchronization.rb | 1 + activesupport/test/core_ext/module/synchronization_test.rb | 1 + 4 files changed, 4 insertions(+) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index ca9314ec99..cffa2387de 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -1,3 +1,4 @@ +require 'thread' require 'monitor' require 'set' require 'active_support/core_ext/module/synchronization' diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 4ddcdc010b..f9678cb0c5 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -1,3 +1,4 @@ +require 'thread' require "cases/helper" require 'models/person' require 'models/reader' diff --git a/activesupport/lib/active_support/core_ext/module/synchronization.rb b/activesupport/lib/active_support/core_ext/module/synchronization.rb index 38ce55f26e..ed16c2f71b 100644 --- a/activesupport/lib/active_support/core_ext/module/synchronization.rb +++ b/activesupport/lib/active_support/core_ext/module/synchronization.rb @@ -1,3 +1,4 @@ +require 'thread' require 'active_support/core_ext/module/aliasing' require 'active_support/core_ext/array/extract_options' diff --git a/activesupport/test/core_ext/module/synchronization_test.rb b/activesupport/test/core_ext/module/synchronization_test.rb index eb850893f0..6c407e2260 100644 --- a/activesupport/test/core_ext/module/synchronization_test.rb +++ b/activesupport/test/core_ext/module/synchronization_test.rb @@ -1,3 +1,4 @@ +require 'thread' require 'abstract_unit' require 'active_support/core_ext/class/attribute_accessors' -- cgit v1.2.3 From cb1570936d70d624f72229c8a19ffbe3a10cc5ca Mon Sep 17 00:00:00 2001 From: raggi Date: Thu, 25 Nov 2010 04:03:04 +0800 Subject: Rakefiles are executables, and rake loads rake, not rakefile code --- Rakefile | 2 +- actionmailer/Rakefile | 2 +- actionpack/Rakefile | 2 +- activemodel/Rakefile | 0 activerecord/Rakefile | 2 +- activeresource/Rakefile | 2 +- activesupport/Rakefile | 0 railties/Rakefile | 2 +- railties/lib/rails/generators/rails/app/templates/Rakefile | 2 +- railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt | 2 +- railties/lib/rails/generators/rails/plugin_new/templates/Rakefile | 4 +--- 11 files changed, 9 insertions(+), 11 deletions(-) mode change 100644 => 100755 Rakefile mode change 100644 => 100755 actionmailer/Rakefile mode change 100644 => 100755 actionpack/Rakefile mode change 100644 => 100755 activemodel/Rakefile mode change 100644 => 100755 activerecord/Rakefile mode change 100644 => 100755 activeresource/Rakefile mode change 100644 => 100755 activesupport/Rakefile mode change 100644 => 100755 railties/Rakefile mode change 100644 => 100755 railties/lib/rails/generators/rails/app/templates/Rakefile mode change 100644 => 100755 railties/lib/rails/generators/rails/plugin_new/templates/Rakefile diff --git a/Rakefile b/Rakefile old mode 100644 new mode 100755 index 8c72312f28..1f3c770c77 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ +#!/usr/bin/env rake gem 'rdoc', '>= 2.5.10' require 'rdoc' -require 'rake' require 'rdoc/task' require 'net/http' diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile old mode 100644 new mode 100755 index cba6e93c8a..123ef9bbbf --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -1,4 +1,4 @@ -require 'rake' +#!/usr/bin/env rake require 'rake/testtask' require 'rake/packagetask' require 'rake/gempackagetask' diff --git a/actionpack/Rakefile b/actionpack/Rakefile old mode 100644 new mode 100755 index a6ce08113f..9030db9f7a --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -1,4 +1,4 @@ -require 'rake' +#!/usr/bin/env rake require 'rake/testtask' require 'rake/packagetask' require 'rake/gempackagetask' diff --git a/activemodel/Rakefile b/activemodel/Rakefile old mode 100644 new mode 100755 diff --git a/activerecord/Rakefile b/activerecord/Rakefile old mode 100644 new mode 100755 index 395c72dfbc..f9b77c1799 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -1,4 +1,4 @@ -require 'rake' +#!/usr/bin/env rake require 'rake/testtask' require 'rake/packagetask' require 'rake/gempackagetask' diff --git a/activeresource/Rakefile b/activeresource/Rakefile old mode 100644 new mode 100755 index 905241acc0..cf01bc1389 --- a/activeresource/Rakefile +++ b/activeresource/Rakefile @@ -1,4 +1,4 @@ -require 'rake' +#!/usr/bin/env rake require 'rake/testtask' require 'rake/packagetask' require 'rake/gempackagetask' diff --git a/activesupport/Rakefile b/activesupport/Rakefile old mode 100644 new mode 100755 diff --git a/railties/Rakefile b/railties/Rakefile old mode 100644 new mode 100755 index 9504661c0e..5137bee761 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -1,4 +1,4 @@ -require 'rake' +#!/usr/bin/env rake require 'rake/testtask' require 'rake/gempackagetask' diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile old mode 100644 new mode 100755 index d83cafc3be..4dc1023f1f --- a/railties/lib/rails/generators/rails/app/templates/Rakefile +++ b/railties/lib/rails/generators/rails/app/templates/Rakefile @@ -1,7 +1,7 @@ +#!/usr/bin/env rake # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) -require 'rake' <%= app_const %>.load_tasks diff --git a/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt index 733e321c94..77149ae351 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt @@ -1,4 +1,4 @@ -require 'rake' +#!/usr/bin/env rake require 'rake/testtask' require 'rake/rdoctask' diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile old mode 100644 new mode 100755 index 88f50f9f04..12350309bf --- a/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Rakefile @@ -1,12 +1,10 @@ -# encoding: UTF-8 -require 'rubygems' +#!/usr/bin/env rake begin require 'bundler/setup' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end -require 'rake' require 'rake/rdoctask' Rake::RDocTask.new(:rdoc) do |rdoc| -- cgit v1.2.3 From ad8e1ba45271ad910ba943840f6f58e973e9a046 Mon Sep 17 00:00:00 2001 From: Cheah Chu Yeow Date: Thu, 25 Nov 2010 16:11:26 +0800 Subject: Fix missing word in ActionMailer::Base documentation. --- actionmailer/lib/action_mailer/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 0bf60a2c24..1c2949f375 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -234,8 +234,8 @@ module ActionMailer #:nodoc: # default :sender => 'system@example.com' # end # - # You can pass in any header value that a Mail::Message, out of the box, ActionMailer::Base - # sets the following: + # You can pass in any header value that a Mail::Message accepts. Out of the box, + # ActionMailer::Base sets the following: # # * :mime_version => "1.0" # * :charset => "UTF-8", -- cgit v1.2.3 From 90b0f6149160e6fedb12ea54f713ec3399bebec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 25 Nov 2010 10:44:42 +0100 Subject: #:nodoc: internal methods. --- actionpack/lib/action_dispatch/routing/mapper.rb | 62 ++++++++++++------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 879ccc5791..0b5437bd4f 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -707,61 +707,61 @@ module ActionDispatch end private - def scope_options + def scope_options #:nodoc: @scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym } end - def merge_path_scope(parent, child) + def merge_path_scope(parent, child) #:nodoc: Mapper.normalize_path("#{parent}/#{child}") end - def merge_shallow_path_scope(parent, child) + def merge_shallow_path_scope(parent, child) #:nodoc: Mapper.normalize_path("#{parent}/#{child}") end - def merge_as_scope(parent, child) + def merge_as_scope(parent, child) #:nodoc: parent ? "#{parent}_#{child}" : child end - def merge_shallow_prefix_scope(parent, child) + def merge_shallow_prefix_scope(parent, child) #:nodoc: parent ? "#{parent}_#{child}" : child end - def merge_module_scope(parent, child) + def merge_module_scope(parent, child) #:nodoc: parent ? "#{parent}/#{child}" : child end - def merge_controller_scope(parent, child) + def merge_controller_scope(parent, child) #:nodoc: child end - def merge_path_names_scope(parent, child) + def merge_path_names_scope(parent, child) #:nodoc: merge_options_scope(parent, child) end - def merge_constraints_scope(parent, child) + def merge_constraints_scope(parent, child) #:nodoc: merge_options_scope(parent, child) end - def merge_defaults_scope(parent, child) + def merge_defaults_scope(parent, child) #:nodoc: merge_options_scope(parent, child) end - def merge_blocks_scope(parent, child) + def merge_blocks_scope(parent, child) #:nodoc: merged = parent ? parent.dup : [] merged << child if child merged end - def merge_options_scope(parent, child) + def merge_options_scope(parent, child) #:nodoc: (parent || {}).except(*override_keys(child)).merge(child) end - def merge_shallow_scope(parent, child) + def merge_shallow_scope(parent, child) #:nodoc: child ? true : false end - def override_keys(child) + def override_keys(child) #:nodoc: child.key?(:only) || child.key?(:except) ? [:only, :except] : [] end end @@ -1167,7 +1167,7 @@ module ActionDispatch @scope[:scope_level_resource] end - def apply_common_behavior_for(method, resources, options, &block) + def apply_common_behavior_for(method, resources, options, &block) #:nodoc: if resources.length > 1 resources.each { |r| send(method, r, options, &block) } return true @@ -1197,23 +1197,23 @@ module ActionDispatch false end - def action_options?(options) + def action_options?(options) #:nodoc: options[:only] || options[:except] end - def scope_action_options? + def scope_action_options? #:nodoc: @scope[:options].is_a?(Hash) && (@scope[:options][:only] || @scope[:options][:except]) end - def scope_action_options + def scope_action_options #:nodoc: @scope[:options].slice(:only, :except) end - def resource_scope? + def resource_scope? #:nodoc: [:resource, :resources].include?(@scope[:scope_level]) end - def resource_method_scope? + def resource_method_scope? #:nodoc: [:collection, :member, :new].include?(@scope[:scope_level]) end @@ -1239,7 +1239,7 @@ module ActionDispatch @scope[:scope_level_resource] = old_resource end - def resource_scope(resource) + def resource_scope(resource) #:nodoc: with_scope_level(resource.is_a?(SingletonResource) ? :resource : :resources, resource) do scope(parent_resource.resource_scope) do yield @@ -1247,30 +1247,30 @@ module ActionDispatch end end - def nested_options + def nested_options #:nodoc: {}.tap do |options| options[:as] = parent_resource.member_name options[:constraints] = { "#{parent_resource.singular}_id".to_sym => id_constraint } if id_constraint? end end - def id_constraint? + def id_constraint? #:nodoc: @scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp) end - def id_constraint + def id_constraint #:nodoc: @scope[:constraints][:id] end - def canonical_action?(action, flag) + def canonical_action?(action, flag) #:nodoc: flag && resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s) end - def shallow_scoping? + def shallow_scoping? #:nodoc: shallow? && @scope[:scope_level] == :member end - def path_for_action(action, path) + def path_for_action(action, path) #:nodoc: prefix = shallow_scoping? ? "#{@scope[:shallow_path]}/#{parent_resource.path}/:id" : @scope[:path] @@ -1281,11 +1281,11 @@ module ActionDispatch end end - def action_path(name, path = nil) + def action_path(name, path = nil) #:nodoc: path || @scope[:path_names][name.to_sym] || name.to_s end - def prefix_name_for_action(as, action) + def prefix_name_for_action(as, action) #:nodoc: if as as.to_s elsif !canonical_action?(action, @scope[:scope_level]) @@ -1293,7 +1293,7 @@ module ActionDispatch end end - def name_for_action(as, action) + def name_for_action(as, action) #:nodoc: prefix = prefix_name_for_action(as, action) prefix = Mapper.normalize_name(prefix) if prefix name_prefix = @scope[:as] @@ -1323,7 +1323,7 @@ module ActionDispatch end end - module Shorthand + module Shorthand #:nodoc: def match(*args) if args.size == 1 && args.last.is_a?(Hash) options = args.pop -- cgit v1.2.3 From 731ca00b484379661786fac36c17db7e085603c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 25 Nov 2010 11:49:51 +0100 Subject: Dynamically generaeted helpers on collection should not clobber resources url helper [#6028 state:resolved] --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 ++ actionpack/test/dispatch/routing_test.rb | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0b5437bd4f..880862c909 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1299,6 +1299,8 @@ module ActionDispatch name_prefix = @scope[:as] if parent_resource + return nil if as.nil? && action.nil? + collection_name = parent_resource.collection_name member_name = parent_resource.member_name end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 0ac8c249cb..bbd010ea6d 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -155,6 +155,11 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end resources :replies do + collection do + get 'page/:page' => 'replies#index', :page => %r{\d+} + get ':page' => 'replies#index', :page => %r{\d+} + end + new do post :preview end @@ -1241,6 +1246,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper + with_test_routes do + assert_equal '/replies', replies_path + end + end + def test_scoped_controller_with_namespace_and_action with_test_routes do assert_equal '/account/twitter/callback', account_callback_path("twitter") -- cgit v1.2.3 From c4d31d0f13783f3cfadbde666fd2a06996b456a2 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Nov 2010 15:36:08 -0300 Subject: Reuse lock_col variable instead calling locking_column class method. Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/locking/optimistic.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 9e1a33a6bf..6503004e38 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -89,7 +89,7 @@ module ActiveRecord affected_rows = relation.where( relation.table[self.class.primary_key].eq(quoted_id).and( - relation.table[self.class.locking_column].eq(quote_value(previous_value)) + relation.table[lock_col].eq(quote_value(previous_value)) ) ).arel.update(arel_attributes_values(false, false, attribute_names)) @@ -111,8 +111,9 @@ module ActiveRecord if persisted? table = self.class.arel_table - predicate = table[self.class.primary_key].eq(id) - predicate = predicate.and(table[self.class.locking_column].eq(send(self.class.locking_column).to_i)) + lock_col = self.class.locking_column + predicate = table[self.class.primary_key].eq(id). + and(table[lock_col].eq(send(lock_col).to_i)) affected_rows = self.class.unscoped.where(predicate).delete_all -- cgit v1.2.3 From 1b6b80355c52cc97d96f6d747271ff43efebab0a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Nov 2010 16:01:41 -0300 Subject: Remove explicit return. Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/locking/optimistic.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 6503004e38..c0e1dda2bd 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -70,7 +70,7 @@ module ActiveRecord result[self.class.locking_column] ||= 0 end - return result + result end def update(attribute_names = @attributes.keys) #:nodoc: -- cgit v1.2.3 From ac6e9447e521a6ab2e3b60acd00a1ae2b863329e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Nov 2010 16:11:53 -0300 Subject: Remove return, we are already returning self. Signed-off-by: Santiago Pastorino --- .../lib/active_record/associations/association_collection.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 774103342a..8a98c0fcbe 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -235,12 +235,12 @@ module ActiveRecord # Removes all records from this association. Returns +self+ so method calls may be chained. def clear - return self if length.zero? # forces load_target if it hasn't happened already - - if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy - destroy_all - else - delete_all + unless length.zero? # forces load_target if it hasn't happened already + if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy + destroy_all + else + delete_all + end end self -- cgit v1.2.3 From c91a13f8f557cc1d21fccb5f964d50438cd60a52 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Nov 2010 16:12:30 -0300 Subject: Use ternary instead explicit return. Signed-off-by: Santiago Pastorino --- activerecord/lib/active_record/associations/association_collection.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 8a98c0fcbe..e4e5ffd2b3 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -357,8 +357,7 @@ module ActiveRecord return false unless record.is_a?(@reflection.klass) return include_in_memory?(record) unless record.persisted? load_target if @reflection.options[:finder_sql] && !loaded? - return @target.include?(record) if loaded? - exists?(record) + loaded? ? @target.include?(record) : exists?(record) end def proxy_respond_to?(method, include_private = false) -- cgit v1.2.3 From a3bd62e1bae64569d0c2d45f8068f291e3e0e776 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Nov 2010 16:12:57 -0300 Subject: Remove explicit return. Signed-off-by: Santiago Pastorino --- .../active_record/associations/has_and_belongs_to_many_association.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index da742fa668..2c72fd0004 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -67,7 +67,7 @@ module ActiveRecord relation.insert(attributes) end - return true + true end def delete_records(records) @@ -80,7 +80,7 @@ module ActiveRecord ).delete end end - + def construct_joins "INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON #{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}" end -- cgit v1.2.3 From 438c0188f8aa07d0e9895a2c13886901ca40ed5e Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 25 Nov 2010 20:00:40 -0200 Subject: nil check unneeded ht. exviva --- activerecord/lib/active_record/associations/association_collection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index e4e5ffd2b3..ba9373ba6a 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -236,7 +236,7 @@ module ActiveRecord # Removes all records from this association. Returns +self+ so method calls may be chained. def clear unless length.zero? # forces load_target if it hasn't happened already - if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy + if @reflection.options[:dependent] == :destroy destroy_all else delete_all -- cgit v1.2.3 From a98d9d65aef31e3e1c95f59cd65ac7e1cbe76f89 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 26 Nov 2010 00:21:51 +0100 Subject: move the setting up of the mime collector into the collector on init Signed-off-by: Santiago Pastorino --- actionpack/lib/action_controller/metal/mime_responds.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 6fe1f4ece5..2e58155b7c 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -258,9 +258,8 @@ module ActionController #:nodoc: # nil if :not_acceptable was sent to the client. # def retrieve_response_from_mimes(mimes=nil, &block) - collector = Collector.new { default_render } mimes ||= collect_mimes_from_class_level - mimes.each { |mime| collector.send(mime) } + collector = Collector.new(mimes) { default_render } block.call(collector) if block_given? if format = request.negotiate_mime(collector.order) @@ -277,8 +276,9 @@ module ActionController #:nodoc: include AbstractController::Collector attr_accessor :order - def initialize(&block) + def initialize(mimes, &block) @order, @responses, @default_response = [], {}, block + mimes.each { |mime| self.send(mime) } end def any(*args, &block) -- cgit v1.2.3 From 74049b57fba3d26a5c9ac220619362ff36893b13 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 25 Nov 2010 21:31:14 -0200 Subject: implicit self here --- actionpack/lib/action_controller/metal/mime_responds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 2e58155b7c..9ba37134b8 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -278,7 +278,7 @@ module ActionController #:nodoc: def initialize(mimes, &block) @order, @responses, @default_response = [], {}, block - mimes.each { |mime| self.send(mime) } + mimes.each { |mime| send(mime) } end def any(*args, &block) -- cgit v1.2.3 From 9332cc582ebaa9b6755fa7bdfe0bc04dd51c098d Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Fri, 26 Nov 2010 00:35:23 +0100 Subject: removes a couple of redundant selfs --- activerecord/lib/active_record/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index b7aac7a7c9..9b09b14c87 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1837,9 +1837,9 @@ MSG # Clear attributes and changed_attributes def clear_timestamp_attributes %w(created_at created_on updated_at updated_on).each do |attribute_name| - if self.has_attribute?(attribute_name) + if has_attribute?(attribute_name) self[attribute_name] = nil - self.changed_attributes.delete(attribute_name) + changed_attributes.delete(attribute_name) end end end -- cgit v1.2.3 From aab76ce199e14ad86ead6a45c60de297f60b1df6 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 13:51:35 +1100 Subject: There is no more routes_configuration_file method. --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index e39ccbc4b8..5ee8d0d0a3 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -39,8 +39,6 @@ Rails will use that particular setting to configure Active Record. h4. Rails General Configuration -* +config.routes_configuration_file+ overrides the default path for the routes configuration file. This defaults to +config/routes.rb+. - * +config.cache_classes+ controls whether or not application classes should be reloaded on each request. * +config.cache_store+ configures which cache store to use for Rails caching. Options include +:memory_store+, +:file_store+, +:mem_cache_store+ or the name of your own custom class. -- cgit v1.2.3 From 26837734d6f50684056e059dfe853653a8ec50d0 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 13:54:37 +1100 Subject: Don't mention Rails 2.3, given that this is supposed to be a guide for Rails *3*. --- railties/guides/source/configuring.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 5ee8d0d0a3..952b20f586 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -23,10 +23,10 @@ To run some code before Rails itself is loaded, simply put it above the call to h3. Configuring Rails Components -In general, the work of configuring Rails means configuring the components of Rails, as well as configuring Rails itself. The +application.rb+ and environment-specific configuration files (such as +config/environments/production.rb+) allow you to specify the various settings that you want to pass down to all of the components. For example, the default Rails 2.3 +application.rb+ file includes one setting: +In general, the work of configuring Rails means configuring the components of Rails, as well as configuring Rails itself. The +application.rb+ and environment-specific configuration files (such as +config/environments/production.rb+) allow you to specify the various settings that you want to pass down to all of the components. For example, the default Rails 3.0 +application.rb+ file includes this setting: -config.filter_parameters << :password + config.filter_parameters += [:password] This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same +config+ object: -- cgit v1.2.3 From 8b114bec061d83352312d5710689ace4557443ab Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 13:56:39 +1100 Subject: Mention what cache_classes defaults to in all three default environments --- railties/guides/source/configuring.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 952b20f586..b3c9b4ad8d 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -32,14 +32,14 @@ In general, the work of configuring Rails means configuring the components of Ra This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same +config+ object: -config.active_record.timestamped_migrations = false + config.active_record.timestamped_migrations = false Rails will use that particular setting to configure Active Record. h4. Rails General Configuration -* +config.cache_classes+ controls whether or not application classes should be reloaded on each request. +* +config.cache_classes+ controls whether or not application classes should be reloaded on each request. Defaults to _true_ in development, _false_ in test and production. * +config.cache_store+ configures which cache store to use for Rails caching. Options include +:memory_store+, +:file_store+, +:mem_cache_store+ or the name of your own custom class. -- cgit v1.2.3 From eb21791c5bd1881163328d4b0aa815a6e01a4ded Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 13:58:01 +1100 Subject: There is no controller_paths method in Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index b3c9b4ad8d..2cc71f2a12 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -45,8 +45,6 @@ h4. Rails General Configuration * +config.colorize_logging+ (true by default) specifies whether or not to use ANSI color codes when logging information. -* +config.controller_paths+ accepts an array of paths that will be searched for controllers. Defaults to +app/controllers+. - * +config.database_configuration_file+ overrides the default path for the database configuration file. Default to +config/database.yml+. * +config.dependency_loading+ enables or disables dependency loading during the request cycle. Setting dependency_loading to _true_ will allow new classes to be loaded during a request and setting it to _false_ will disable this behavior. -- cgit v1.2.3 From db7c8abbb69f0ac06719b1e69f6276d633669a9e Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 13:59:51 +1100 Subject: There is no database_configuration_file method in Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 2cc71f2a12..c6d4a8a799 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -45,8 +45,6 @@ h4. Rails General Configuration * +config.colorize_logging+ (true by default) specifies whether or not to use ANSI color codes when logging information. -* +config.database_configuration_file+ overrides the default path for the database configuration file. Default to +config/database.yml+. - * +config.dependency_loading+ enables or disables dependency loading during the request cycle. Setting dependency_loading to _true_ will allow new classes to be loaded during a request and setting it to _false_ will disable this behavior. * +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. All elements of this array must also be in +load_paths+. -- cgit v1.2.3 From c8af6c28cc82d0c6cbddd326f316405c570eac2d Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:01:09 +1100 Subject: load_once_paths is now autoload_paths in Rails 3 --- railties/guides/source/configuring.textile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index c6d4a8a799..fc4cc623a1 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -39,6 +39,10 @@ Rails will use that particular setting to configure Active Record. h4. Rails General Configuration +* +config.autoload_once_paths+ accepts an array of paths from which Rails will automatically load from only once. All elements of this array must also be in +autoload_paths+. + +* +config.autoload_paths+ accepts an array of additional paths to prepend to the load path. By default, all app, lib, vendor and mock paths are included in this list. + * +config.cache_classes+ controls whether or not application classes should be reloaded on each request. Defaults to _true_ in development, _false_ in test and production. * +config.cache_store+ configures which cache store to use for Rails caching. Options include +:memory_store+, +:file_store+, +:mem_cache_store+ or the name of your own custom class. @@ -49,9 +53,6 @@ h4. Rails General Configuration * +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. All elements of this array must also be in +load_paths+. -* +config.load_once_paths+ accepts an array of paths from which Rails will automatically load from only once. All elements of this array must also be in +load_paths+. - -* +config.load_paths+ accepts an array of additional paths to prepend to the load path. By default, all app, lib, vendor and mock paths are included in this list. * +config.log_level+ defines the verbosity of the Rails logger. In production mode, this defaults to +:info+. In development mode, it defaults to +:debug+. -- cgit v1.2.3 From 9979251d7c2ab886410f5448dfec701218cc0d15 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:05:00 +1100 Subject: There is no plugin_loader config option in Rails 3 --- railties/guides/source/configuring.textile | 3 --- 1 file changed, 3 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index fc4cc623a1..dd6aba12d6 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -53,15 +53,12 @@ h4. Rails General Configuration * +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. All elements of this array must also be in +load_paths+. - * +config.log_level+ defines the verbosity of the Rails logger. In production mode, this defaults to +:info+. In development mode, it defaults to +:debug+. * +config.log_path+ overrides the path to the log file to use. Defaults to +log/#{environment}.log+ (e.g. log/development.log or log/production.log). * +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging. -* +config.plugin_loader+ overrides the class that handles loading each plugin. Defaults to +Rails::Plugin::Loader+. - * +config.plugin_locators+ overrides the class that handle finding the desired plugins that you‘d like to load for your application. By default it is the +Rails::Plugin::FileSystemLocator+. * +config.plugin_paths+ overrides the path to the root of the plugins directory. Defaults to +vendor/plugins+. -- cgit v1.2.3 From f01f7fc62953dd402ac118c07ae1851a181c4a67 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:05:22 +1100 Subject: There is no plugin_locators config option in Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index dd6aba12d6..6e5f917836 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -59,8 +59,6 @@ h4. Rails General Configuration * +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging. -* +config.plugin_locators+ overrides the class that handle finding the desired plugins that you‘d like to load for your application. By default it is the +Rails::Plugin::FileSystemLocator+. - * +config.plugin_paths+ overrides the path to the root of the plugins directory. Defaults to +vendor/plugins+. * +config.plugins+ accepts the list of plugins to load. If this is set to nil, all plugins will be loaded. If this is set to [], no plugins will be loaded. Otherwise, plugins will be loaded in the order specified. -- cgit v1.2.3 From ffca2d7f1469fd5444b1417e5d2d4bd3d7d0af18 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:05:43 +1100 Subject: There is no plugin_paths config option in Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 6e5f917836..e0ef07fa36 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -59,8 +59,6 @@ h4. Rails General Configuration * +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging. -* +config.plugin_paths+ overrides the path to the root of the plugins directory. Defaults to +vendor/plugins+. - * +config.plugins+ accepts the list of plugins to load. If this is set to nil, all plugins will be loaded. If this is set to [], no plugins will be loaded. Otherwise, plugins will be loaded in the order specified. * +config.preload_frameworks+ enables or disables preloading all frameworks at startup. -- cgit v1.2.3 From 69ae74210c6b49219b97a8e2e2711a81a523d8b8 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:07:42 +1100 Subject: There is no root_path config option in Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index e0ef07fa36..eee46b47ea 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -65,8 +65,6 @@ h4. Rails General Configuration * +config.reload_plugins+ enables or disables plugin reloading. -* +config.root_path+ configures the root path of the application. - * +config.time_zone+ sets the default time zone for the application and enables time zone awareness for Active Record. * +config.view_path+ sets the path of the root of an application's views. Defaults to +app/views+. -- cgit v1.2.3 From 9a4d6724573470d74ef9ef4572dbe04a1b5d9b4a Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:08:26 +1100 Subject: There is no view_path config option in Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index eee46b47ea..e614d232fe 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -67,8 +67,6 @@ h4. Rails General Configuration * +config.time_zone+ sets the default time zone for the application and enables time zone awareness for Active Record. -* +config.view_path+ sets the path of the root of an application's views. Defaults to +app/views+. - * +config.whiny_nils+ enables or disabled warnings when an methods of nil are invoked. Defaults to _false_. h4. Configuring i18n -- cgit v1.2.3 From 33298d8e38eab9ef2e528478fbd2d4585f732d82 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:16:57 +1100 Subject: There is no config.action_controller.params_parser method for Rails 3. This is now handled by the ActionDispatch::ParamsParser middleware. --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index e614d232fe..03a360f87f 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -121,8 +121,6 @@ h4. Configuring Action Controller WARNING: Threadsafe operation is incompatible with the normal workings of development mode Rails. In particular, automatic dependency loading and class reloading are automatically disabled when you call +config.threadsafe!+. -* +config.action_controller.param_parsers+ provides an array of handlers that can extract information from incoming HTTP requests and add it to the +params+ hash. By default, parsers for multipart forms, URL-encoded forms, XML, and JSON are active. - * +config.action_controller.default_charset+ specifies the default character set for all renders. The default is "utf-8". * +config.action_controller.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging. -- cgit v1.2.3 From f1406a905adc77ea719a6f3f85229d43a4766dc5 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:19:17 +1100 Subject: There is no config.action_controller.resource_path_names method for Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 03a360f87f..b4dc223c71 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -125,8 +125,6 @@ WARNING: Threadsafe operation is incompatible with the normal workings of develo * +config.action_controller.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging. -* +config.action_controller.resource_path_names+ is a hash of default names for several RESTful actions. By default, the new action is named +new+ and the edit action is named +edit+. - * +config.action_controller.request_forgery_protection_token+ sets the token parameter name for RequestForgery. Calling +protect_from_forgery+ sets it to +:authenticity_token+ by default. * +config.action_controller.optimise_named_routes+ turns on some optimizations in generating the routing table. It is set to +true+ by default. -- cgit v1.2.3 From 3eec4d4f93df70ea9c421df44c23ca0d4595534c Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:20:33 +1100 Subject: There is no config.action_controller.optimize_named_routes method for Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index b4dc223c71..d6df1e7cbe 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -127,8 +127,6 @@ WARNING: Threadsafe operation is incompatible with the normal workings of develo * +config.action_controller.request_forgery_protection_token+ sets the token parameter name for RequestForgery. Calling +protect_from_forgery+ sets it to +:authenticity_token+ by default. -* +config.action_controller.optimise_named_routes+ turns on some optimizations in generating the routing table. It is set to +true+ by default. - * +config.action_controller.allow_forgery_protection+ enables or disables CSRF protection. By default this is +false+ in test mode and +true+ in all other modes. * +config.action_controller.relative_url_root+ can be used to tell Rails that you are deploying to a subdirectory. The default is +ENV['RAILS_RELATIVE_URL_ROOT']+. -- cgit v1.2.3 From b4ec8ad09c028a5e322a04eacf487b775a672ec2 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:21:04 +1100 Subject: Separate Action Dispatch and Action Pack sections in Configuration Guide. --- railties/guides/source/configuring.textile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index d6df1e7cbe..c948f680f8 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -131,8 +131,6 @@ WARNING: Threadsafe operation is incompatible with the normal workings of develo * +config.action_controller.relative_url_root+ can be used to tell Rails that you are deploying to a subdirectory. The default is +ENV['RAILS_RELATIVE_URL_ROOT']+. -* +config.action_dispatch.session_store+ sets the name of the store for session data. The default is +:cookie_store+; other valid options include +:active_record_store+, +:mem_cache_store+ or the name of your own custom class. - The caching code adds two additional settings: * +ActionController::Base.page_cache_directory+ sets the directory where Rails will create cached pages for your web server. The default is +Rails.public_path+ (which is usually set to +Rails.root + "/public"+). @@ -147,6 +145,10 @@ The Active Record session store can also be configured: * +ActiveRecord::SessionStore::Session.data_column_name+ sets the name of the column which stores marshaled session data. Defaults to +data+. +h4. Configuring Action Dispatch + +* +config.action_dispatch.session_store+ sets the name of the store for session data. The default is +:cookie_store+; other valid options include +:active_record_store+, +:mem_cache_store+ or the name of your own custom class. + h4. Configuring Action View There are only a few configuration options for Action View, starting with four on +ActionView::Base+: -- cgit v1.2.3 From 3d8d21b5132bb6852fe9533710d9105ab4d30ec8 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:23:40 +1100 Subject: There is no config.action_view.warn_cache_misses method for Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index c948f680f8..0803c1e7f4 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -155,8 +155,6 @@ There are only a few configuration options for Action View, starting with four o * +config.action_view.debug_rjs+ specifies whether RJS responses should be wrapped in a try/catch block that alert()s the caught exception (and then re-raises it). The default is +false+. -* +config.action_view.warn_cache_misses+ tells Rails to display a warning whenever an action results in a cache miss on your view paths. The default is +false+. - * +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is Proc.new{ |html_tag, instance| %Q(%<div class="field_with_errors">#{html_tag}</div>).html_safe } * +config.action_view.default_form_builder+ tells Rails which form builder to use by default. The default is +ActionView::Helpers::FormBuilder+. -- cgit v1.2.3 From 8b49fae3eaa8d227261be06124ee7a8041ea77d7 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:24:51 +1100 Subject: There is no config.action_mailer.template_root method for Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 0803c1e7f4..67028c683b 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -167,8 +167,6 @@ h4. Configuring Action Mailer There are a number of settings available on +config.action_mailer+: -* +config.action_mailer.template_root+ gives the root folder for Action Mailer templates. - * +config.action_mailer.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Mailer. Set to nil to disable logging. * +config.action_mailer.smtp_settings+ allows detailed configuration for the +:smtp+ delivery method. It accepts a hash of options, which can include any of these options: -- cgit v1.2.3 From e968acc21c7e60e09a8ef076a00ef22bce2813b9 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:25:46 +1100 Subject: Update ActionMailer documentation to not use deprecated template_root method as documentation, but rather raise_delivery_errors method --- actionmailer/lib/action_mailer/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 0bf60a2c24..d13ae3dd3a 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -273,7 +273,7 @@ module ActionMailer #:nodoc: # = Configuration options # # These options are specified on the class level, like - # ActionMailer::Base.template_root = "/my/templates" + # ActionMailer::Base.raise_delivery_errors = true # # * default - You can pass this in at a class level as well as within the class itself as # per the above section. -- cgit v1.2.3 From 926d64e8b3a0cfbc233a0c564b5dfb0aeacb9546 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:32:20 +1100 Subject: There is no config.action_mailer.default_charset method for Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 67028c683b..b5f32671a8 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -187,8 +187,6 @@ There are a number of settings available on +config.action_mailer+: * +config.action_mailer.perform_deliveries+ specifies whether mail will actually be delivered. By default this is +true+; it can be convenient to set it to +false+ for testing. -* +config.action_mailer.default_charset+ tells Action Mailer which character set to use for the body and for encoding the subject. It defaults to +utf-8+. - * +config.action_mailer.default_content_type+ specifies the default content type used for the main part of the message. It defaults to "text/plain" * +config.action_mailer.default_mime_version+ is the default MIME version for the message. It defaults to +1.0+. -- cgit v1.2.3 From 66aefed136ef0c087e9448d8098cea629e211144 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:32:36 +1100 Subject: There is no config.action_mailer.default_content_type method for Rails 3 --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index b5f32671a8..df56768de9 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -187,8 +187,6 @@ There are a number of settings available on +config.action_mailer+: * +config.action_mailer.perform_deliveries+ specifies whether mail will actually be delivered. By default this is +true+; it can be convenient to set it to +false+ for testing. -* +config.action_mailer.default_content_type+ specifies the default content type used for the main part of the message. It defaults to "text/plain" - * +config.action_mailer.default_mime_version+ is the default MIME version for the message. It defaults to +1.0+. * +config.action_mailer.default_implicit_parts_order+ - When a message is built implicitly (i.e. multiple parts are assembled from templates -- cgit v1.2.3 From d0006121c581d0acadf7d46f955051be10128238 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:43:16 +1100 Subject: Mention the default config.action_mailer.default options in Configuration guide --- railties/guides/source/configuring.textile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index df56768de9..bb8561587c 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -187,7 +187,13 @@ There are a number of settings available on +config.action_mailer+: * +config.action_mailer.perform_deliveries+ specifies whether mail will actually be delivered. By default this is +true+; it can be convenient to set it to +false+ for testing. -* +config.action_mailer.default_mime_version+ is the default MIME version for the message. It defaults to +1.0+. +* +config.action_mailer.default+ configures Action Mailer defaults. These default to: + + :mime_version => "1.0", + :charset => "UTF-8", + :content_type => "text/plain", + :parts_order => [ "text/plain", "text/enriched", "text/html" ] + * +config.action_mailer.default_implicit_parts_order+ - When a message is built implicitly (i.e. multiple parts are assembled from templates which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to +["text/html", "text/enriched", "text/plain"]+. Items that appear first in the array have higher priority in the mail client -- cgit v1.2.3 From e96a64fb3910ad0ec2f3b7a970ae6047dfb89e01 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:53:12 +1100 Subject: There is no config.action_mailer.default_implicit_parts_order method for Rails 3 --- railties/guides/source/configuring.textile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index bb8561587c..a7244de19f 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -195,10 +195,6 @@ There are a number of settings available on +config.action_mailer+: :parts_order => [ "text/plain", "text/enriched", "text/html" ] -* +config.action_mailer.default_implicit_parts_order+ - When a message is built implicitly (i.e. multiple parts are assembled from templates -which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to +["text/html", "text/enriched", "text/plain"]+. Items that appear first in the array have higher priority in the mail client -and appear last in the mime encoded message. - h4. Configuring Active Resource There is a single configuration setting available on +config.active_resource+: -- cgit v1.2.3 From 1d5db09ca7cd2d8fa2d05c138e0211979fdbe966 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:55:56 +1100 Subject: There is no RAILS_GEM_VERSION environment variable or constant for Rails 3, since this is now managed by Bundler --- railties/guides/source/configuring.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index a7244de19f..a4e85de590 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -247,8 +247,6 @@ Some parts of Rails can also be configured externally by supplying environment v * +ENV["RAILS_CACHE_ID"]+ and +ENV["RAILS_APP_VERSION"]+ are used to generate expanded cache keys in Rails' caching code. This allows you to have multiple separate caches from the same application. -* +ENV['RAILS_GEM_VERSION']+ defines the version of the Rails gems to use, if +RAILS_GEM_VERSION+ is not defined in your +environment.rb+ file. - h3. Changelog * August 13, 2009: Updated with config syntax and added general configuration options by "John Pignata" -- cgit v1.2.3 From 788fdb2ac1ae930660a135000abf92c36735815f Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 14:57:16 +1100 Subject: Update Changelog for configuring guide --- railties/guides/source/configuring.textile | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index a4e85de590..efb5663e33 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -249,6 +249,7 @@ Some parts of Rails can also be configured externally by supplying environment v h3. Changelog +* November 26, 2010: Removed all config settings not available in Rails 3 (Ryan Bigg) * August 13, 2009: Updated with config syntax and added general configuration options by "John Pignata" * January 3, 2009: First reasonably complete draft by "Mike Gunderloy":credits.html#mgunderloy * November 5, 2008: Rough outline by "Mike Gunderloy":credits.html#mgunderloy -- cgit v1.2.3 From ff04f6fee4a71da867398f49cc2d9e22760dd7e0 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 15:09:17 +1100 Subject: root_path is now simply root in Rails 3 --- railties/guides/source/configuring.textile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index efb5663e33..30f8e31095 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -65,6 +65,8 @@ h4. Rails General Configuration * +config.reload_plugins+ enables or disables plugin reloading. +* +config.root+ configures the root path of the application. + * +config.time_zone+ sets the default time zone for the application and enables time zone awareness for Active Record. * +config.whiny_nils+ enables or disabled warnings when an methods of nil are invoked. Defaults to _false_. -- cgit v1.2.3 From 6bb462861f7cca070f1d3933c19c10b18fa44c9e Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 16:46:06 +1100 Subject: There is no more load_application_initializers in Rails 3 --- railties/guides/source/configuring.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 30f8e31095..3986faa3cd 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -13,7 +13,7 @@ Rails offers (at least) four good spots to place initialization code: * application.rb * Environment-specific Configuration Files -* Initializers (load_application_initializers) +* Initializers * After-Initializers h3. Running Code Before Rails -- cgit v1.2.3 From 72e973ebbcddbeb172c2dd3a7ddc12957dc5bec0 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 17:03:14 +1100 Subject: Add mention of after_initialize to the config guide --- railties/guides/source/configuring.textile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 3986faa3cd..154eebc0c1 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -39,6 +39,14 @@ Rails will use that particular setting to configure Active Record. h4. Rails General Configuration +* +config.after_initialize+ takes a block which will be ran _after_ Rails has finished initializing. Useful for configuring values set up by other initializers: + + + config.after_initialize do + ActionView::Base.sanitized_allowed_tags.delete 'div' + end + + * +config.autoload_once_paths+ accepts an array of paths from which Rails will automatically load from only once. All elements of this array must also be in +autoload_paths+. * +config.autoload_paths+ accepts an array of additional paths to prepend to the load path. By default, all app, lib, vendor and mock paths are included in this list. -- cgit v1.2.3 From 8d6ac59d58ff7fce851a894d714e0677c11d7eb6 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 18:06:14 +1100 Subject: Added documentation for config.generators to the config guide --- railties/guides/source/configuring.textile | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 154eebc0c1..c395e42c00 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -47,6 +47,8 @@ h4. Rails General Configuration end +* +config.app_generators+ alternate name for +config.generators+. See the "Configuring Generators" section below for how to use this. + * +config.autoload_once_paths+ accepts an array of paths from which Rails will automatically load from only once. All elements of this array must also be in +autoload_paths+. * +config.autoload_paths+ accepts an array of additional paths to prepend to the load path. By default, all app, lib, vendor and mock paths are included in this list. @@ -79,6 +81,31 @@ h4. Rails General Configuration * +config.whiny_nils+ enables or disabled warnings when an methods of nil are invoked. Defaults to _false_. +h4. Configuring Generators + +Rails 3 allows you to alter what generators are used with the +config.generators+ method. This method takes a block: + + + config.generators do |g| + g.orm :active_record + g.test_framework :test_unit + end + + +The full set of methods that can be used in this block are as follows: + +* +force_plural+ allows pluralized model names. Defaults to _false_. +* +helper+ defines whether or not to generate helpers. Defaults to _true_ +* +orm+ defines which orm to use. Defaults to _nil_, so will use Active Record by default. +* +integration_tool+ defines which integration tool to use. Defaults to _nil_ +* +performance_tool+ defines which performance tool to use. Defaults to _nil_ +* +resource_controller+ defines which generator to use for generating a controller when using +rails generate resource+. Defaults to +:controller+. +* +scaffold_controller+ different from +resource_controller+, defines which generator to use for generating a _scaffolded_ controller when using +rails generate scaffold+. Defaults to +:scaffold_controller+ +* +stylesheets+ turns on the hook for stylesheets in generators. Used in Rails for when the +scaffold+ generator is ran, but this hook can be used in other generates as well. +* +test_framework+ defines which test framework to use. Defaults to _nil_, so will use Test::Unit by default. +* +template_engine+ defines which template engine to use, such as ERB or Haml. Defaults to +:erb+. + + h4. Configuring i18n * +config.i18n.default_locale+ sets the default locale of an application used for i18n. Defaults to +:en+. -- cgit v1.2.3 From ce9456eca0c4ea77a42aaad5e8080842c1c01422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 26 Nov 2010 11:55:56 +0100 Subject: Only convert direct hash instances in hash with indifferent access. --- activesupport/lib/active_support/hash_with_indifferent_access.rb | 7 +++---- activesupport/test/core_ext/hash_ext_test.rb | 8 ++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 320f5c1c92..6a344867ee 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -140,11 +140,10 @@ module ActiveSupport end def convert_value(value) - case value - when Hash + if value.class == Hash self.class.new_from_hash_copying_default(value) - when Array - value.dup.replace(value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e }) + elsif value.is_a?(Array) + value.dup.replace(value.map { |e| convert_value(e) }) else value end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 370f26b0d7..74223dd7f2 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -12,6 +12,9 @@ class HashExtTest < Test::Unit::TestCase class SubclassingArray < Array end + class SubclassingHash < Hash + end + def setup @strings = { 'a' => 1, 'b' => 2 } @symbols = { :a => 1, :b => 2 } @@ -105,6 +108,11 @@ class HashExtTest < Test::Unit::TestCase assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys! end + def test_hash_subclass + flash = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access + assert_kind_of SubclassingHash, flash["foo"] + end + def test_indifferent_assorted @strings = @strings.with_indifferent_access @symbols = @symbols.with_indifferent_access -- cgit v1.2.3 From 5b9f6a74db1a58c5557087cd924fd67dd9cf43e0 Mon Sep 17 00:00:00 2001 From: Aditya Sanghi Date: Fri, 26 Nov 2010 16:41:33 +0530 Subject: Resolving LH #5986, cookies doc updates --- actionpack/lib/action_dispatch/middleware/cookies.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index c4c2e1acd7..b0a4e3d949 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -16,17 +16,23 @@ module ActionDispatch # Examples for writing: # # # Sets a simple session cookie. + # # This cookie will be deleted when the user's browser is closed. # cookies[:user_name] = "david" # + # # Assign an array of values to a cookie. + # cookies[:lat_lon] = [47.68, -122.37] + # # # Sets a cookie that expires in 1 hour. # cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now } # # # Sets a signed cookie, which prevents a user from tampering with its value. - # # You must specify a value in ActionController::Base.cookie_verifier_secret. - # cookies.signed[:remember_me] = [current_user.id, current_user.salt] + # # The cookie is signed by your app's config.secret_token value. + # # Rails generates this value by default when you create a new Rails app. + # cookies.signed[:user_id] = current_user.id # # # Sets a "permanent" cookie (which expires in 20 years from now). # cookies.permanent[:login] = "XJ-122" + # # # You can also chain these methods: # cookies.permanent.signed[:login] = "XJ-122" # @@ -34,6 +40,7 @@ module ActionDispatch # # cookies[:user_name] # => "david" # cookies.size # => 2 + # cookies[:lat_lon] # => [47.68, -122.37] # # Example for deleting: # @@ -275,7 +282,7 @@ module ActionDispatch "integrity hash for cookie session data. Use " + "config.secret_token = \"some secret phrase of at " + "least #{SECRET_MIN_LENGTH} characters\"" + - "in config/application.rb" + "in config/initializers/secret_token.rb" end if secret.length < SECRET_MIN_LENGTH -- cgit v1.2.3 From fe2103a1c8336e8ef164d696e8eaeab62158d84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mej=C3=ADa?= Date: Fri, 26 Nov 2010 14:11:28 +0100 Subject: Added missing word. --- railties/guides/source/contributing_to_rails.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/contributing_to_rails.textile b/railties/guides/source/contributing_to_rails.textile index f501335958..721adc00d7 100644 --- a/railties/guides/source/contributing_to_rails.textile +++ b/railties/guides/source/contributing_to_rails.textile @@ -127,7 +127,7 @@ You can now run tests as you did for +sqlite3+: rake test_mysql -You can also +myqsl+ with +postgresql+, +jdbcmysql+, +jdbcsqlite3+ or +jdbcpostgresql+. Check out the file +activerecord/RUNNING_UNIT_TESTS+ for information on running more targeted database tests, or the file +ci/ci_build.rb+ to see the test suite that the Rails continuous integration server runs. +You can also replace +myqsl+ with +postgresql+, +jdbcmysql+, +jdbcsqlite3+ or +jdbcpostgresql+. Check out the file +activerecord/RUNNING_UNIT_TESTS+ for information on running more targeted database tests, or the file +ci/ci_build.rb+ to see the test suite that the Rails continuous integration server runs. NOTE: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite 3. Subtle differences between the various Active Record database adapters have been behind the rejection of many patches that looked OK when tested only against MySQL. -- cgit v1.2.3 From 3a50799ab8aede48767612ba1d4cc904f294cdb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mej=C3=ADa?= Date: Fri, 26 Nov 2010 17:16:52 +0100 Subject: Mentioning catch with Bundler remembering options between different calls --- railties/guides/source/contributing_to_rails.textile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/contributing_to_rails.textile b/railties/guides/source/contributing_to_rails.textile index 721adc00d7..ccb9db5eee 100644 --- a/railties/guides/source/contributing_to_rails.textile +++ b/railties/guides/source/contributing_to_rails.textile @@ -105,12 +105,17 @@ mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.* to 'rails'@'localhost'; -Then ensure you run bundle install without the +--without db+ option: +Now you'll have to install Active Record dependencies. This step is a little tricky because just running +bundle install+ without the +--without db+ parameter won't get those dependencies installed. It turns out that bundler remembers the +--without db+ parameter between calls so you'll have to manually override this. (See the "+bundle_install+ man page":http://gembundler.com/man/bundle-install.1.html for details) + +The easiest way to do this is to remove bundler's config file and then run +install+ again: +rm .bundle/config bundle install +INFO: If you don't feel comfortable deleting bundler's config file, you can achieve the same effect by manually removing the "+BUNDLE_WITHOUT: db+" line on +.bundle/config+. + Finally, enter this from the +activerecord+ directory to create the test databases: -- cgit v1.2.3 From 6aa408e11cc99603778eb99e8cd2e585e0f97b50 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 26 Nov 2010 21:14:58 +1100 Subject: Add mention of config.serve_static_assets to config guide --- railties/guides/source/configuring.textile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index c395e42c00..91c4c2b0f7 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -77,6 +77,8 @@ h4. Rails General Configuration * +config.root+ configures the root path of the application. +* +config.serve_static_assets+ configures Rails to serve static assets. Defaults to _true_, but in the production environment is turned off. The server software used to run the application should be used to serve the assets instead. + * +config.time_zone+ sets the default time zone for the application and enables time zone awareness for Active Record. * +config.whiny_nils+ enables or disabled warnings when an methods of nil are invoked. Defaults to _false_. -- cgit v1.2.3 From 167964149e76d66742675a1505e1030e1c8f440b Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 27 Nov 2010 07:56:08 +1100 Subject: Add explicit statement that verify_authenticity_token can be turned off for actions. --- .../lib/action_controller/metal/request_forgery_protection.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 02f577647e..148efbb081 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -53,9 +53,13 @@ module ActionController #:nodoc: # class FooController < ApplicationController # protect_from_forgery :except => :index # - # # you can disable csrf protection on controller-by-controller basis: - # skip_before_filter :verify_authenticity_token - # end + # You can disable csrf protection on controller-by-controller basis: + # + # skip_before_filter :verify_authenticity_token + # + # It can also be disabled for specific controller actions: + # + # skip_before_filter :verify_authenticity_token, :except => [:create] # # Valid Options: # -- cgit v1.2.3 From 3ee0f0379cc0ae3dd44a050e35d644f1ad7a920b Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 27 Nov 2010 08:15:29 +1100 Subject: Add "Configuring Middleware" section to config guide, starting with mentioning what every bit of middleware does. --- railties/guides/source/configuring.textile | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 91c4c2b0f7..8187c647dd 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -67,6 +67,8 @@ h4. Rails General Configuration * +config.log_path+ overrides the path to the log file to use. Defaults to +log/#{environment}.log+ (e.g. log/development.log or log/production.log). +* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware" section below. + * +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging. * +config.plugins+ accepts the list of plugins to load. If this is set to nil, all plugins will be loaded. If this is set to [], no plugins will be loaded. Otherwise, plugins will be loaded in the order specified. @@ -107,6 +109,29 @@ The full set of methods that can be used in this block are as follows: * +test_framework+ defines which test framework to use. Defaults to _nil_, so will use Test::Unit by default. * +template_engine+ defines which template engine to use, such as ERB or Haml. Defaults to +:erb+. +h4. Configuring Middleware + +Every Rails application comes with a standard set of middleware which it uses in this order in the development environment: + +* +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is _true_. +* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to _false_, which it is by default. +* +ActiveSupport::Cache::Strategy::LocalCache+ Serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. +* +Rack::Runtime+ Sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request. +* +Rails::Rack::Logger+ Will notify the logs that the request has began. After request is complete, flushes all the logs. +* +ActionDispatch::ShowExceptions+ rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to _true_. If +config.action_dispatch.show_exceptions+ is set to _false_, exceptions will be raised regardless. +* +ActionDispatch::RemoteIp+ checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings. +* +Rack::Sendfile+ The Sendfile middleware intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch_ +* +ActionDispatch::Callbacks+ Runs the prepare callbacks before serving the request. +* +ActiveRecord::ConnectionAdapters::ConnectionManagement+ cleans active connections after each request, unless the +rack.test+ key in the request environment is set to _true_. +* +ActiveRecord::QueryCache+ caches all +SELECT+ queries generated in a request. If an +INSERT+ or +UPDATE+ takes place then the cache is cleaned. +* +ActionDispatch::Cookies+ sets cookies for the request. +* +ActionDispatch::Session::CookieStore+ is responsible for storing the session in cookies. An alternate middleware can be used for this by changing the +config.action_controller.session_store+ to an alternate value. Additionally, options passed to this can be configured by using +config.action_controller.session_options+. +* +ActionDispatch::Flash+ sets up the +flash+ keys. Only available if +config.action_controller.session_store+ is set to a value. +* +ActionDispatch::ParamsParser+ parses out parameters from the request into +params+ +* +Rack::MethodOverride+ allows the method to be overridden if +params[:_method]+ is set. This is the middleware which supports the PUT and DELETE HTTP method types. +* +ActionDispatch::Head+ converts HEAD requests to GET requests and serves them as so. +* +ActionDispatch::BestStandardsSupport+ enables "best standards support" so that IE8 renders some elements correctly. + h4. Configuring i18n -- cgit v1.2.3 From c8c95fc519f9d0e23e012d4434e6c3fe0f6e2a62 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 27 Nov 2010 08:29:29 +1100 Subject: Add methods for configuring middleware to config guide --- railties/guides/source/configuring.textile | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index 8187c647dd..ca78cc0e6d 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -132,6 +132,29 @@ Every Rails application comes with a standard set of middleware which it uses in * +ActionDispatch::Head+ converts HEAD requests to GET requests and serves them as so. * +ActionDispatch::BestStandardsSupport+ enables "best standards support" so that IE8 renders some elements correctly. +Besides these usual middleware, you can add your own by using the +config.middleware.use+ method: + + + config.middleware.use Magical::Unicorns + + +This will put the +Magical::Unicorns+ middleware on the end of the stack. If you wish to put this middleware before another use +insert_before+: + + + config.middleware.insert_before ActionDispatch::Head, Magical::Unicorns + + +There's also +insert_after+ which will insert a middleware _after_ another: + + + config.middleware.insert_after ActionDispatch::Head, Magical::Unicorns + + +Middlewares can also be completely swapped out and replaced with others: + + + config.middleware.swap ActionDispatch::BestStandardsSupport, Magical::Unicorns + h4. Configuring i18n -- cgit v1.2.3