aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2010-07-22 01:29:18 +0200
committerXavier Noria <fxn@hashref.com>2010-07-22 01:29:18 +0200
commit919eb200a9a0969c444b938d08eb4661d41ba986 (patch)
tree329cbe815d549275cc0dc6aa0f75c18d8954f105
parent56669ec3048de316918ec5ad554fff83d757911b (diff)
parentb456877cfb7e0cb0bab9ffd5674abd23caba0ab4 (diff)
downloadrails-919eb200a9a0969c444b938d08eb4661d41ba986.tar.gz
rails-919eb200a9a0969c444b938d08eb4661d41ba986.tar.bz2
rails-919eb200a9a0969c444b938d08eb4661d41ba986.zip
Merge remote branch 'rails/master'
-rw-r--r--README.rdoc58
-rw-r--r--Rakefile16
-rw-r--r--actionmailer/README.rdoc (renamed from actionmailer/README)22
-rw-r--r--actionmailer/Rakefile2
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionmailer/install.rb30
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--actionpack/README.rdoc (renamed from actionpack/README)26
-rw-r--r--actionpack/Rakefile2
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/install.rb30
-rw-r--r--actionpack/lib/abstract_controller.rb1
-rw-r--r--actionpack/lib/action_controller.rb1
-rw-r--r--actionpack/lib/action_controller/base.rb3
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb1
-rw-r--r--actionpack/lib/action_controller/metal/rescue.rb9
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb2
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb183
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb33
-rw-r--r--actionpack/lib/action_dispatch.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb76
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb72
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb15
-rw-r--r--actionpack/lib/action_dispatch/routing.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb186
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/model.rb19
-rw-r--r--actionpack/lib/action_view.rb1
-rw-r--r--actionpack/lib/action_view/helpers.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/record_identification_helper.rb23
-rw-r--r--actionpack/lib/action_view/helpers/record_tag_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/test_case.rb2
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb15
-rw-r--r--actionpack/test/controller/record_identifier_test.rb40
-rw-r--r--actionpack/test/controller/rescue_test.rb27
-rw-r--r--actionpack/test/controller/test_test.rb7
-rw-r--r--actionpack/test/dispatch/middleware_stack_test.rb10
-rw-r--r--actionpack/test/dispatch/request_test.rb8
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb20
-rw-r--r--actionpack/test/template/form_options_helper_test.rb23
-rw-r--r--actionpack/test/template/prototype_helper_test.rb6
-rw-r--r--activemodel/CHANGELOG5
-rw-r--r--activemodel/README.rdoc (renamed from activemodel/README)0
-rw-r--r--activemodel/Rakefile2
-rw-r--r--activemodel/activemodel.gemspec2
-rw-r--r--activemodel/lib/active_model/naming.rb29
-rw-r--r--activemodel/test/cases/naming_test.rb39
-rw-r--r--activemodel/test/models/contact.rb1
-rw-r--r--activemodel/test/models/sheep.rb4
-rw-r--r--activerecord/CHANGELOG2
-rw-r--r--activerecord/README.rdoc (renamed from activerecord/README)21
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/activerecord.gemspec6
-rw-r--r--activerecord/install.rb30
-rw-r--r--activerecord/lib/active_record/association_preload.rb6
-rw-r--r--activerecord/lib/active_record/associations.rb31
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb24
-rw-r--r--activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb11
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/log_subscriber.rb8
-rw-r--r--activerecord/lib/active_record/named_scope.rb4
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/railtie.rb6
-rw-r--r--activerecord/lib/active_record/railties/databases.rake2
-rw-r--r--activerecord/lib/active_record/relation.rb9
-rw-r--r--activerecord/lib/active_record/session_store.rb1
-rw-r--r--activerecord/lib/active_record/timestamp.rb19
-rw-r--r--activerecord/test/cases/adapters/mysql/active_schema_test.rb1
-rw-r--r--activerecord/test/cases/aggregations_test.rb2
-rw-r--r--activerecord/test/cases/ar_schema_test.rb2
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/callbacks_test.rb2
-rw-r--r--activerecord/test/cases/associations/cascaded_eager_loading_test.rb1
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb57
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb4
-rw-r--r--activerecord/test/cases/associations_test.rb32
-rw-r--r--activerecord/test/cases/base_test.rb12
-rw-r--r--activerecord/test/cases/finder_test.rb1
-rw-r--r--activerecord/test/cases/fixtures_test.rb6
-rw-r--r--activerecord/test/cases/log_subscriber_test.rb18
-rw-r--r--activerecord/test/cases/method_scoping_test.rb3
-rw-r--r--activerecord/test/cases/named_scope_test.rb10
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb69
-rw-r--r--activerecord/test/cases/persistence_test.rb15
-rw-r--r--activerecord/test/cases/primary_keys_test.rb (renamed from activerecord/test/cases/pk_test.rb)4
-rw-r--r--activerecord/test/cases/query_cache_test.rb2
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb23
-rw-r--r--activerecord/test/cases/relations_test.rb1
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb1
-rw-r--r--activerecord/test/cases/validations/i18n_generate_message_validation_test.rb1
-rw-r--r--activerecord/test/cases/validations_test.rb5
-rw-r--r--activerecord/test/cases/xml_serialization_test.rb1
-rw-r--r--activerecord/test/fixtures/minivans.yml1
-rw-r--r--activerecord/test/models/country.rb7
-rw-r--r--activerecord/test/models/minivan.rb5
-rw-r--r--activerecord/test/models/person.rb2
-rw-r--r--activerecord/test/models/reference.rb5
-rw-r--r--activerecord/test/models/treaty.rb7
-rw-r--r--activerecord/test/schema/schema.rb16
-rw-r--r--activeresource/README.rdoc (renamed from activeresource/README)0
-rw-r--r--activeresource/Rakefile2
-rw-r--r--activeresource/activeresource.gemspec6
-rw-r--r--activesupport/README.rdoc (renamed from activesupport/README)15
-rw-r--r--activesupport/Rakefile2
-rw-r--r--activesupport/activesupport.gemspec2
-rw-r--r--activesupport/install.rb30
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/module/remove_method.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_param.rb2
-rw-r--r--activesupport/lib/active_support/log_subscriber.rb23
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb23
-rw-r--r--activesupport/lib/active_support/notifications.rb24
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb69
-rw-r--r--activesupport/lib/active_support/notifications/instrumenter.rb20
-rw-r--r--activesupport/test/buffered_logger_test.rb15
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb29
-rw-r--r--activesupport/test/multibyte_test_helpers.rb5
-rw-r--r--activesupport/test/notifications_test.rb32
-rw-r--r--railties/CHANGELOG14
-rw-r--r--railties/README281
-rw-r--r--railties/README.rdoc25
-rw-r--r--railties/Rakefile9
-rw-r--r--railties/guides/source/active_support_core_extensions.textile22
-rw-r--r--railties/guides/source/contributing_to_rails.textile57
-rw-r--r--railties/lib/rails/application.rb13
-rw-r--r--railties/lib/rails/commands/console.rb5
-rw-r--r--railties/lib/rails/configuration.rb5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb7
-rw-r--r--railties/lib/rails/railtie.rb18
-rw-r--r--railties/lib/rails/tasks/documentation.rake16
-rw-r--r--railties/railties.gemspec2
-rw-r--r--railties/test/application/console_test.rb21
-rw-r--r--railties/test/application/generators_test.rb15
-rw-r--r--railties/test/application/initializers/notifications_test.rb19
-rw-r--r--railties/test/railties/railtie_test.rb16
146 files changed, 1275 insertions, 1234 deletions
diff --git a/README.rdoc b/README.rdoc
new file mode 100644
index 0000000000..6198000279
--- /dev/null
+++ b/README.rdoc
@@ -0,0 +1,58 @@
+== Welcome to Rails
+
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
+
+This pattern splits the view (also called the presentation) into "dumb"
+templates that are primarily responsible for inserting pre-built data in between
+HTML tags. The model contains the "smart" domain objects (such as Account,
+Product, Person, Post) that holds all the business logic and knows how to
+persist themselves to a database. The controller handles the incoming requests
+(such as Save New Account, Update Product, Show Post) by manipulating the model
+and directing data to the view.
+
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
+
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
+
+
+== Getting Started
+
+1. Install Rails at the command prompt if you haven't yet:
+ <tt>gem install rails</tt>
+
+2. At the command prompt, create a new Rails application:
+ <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
+
+3. Change directory to <tt>myapp</tt> and start the web server:
+ <tt>cd myapp; rails server</tt> (run with --help for options)
+
+4. Go to http://localhost:3000/ and you'll see:
+ "Welcome aboard: You're riding Ruby on Rails!"
+
+5. Follow the guidelines to start developing your application. You can find
+the following resources handy:
+
+* The README file created within your application
+* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
+* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
+
+
+== Contributing
+
+Check out the contributing guide at http://edgeguides.rubyonrails.org/contributing_to_rails.html
+
+
+== License
+
+Ruby on Rails is released under the MIT license.
diff --git a/Rakefile b/Rakefile
index e608af0319..c49942c0bb 100644
--- a/Rakefile
+++ b/Rakefile
@@ -69,7 +69,7 @@ Rake::RDocTask.new do |rdoc|
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
- rdoc.options << '--main' << 'railties/README'
+ rdoc.options << '--main' << 'README.rdoc'
# Workaround: RDoc assumes that rdoc.template can be required, and that
# rdoc.template.upcase is a constant living in RDoc::Generator::HTML
@@ -83,38 +83,38 @@ Rake::RDocTask.new do |rdoc|
rdoc.rdoc_files.include('railties/CHANGELOG')
rdoc.rdoc_files.include('railties/MIT-LICENSE')
- rdoc.rdoc_files.include('railties/README')
+ rdoc.rdoc_files.include('railties/README.rdoc')
rdoc.rdoc_files.include('railties/lib/**/*.rb')
rdoc.rdoc_files.exclude('railties/lib/rails/generators/**/templates/*')
- rdoc.rdoc_files.include('activerecord/README')
+ rdoc.rdoc_files.include('activerecord/README.rdoc')
rdoc.rdoc_files.include('activerecord/CHANGELOG')
rdoc.rdoc_files.include('activerecord/lib/active_record/**/*.rb')
rdoc.rdoc_files.exclude('activerecord/lib/active_record/vendor/*')
- rdoc.rdoc_files.include('activeresource/README')
+ rdoc.rdoc_files.include('activeresource/README.rdoc')
rdoc.rdoc_files.include('activeresource/CHANGELOG')
rdoc.rdoc_files.include('activeresource/lib/active_resource.rb')
rdoc.rdoc_files.include('activeresource/lib/active_resource/*')
- rdoc.rdoc_files.include('actionpack/README')
+ rdoc.rdoc_files.include('actionpack/README.rdoc')
rdoc.rdoc_files.include('actionpack/CHANGELOG')
rdoc.rdoc_files.include('actionpack/lib/action_controller/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_dispatch/**/*.rb')
rdoc.rdoc_files.include('actionpack/lib/action_view/**/*.rb')
rdoc.rdoc_files.exclude('actionpack/lib/action_controller/vendor/*')
- rdoc.rdoc_files.include('actionmailer/README')
+ rdoc.rdoc_files.include('actionmailer/README.rdoc')
rdoc.rdoc_files.include('actionmailer/CHANGELOG')
rdoc.rdoc_files.include('actionmailer/lib/action_mailer/base.rb')
rdoc.rdoc_files.exclude('actionmailer/lib/action_mailer/vendor/*')
- rdoc.rdoc_files.include('activesupport/README')
+ rdoc.rdoc_files.include('activesupport/README.rdoc')
rdoc.rdoc_files.include('activesupport/CHANGELOG')
rdoc.rdoc_files.include('activesupport/lib/active_support/**/*.rb')
rdoc.rdoc_files.exclude('activesupport/lib/active_support/vendor/*')
- rdoc.rdoc_files.include('activemodel/README')
+ rdoc.rdoc_files.include('activemodel/README.rdoc')
rdoc.rdoc_files.include('activemodel/CHANGELOG')
rdoc.rdoc_files.include('activemodel/lib/active_model/**/*.rb')
end
diff --git a/actionmailer/README b/actionmailer/README.rdoc
index 2a4d507d8a..3dd56a6fd8 100644
--- a/actionmailer/README
+++ b/actionmailer/README.rdoc
@@ -126,36 +126,20 @@ or is accessible as a GEM.
Additionally, Action Mailer requires the Mail gem, http://github.com/mikel/mail
-== Bundled software
-
-* Text::Format 0.63 by Austin Ziegler released under OpenSource
- Read more on http://www.halostatue.ca/ruby/Text__Format.html
-
== Download
-The latest version of Action Mailer can be found at
+The latest version of Action Mailer can be installed with Rubygems:
-* http://rubyforge.org/project/showfiles.php?group_id=361
+* gem install actionmailer
Documentation can be found at
-* http://actionmailer.rubyonrails.org
-
-
-== Installation
-
-You can install Action Mailer with the following command.
-
- % [sudo] ruby install.rb
-
-from its distribution directory.
-
+* http://api.rubyonrails.org
== License
Action Mailer is released under the MIT license.
-
== Support
The Action Mailer homepage is http://www.rubyonrails.org. You can find
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index f20e7ea928..98aeae9818 100644
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -32,7 +32,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include('README', 'CHANGELOG')
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
rdoc.rdoc_files.include('lib/action_mailer.rb')
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
rdoc.rdoc_files.include('lib/action_mailer/delivery_method/*.rb')
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index fa0ee778c9..daf30e434a 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'actionmailer'
- s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*']
+ s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
s.requirements << 'none'
diff --git a/actionmailer/install.rb b/actionmailer/install.rb
deleted file mode 100644
index 8d7c140c3b..0000000000
--- a/actionmailer/install.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'rbconfig'
-require 'find'
-require 'ftools'
-
-include Config
-
-# this was adapted from rdoc's install.rb by way of Log4r
-
-$sitedir = CONFIG["sitelibdir"]
-unless $sitedir
- version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
- $libdir = File.join(CONFIG["libdir"], "ruby", version)
- $sitedir = $:.find {|x| x =~ /site_ruby/ }
- if !$sitedir
- $sitedir = File.join($libdir, "site_ruby")
- elsif $sitedir !~ Regexp.quote(version)
- $sitedir = File.join($sitedir, version)
- end
-end
-
-# the actual gruntwork
-Dir.chdir("lib")
-
-Find.find("action_mailer", "action_mailer.rb") { |f|
- if f[-3..-1] == ".rb"
- File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
- else
- File::makedirs(File.join($sitedir, *f.split(/\//)))
- end
-}
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 32aba2091a..6e07516a58 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [Release Candidate] (unreleased)*
+* Allow stylesheet/javascript extensions to be changed through railties. [Josh Kalderimis]
+
* link_to, button_to, and tag/tag_options now rely on html_escape instead of escape_once. [fxn]
* url_for returns always unescaped strings, and the :escape option is gone. [fxn]
diff --git a/actionpack/README b/actionpack/README.rdoc
index 1a59f728cc..272feb63d0 100644
--- a/actionpack/README
+++ b/actionpack/README.rdoc
@@ -19,15 +19,6 @@ the HTML. To avoid cluttering the templates with code, a bunch of helper
classes provide common behavior for forms, dates, and strings. And it's easy
to add specific helpers to keep the separation as the application evolves.
-Note: Some of the features, such as scaffolding and form building, are tied to
-ActiveRecord[http://activerecord.rubyonrails.org] (an object-relational
-mapping package), but that doesn't mean that Action Pack depends on Active
-Record. Action Pack is an independent package that can be used with any sort
-of backend (Instiki[http://www.instiki.org], which is based on an older version
-of Action Pack, used Madeleine for example). Read more about the role Action
-Pack can play when used together with Active Record on
-http://www.rubyonrails.org.
-
A short rundown of the major features:
* Actions grouped in controller as methods instead of separate command objects
@@ -366,22 +357,13 @@ an URL such as /weblog/5 (where 5 is the id of the post).
== Download
-The latest version of Action Pack can be found at
-
-* http://rubyforge.org/project/showfiles.php?group_id=249
-
-Documentation can be found at
-
-* http://api.rubyonrails.com
-
-
-== Installation
+The latest version of Action Pack can be installed with Rubygems:
-You can install Action Pack with the following command.
+* gem install actionpack
- % [sudo] ruby install.rb
+Documentation can be found at
-from its distribution directory.
+* http://api.rubyonrails.org
== License
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index aed5278e38..3a988d832d 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -47,7 +47,7 @@ Rake::RDocTask.new { |rdoc|
if ENV['DOC_FILES']
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
else
- rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
+ rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include(Dir['lib/**/*.rb'] -
Dir['lib/*/vendor/**/*.rb'])
rdoc.rdoc_files.exclude('lib/actionpack.rb')
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 9ce7ba5f02..99deff234c 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'actionpack'
- s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*']
+ s.files = Dir['CHANGELOG', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
s.requirements << 'none'
diff --git a/actionpack/install.rb b/actionpack/install.rb
deleted file mode 100644
index d3b83c3b00..0000000000
--- a/actionpack/install.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'rbconfig'
-require 'find'
-require 'ftools'
-
-include Config
-
-# this was adapted from rdoc's install.rb by way of Log4r
-
-$sitedir = CONFIG["sitelibdir"]
-unless $sitedir
- version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
- $libdir = File.join(CONFIG["libdir"], "ruby", version)
- $sitedir = $:.find {|x| x =~ /site_ruby/ }
- if !$sitedir
- $sitedir = File.join($libdir, "site_ruby")
- elsif $sitedir !~ Regexp.quote(version)
- $sitedir = File.join($sitedir, version)
- end
-end
-
-# the actual gruntwork
-Dir.chdir("lib")
-
-Find.find("action_controller", "action_controller.rb", "action_view", "action_view.rb") { |f|
- if f[-3..-1] == ".rb"
- File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
- else
- File::makedirs(File.join($sitedir, *f.split(/\//)))
- end
-} \ No newline at end of file
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 5990a1bbd0..c565c940a1 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -1,6 +1,7 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+require 'action_pack'
require 'active_support/ruby/shim'
require 'active_support/dependencies/autoload'
require 'active_support/core_ext/class/attribute'
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 1bd4572a47..ca0e5d6ff6 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -6,7 +6,6 @@ module ActionController
autoload :Base
autoload :Caching
- autoload :PolymorphicRoutes
autoload :Metal
autoload :Middleware
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 1a2cbaab65..1c6896d362 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -28,7 +28,6 @@ module ActionController
SessionManagement,
Caching,
MimeResponds,
- PolymorphicRoutes,
ImplicitRender,
Cookies,
@@ -69,4 +68,4 @@ module ActionController
end
end
-require "action_controller/deprecated/base" \ No newline at end of file
+require "action_controller/deprecated/base"
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index b2c119d7e4..b08d9a8434 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -1,3 +1,4 @@
+require 'benchmark'
require 'abstract_controller/logger'
module ActionController
diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb
index bbca1b2179..eb037aa1b0 100644
--- a/actionpack/lib/action_controller/metal/rescue.rb
+++ b/actionpack/lib/action_controller/metal/rescue.rb
@@ -3,6 +3,15 @@ module ActionController #:nodoc:
extend ActiveSupport::Concern
include ActiveSupport::Rescuable
+ def rescue_with_handler(exception)
+ if (exception.respond_to?(:original_exception) &&
+ (orig_exception = exception.original_exception) &&
+ handler_for_rescue(orig_exception))
+ exception = orig_exception
+ end
+ super(exception)
+ end
+
private
def process_action(*args)
super
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 753af3dc58..d75b46dace 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/file/path'
+
module ActionController #:nodoc:
# Methods for sending arbitrary data and for streaming files to the browser,
# instead of rendering.
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
deleted file mode 100644
index bee50a7a3b..0000000000
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ /dev/null
@@ -1,183 +0,0 @@
-module ActionController
- # Polymorphic URL helpers are methods for smart resolution to a named route call when
- # given an Active Record model instance. They are to be used in combination with
- # ActionController::Resources.
- #
- # These methods are useful when you want to generate correct URL or path to a RESTful
- # resource without having to know the exact type of the record in question.
- #
- # Nested resources and/or namespaces are also supported, as illustrated in the example:
- #
- # polymorphic_url([:admin, @article, @comment])
- #
- # results in:
- #
- # admin_article_comment_url(@article, @comment)
- #
- # == Usage within the framework
- #
- # Polymorphic URL helpers are used in a number of places throughout the Rails framework:
- #
- # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
- # <tt>url_for(@article)</tt>;
- # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
- # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
- # action;
- # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
- # <tt>redirect_to(post)</tt> in your controllers;
- # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs
- # for feed entries.
- #
- # == Prefixed polymorphic helpers
- #
- # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
- # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
- # in options. Those are:
- #
- # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
- # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt>
- #
- # Example usage:
- #
- # edit_polymorphic_path(@post) # => "/posts/1/edit"
- # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
- module PolymorphicRoutes
- # Constructs a call to a named RESTful route for the given record and returns the
- # resulting URL string. For example:
- #
- # # calls post_url(post)
- # polymorphic_url(post) # => "http://example.com/posts/1"
- # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
- # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
- # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
- # polymorphic_url(Comment) # => "http://example.com/comments"
- #
- # ==== Options
- #
- # * <tt>:action</tt> - Specifies the action prefix for the named route:
- # <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix.
- # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
- # Default is <tt>:url</tt>.
- #
- # ==== Examples
- #
- # # an Article record
- # polymorphic_url(record) # same as article_url(record)
- #
- # # a Comment record
- # polymorphic_url(record) # same as comment_url(record)
- #
- # # it recognizes new records and maps to the collection
- # record = Comment.new
- # polymorphic_url(record) # same as comments_url()
- #
- # # the class of a record will also map to the collection
- # polymorphic_url(Comment) # same as comments_url()
- #
- def polymorphic_url(record_or_hash_or_array, options = {})
- if record_or_hash_or_array.kind_of?(Array)
- record_or_hash_or_array = record_or_hash_or_array.compact
- record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
- end
-
- record = extract_record(record_or_hash_or_array)
- record = record.to_model if record.respond_to?(:to_model)
-
- args = case record_or_hash_or_array
- when Hash; [ record_or_hash_or_array ]
- when Array; record_or_hash_or_array.dup
- else [ record_or_hash_or_array ]
- end
-
- inflection = if options[:action].to_s == "new"
- args.pop
- :singular
- elsif (record.respond_to?(:persisted?) && !record.persisted?)
- args.pop
- :plural
- elsif record.is_a?(Class)
- args.pop
- :plural
- else
- :singular
- end
-
- args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
- named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
-
- url_options = options.except(:action, :routing_type)
- unless url_options.empty?
- args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
- end
-
- __send__(named_route, *args)
- end
-
- # Returns the path component of a URL for the given record. It uses
- # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
- def polymorphic_path(record_or_hash_or_array, options = {})
- polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
- end
-
- %w(edit new).each do |action|
- module_eval <<-EOT, __FILE__, __LINE__ + 1
- def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
- polymorphic_url( # polymorphic_url(
- record_or_hash, # record_or_hash,
- options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
- end # end
- #
- def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
- polymorphic_url( # polymorphic_url(
- record_or_hash, # record_or_hash,
- options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
- end # end
- EOT
- end
-
- private
- def action_prefix(options)
- options[:action] ? "#{options[:action]}_" : ''
- end
-
- def routing_type(options)
- options[:routing_type] || :url
- end
-
- def build_named_route_call(records, inflection, options = {})
- unless records.is_a?(Array)
- record = extract_record(records)
- route = ''
- else
- record = records.pop
- route = records.inject("") do |string, parent|
- if parent.is_a?(Symbol) || parent.is_a?(String)
- string << "#{parent}_"
- else
- string << RecordIdentifier.__send__("plural_class_name", parent).singularize
- string << "_"
- end
- end
- end
-
- if record.is_a?(Symbol) || record.is_a?(String)
- route << "#{record}_"
- else
- route << RecordIdentifier.__send__("plural_class_name", record)
- route = route.singularize if inflection == :singular
- route << "_"
- route << "index_" if RecordIdentifier.uncountable?(record) && inflection == :plural
- end
-
- action_prefix(options) + route + routing_type(options).to_s
- end
-
- def extract_record(record_or_hash_or_array)
- case record_or_hash_or_array
- when Array; record_or_hash_or_array.last
- when Hash; record_or_hash_or_array[:id]
- else record_or_hash_or_array
- end
- end
- end
-end
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index d20c3b64c5..3de40b0de3 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -46,7 +46,7 @@ module ActionController
# dom_class(post, :edit) # => "edit_post"
# dom_class(Person, :edit) # => "edit_person"
def dom_class(record_or_class, prefix = nil)
- singular = singular_class_name(record_or_class)
+ singular = ActiveModel::Naming.singular(record_or_class)
prefix ? "#{prefix}#{JOIN}#{singular}" : singular
end
@@ -67,6 +67,8 @@ module ActionController
end
end
+ protected
+
# Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
# This can be overwritten to customize the default generated string representation if desired.
# If you need to read back a key from a dom_id in order to query for the underlying database record,
@@ -85,34 +87,5 @@ module ActionController
def sanitize_dom_id(candidate_id)
candidate_id # TODO implement conversion to valid DOM id values
end
-
- # Returns the plural class name of a record or class. Examples:
- #
- # plural_class_name(post) # => "posts"
- # plural_class_name(Highrise::Person) # => "highrise_people"
- def plural_class_name(record_or_class)
- model_name_from_record_or_class(record_or_class).plural
- end
-
- # Returns the singular class name of a record or class. Examples:
- #
- # singular_class_name(post) # => "post"
- # singular_class_name(Highrise::Person) # => "highrise_person"
- def singular_class_name(record_or_class)
- model_name_from_record_or_class(record_or_class).singular
- end
-
- # Identifies whether the class name of a record or class is uncountable. Examples:
- #
- # uncountable?(Sheep) # => true
- # uncountable?(Post) => false
- def uncountable?(record_or_class)
- plural_class_name(record_or_class) == singular_class_name(record_or_class)
- end
-
- private
- def model_name_from_record_or_class(record_or_class)
- (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
- end
end
end
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index cdf81c6648..50d8e91c47 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -24,9 +24,14 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
+$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
+
require 'active_support'
require 'active_support/dependencies/autoload'
+require 'action_pack'
+require 'active_model'
require 'rack'
module Rack
@@ -63,6 +68,7 @@ module ActionDispatch
autoload :Headers
autoload :MimeNegotiation
autoload :Parameters
+ autoload :ParameterFilter
autoload :FilterParameters
autoload :Upload
autoload :UploadedFile, 'action_dispatch/http/upload'
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 152aaa2e67..1ab48ae04d 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -26,88 +26,32 @@ module ActionDispatch
module FilterParameters
extend ActiveSupport::Concern
- @@compiled_parameter_filter_for = {}
+ @@parameter_filter_for = {}
# Return a hash of parameters with all sensitive data replaced.
def filtered_parameters
- @filtered_parameters ||= if filtering_parameters?
- process_parameter_filter(parameters)
- else
- parameters.dup
- end
+ @filtered_parameters ||= parameter_filter.filter(parameters)
end
- alias :fitered_params :filtered_parameters
# Return a hash of request.env with all sensitive data replaced.
def filtered_env
- filtered_env = @env.dup
- filtered_env.each do |key, value|
- if (key =~ /RAW_POST_DATA/i)
- filtered_env[key] = '[FILTERED]'
- elsif value.is_a?(Hash)
- filtered_env[key] = process_parameter_filter(value)
- end
- end
- filtered_env
+ @filtered_env ||= env_filter.filter(@env)
end
protected
- def filtering_parameters? #:nodoc:
- @env["action_dispatch.parameter_filter"].present?
+ def parameter_filter
+ parameter_filter_for(@env["action_dispatch.parameter_filter"])
end
- def process_parameter_filter(params) #:nodoc:
- compiled_parameter_filter_for(@env["action_dispatch.parameter_filter"]).call(params)
+ def env_filter
+ parameter_filter_for(Array.wrap(@env["action_dispatch.parameter_filter"]) << /RAW_POST_DATA/)
end
- def compile_parameter_filter(filters) #:nodoc:
- strings, regexps, blocks = [], [], []
-
- filters.each do |item|
- case item
- when NilClass
- when Proc
- blocks << item
- when Regexp
- regexps << item
- else
- strings << item.to_s
- end
- end
-
- regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
- [regexps, blocks]
- end
-
- def compiled_parameter_filter_for(filters) #:nodoc:
- @@compiled_parameter_filter_for[filters] ||= begin
- regexps, blocks = compile_parameter_filter(filters)
-
- lambda do |original_params|
- filtered_params = {}
-
- original_params.each do |key, value|
- if regexps.find { |r| key =~ r }
- value = '[FILTERED]'
- elsif value.is_a?(Hash)
- value = process_parameter_filter(value)
- elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? process_parameter_filter(v) : v }
- elsif blocks.present?
- key = key.dup
- value = value.dup if value.duplicable?
- blocks.each { |b| b.call(key, value) }
- end
-
- filtered_params[key] = value
- end
-
- filtered_params
- end
- end
+ def parameter_filter_for(filters)
+ @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
new file mode 100644
index 0000000000..1480e8f77c
--- /dev/null
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -0,0 +1,72 @@
+module ActionDispatch
+ module Http
+ class ParameterFilter
+
+ def initialize(filters)
+ @filters = filters
+ end
+
+ def filter(params)
+ if enabled?
+ compiled_filter.call(params)
+ else
+ params.dup
+ end
+ end
+
+ private
+
+ def enabled?
+ @filters.present?
+ end
+
+ def compiled_filter
+ @compiled_filter ||= begin
+ regexps, blocks = compile_filter
+
+ lambda do |original_params|
+ filtered_params = {}
+
+ original_params.each do |key, value|
+ if regexps.find { |r| key =~ r }
+ value = '[FILTERED]'
+ elsif value.is_a?(Hash)
+ value = filter(value)
+ elsif value.is_a?(Array)
+ value = value.map { |v| v.is_a?(Hash) ? filter(v) : v }
+ elsif blocks.present?
+ key = key.dup
+ value = value.dup if value.duplicable?
+ blocks.each { |b| b.call(key, value) }
+ end
+
+ filtered_params[key] = value
+ end
+
+ filtered_params
+ end
+ end
+ end
+
+ def compile_filter
+ strings, regexps, blocks = [], [], []
+
+ @filters.each do |item|
+ case item
+ when NilClass
+ when Proc
+ blocks << item
+ when Regexp
+ regexps << item
+ else
+ strings << item.to_s
+ end
+ end
+
+ regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
+ [regexps, blocks]
+ end
+
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 64f4d1d532..ad98249468 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -24,9 +24,9 @@ module ActionDispatch
def [](key)
if key == :id
- load_session_id! unless super(:id) || has_session_id?
+ load_session_id! unless key?(:id) || has_session_id?
end
- super(key)
+ super
end
private
@@ -191,8 +191,11 @@ module ActionDispatch
def load_session(env)
stale_session_check! do
- sid = current_session_id(env)
- sid, session = get_session(env, sid)
+ if sid = current_session_id(env)
+ sid, session = get_session(env, sid)
+ else
+ sid, session = generate_sid, {}
+ end
[sid, session]
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
index 28e3dbd732..5304440418 100644
--- a/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
@@ -25,7 +25,6 @@ module ActionDispatch
private
def get_session(env, sid)
- sid ||= generate_sid
begin
session = @pool.get(sid) || {}
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index 4618f3befc..41078eced7 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -46,7 +46,7 @@ module ActionDispatch
end
def insert(index, *args, &block)
- index = self.index(index) unless index.is_a?(Integer)
+ index = assert_index(index, :before)
middleware = self.class::Middleware.new(*args, &block)
super(index, middleware)
end
@@ -54,9 +54,8 @@ module ActionDispatch
alias_method :insert_before, :insert
def insert_after(index, *args, &block)
- i = index.is_a?(Integer) ? index : self.index(index)
- raise "No such middleware to insert after: #{index.inspect}" unless i
- insert(i + 1, *args, &block)
+ index = assert_index(index, :after)
+ insert(index + 1, *args, &block)
end
def swap(target, *args, &block)
@@ -79,5 +78,13 @@ module ActionDispatch
raise "MiddlewareStack#build requires an app" unless app
reverse.inject(app) { |a, e| e.build(a) }
end
+
+ protected
+
+ def assert_index(index, where)
+ i = index.is_a?(Integer) ? index : self.index(index)
+ raise "No such middleware to insert #{where}: #{index.inspect}" unless i
+ i
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 8afc685fdf..683dd72555 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -1,6 +1,5 @@
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/regexp'
-require 'action_controller/polymorphic_routes'
module ActionDispatch
# = Routing
@@ -217,13 +216,14 @@ module ActionDispatch
autoload :Route, 'action_dispatch/routing/route'
autoload :RouteSet, 'action_dispatch/routing/route_set'
autoload :UrlFor, 'action_dispatch/routing/url_for'
+ autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
SEPARATORS = %w( / . ? ) #:nodoc:
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options] #:nodoc:
# A helper module to hold URL related helpers.
module Helpers #:nodoc:
- include ActionController::PolymorphicRoutes
+ include PolymorphicRoutes
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
new file mode 100644
index 0000000000..31dba835ac
--- /dev/null
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -0,0 +1,186 @@
+module ActionDispatch
+ module Routing
+ # Polymorphic URL helpers are methods for smart resolution to a named route call when
+ # given an Active Record model instance. They are to be used in combination with
+ # ActionController::Resources.
+ #
+ # These methods are useful when you want to generate correct URL or path to a RESTful
+ # resource without having to know the exact type of the record in question.
+ #
+ # Nested resources and/or namespaces are also supported, as illustrated in the example:
+ #
+ # polymorphic_url([:admin, @article, @comment])
+ #
+ # results in:
+ #
+ # admin_article_comment_url(@article, @comment)
+ #
+ # == Usage within the framework
+ #
+ # Polymorphic URL helpers are used in a number of places throughout the Rails framework:
+ #
+ # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
+ # <tt>url_for(@article)</tt>;
+ # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
+ # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
+ # action;
+ # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
+ # <tt>redirect_to(post)</tt> in your controllers;
+ # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs
+ # for feed entries.
+ #
+ # == Prefixed polymorphic helpers
+ #
+ # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
+ # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
+ # in options. Those are:
+ #
+ # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
+ # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt>
+ #
+ # Example usage:
+ #
+ # edit_polymorphic_path(@post) # => "/posts/1/edit"
+ # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
+ module PolymorphicRoutes
+ # Constructs a call to a named RESTful route for the given record and returns the
+ # resulting URL string. For example:
+ #
+ # # calls post_url(post)
+ # polymorphic_url(post) # => "http://example.com/posts/1"
+ # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
+ # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
+ # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
+ # polymorphic_url(Comment) # => "http://example.com/comments"
+ #
+ # ==== Options
+ #
+ # * <tt>:action</tt> - Specifies the action prefix for the named route:
+ # <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix.
+ # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
+ # Default is <tt>:url</tt>.
+ #
+ # ==== Examples
+ #
+ # # an Article record
+ # polymorphic_url(record) # same as article_url(record)
+ #
+ # # a Comment record
+ # polymorphic_url(record) # same as comment_url(record)
+ #
+ # # it recognizes new records and maps to the collection
+ # record = Comment.new
+ # polymorphic_url(record) # same as comments_url()
+ #
+ # # the class of a record will also map to the collection
+ # polymorphic_url(Comment) # same as comments_url()
+ #
+ def polymorphic_url(record_or_hash_or_array, options = {})
+ if record_or_hash_or_array.kind_of?(Array)
+ record_or_hash_or_array = record_or_hash_or_array.compact
+ record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
+ end
+
+ record = extract_record(record_or_hash_or_array)
+ record = record.to_model if record.respond_to?(:to_model)
+
+ args = case record_or_hash_or_array
+ when Hash; [ record_or_hash_or_array ]
+ when Array; record_or_hash_or_array.dup
+ else [ record_or_hash_or_array ]
+ end
+
+ inflection = if options[:action].to_s == "new"
+ args.pop
+ :singular
+ elsif (record.respond_to?(:persisted?) && !record.persisted?)
+ args.pop
+ :plural
+ elsif record.is_a?(Class)
+ args.pop
+ :plural
+ else
+ :singular
+ end
+
+ args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
+ named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
+
+ url_options = options.except(:action, :routing_type)
+ unless url_options.empty?
+ args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
+ end
+
+ send(named_route, *args)
+ end
+
+ # Returns the path component of a URL for the given record. It uses
+ # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
+ def polymorphic_path(record_or_hash_or_array, options = {})
+ polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
+ end
+
+ %w(edit new).each do |action|
+ module_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
+ polymorphic_url( # polymorphic_url(
+ record_or_hash, # record_or_hash,
+ options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
+ end # end
+ #
+ def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
+ polymorphic_url( # polymorphic_url(
+ record_or_hash, # record_or_hash,
+ options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
+ end # end
+ EOT
+ end
+
+ private
+ def action_prefix(options)
+ options[:action] ? "#{options[:action]}_" : ''
+ end
+
+ def routing_type(options)
+ options[:routing_type] || :url
+ end
+
+ def build_named_route_call(records, inflection, options = {})
+ unless records.is_a?(Array)
+ record = extract_record(records)
+ route = ''
+ else
+ record = records.pop
+ route = records.inject("") do |string, parent|
+ if parent.is_a?(Symbol) || parent.is_a?(String)
+ string << "#{parent}_"
+ else
+ string << ActiveModel::Naming.plural(parent).singularize
+ string << "_"
+ end
+ end
+ end
+
+ if record.is_a?(Symbol) || record.is_a?(String)
+ route << "#{record}_"
+ else
+ route << ActiveModel::Naming.plural(record)
+ route = route.singularize if inflection == :singular
+ route << "_"
+ route << "index_" if ActiveModel::Naming.uncountable?(record) && inflection == :plural
+ end
+
+ action_prefix(options) + route + routing_type(options).to_s
+ end
+
+ def extract_record(record_or_hash_or_array)
+ case record_or_hash_or_array
+ when Array; record_or_hash_or_array.last
+ when Hash; record_or_hash_or_array[:id]
+ else record_or_hash_or_array
+ end
+ 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 36c52eb65a..a9b97a17eb 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -414,7 +414,8 @@ module ActionDispatch
elsif value.is_a?(Array)
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
else
- Rack::Mount::Utils.escape_uri(value.to_param)
+ return nil unless param = value.to_param
+ param.split('/').map { |v| Rack::Mount::Utils.escape_uri(v) }.join("/")
end
end
{:parameterize => parameterize}
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index 980abd44df..662eb05c26 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -82,6 +82,7 @@ module ActionDispatch
#
module UrlFor
extend ActiveSupport::Concern
+ include PolymorphicRoutes
included do
# TODO: with_routing extends @controller with url_helpers, trickling down to including this module which overrides its default_url_options
diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb
index 0e4a92048f..822150b768 100644
--- a/actionpack/lib/action_dispatch/testing/assertions.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions.rb
@@ -1,7 +1,6 @@
module ActionDispatch
module Assertions
autoload :DomAssertions, 'action_dispatch/testing/assertions/dom'
- autoload :ModelAssertions, 'action_dispatch/testing/assertions/model'
autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response'
autoload :RoutingAssertions, 'action_dispatch/testing/assertions/routing'
autoload :SelectorAssertions, 'action_dispatch/testing/assertions/selector'
@@ -11,7 +10,6 @@ module ActionDispatch
included do
include DomAssertions
- include ModelAssertions
include ResponseAssertions
include RoutingAssertions
include SelectorAssertions
diff --git a/actionpack/lib/action_dispatch/testing/assertions/model.rb b/actionpack/lib/action_dispatch/testing/assertions/model.rb
deleted file mode 100644
index 46714418c6..0000000000
--- a/actionpack/lib/action_dispatch/testing/assertions/model.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module ActionDispatch
- module Assertions
- module ModelAssertions
- # Ensures that the passed record is valid by Active Record standards and
- # returns any error messages if it is not.
- #
- # ==== Examples
- #
- # # assert that a newly created record is valid
- # model = Model.new
- # assert_valid(model)
- #
- def assert_valid(record)
- ::ActiveSupport::Deprecation.warn("assert_valid is deprecated. Use assert record.valid? instead", caller)
- assert record.valid?, record.errors.full_messages.join("\n")
- end
- end
- end
-end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 9f56cca869..c0d7423682 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -23,6 +23,7 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
+
require 'active_support/ruby/shim'
require 'active_support/core_ext/class/attribute_accessors'
diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb
index ba3bdd0d18..b7ffa345cc 100644
--- a/actionpack/lib/action_view/helpers.rb
+++ b/actionpack/lib/action_view/helpers.rb
@@ -20,7 +20,6 @@ module ActionView #:nodoc:
autoload :NumberHelper
autoload :PrototypeHelper
autoload :RawOutputHelper
- autoload :RecordIdentificationHelper
autoload :RecordTagHelper
autoload :SanitizeHelper
autoload :ScriptaculousHelper
@@ -51,7 +50,6 @@ module ActionView #:nodoc:
include NumberHelper
include PrototypeHelper
include RawOutputHelper
- include RecordIdentificationHelper
include RecordTagHelper
include SanitizeHelper
include ScriptaculousHelper
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f097b9a5a3..8050669adb 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -800,7 +800,8 @@ module ActionView
start = options.delete(:start) || 0
stop = options.delete(:end) || 59
step = options.delete(:step) || 1
- leading_zeros = options.delete(:leading_zeros).nil? ? true : false
+ options.reverse_merge!({:leading_zeros => true})
+ leading_zeros = options.delete(:leading_zeros)
select_options = []
start.step(stop, step) do |i|
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index b8c163e1c2..b0af836522 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -298,12 +298,12 @@ module ActionView
object_name = record_or_name_or_array
when Array
object = record_or_name_or_array.last
- object_name = options[:as] || ActionController::RecordIdentifier.singular_class_name(object)
+ object_name = options[:as] || ActiveModel::Naming.singular(object)
apply_form_for_options!(record_or_name_or_array, options)
args.unshift object
else
object = record_or_name_or_array
- object_name = options[:as] || ActionController::RecordIdentifier.singular_class_name(object)
+ object_name = options[:as] || ActiveModel::Naming.singular(object)
apply_form_for_options!([object], options)
args.unshift object
end
@@ -529,7 +529,7 @@ module ActionView
object = args.first
else
object = record_or_name_or_array
- object_name = ActionController::RecordIdentifier.singular_class_name(object)
+ object_name = ActiveModel::Naming.singular(object)
end
builder = options[:builder] || ActionView::Base.default_form_builder
@@ -1152,11 +1152,11 @@ module ActionView
end
when Array
object = record_or_name_or_array.last
- name = "#{object_name}#{index}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
+ name = "#{object_name}#{index}[#{ActiveModel::Naming.singular(object)}]"
args.unshift(object)
else
object = record_or_name_or_array
- name = "#{object_name}#{index}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
+ name = "#{object_name}#{index}[#{ActiveModel::Naming.singular(object)}]"
args.unshift(object)
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 6f9d14de8b..ee34452769 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -447,7 +447,7 @@ module ActionView
# wrap the output in an appropriate <tt><select></tt> tag.
def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
body = ''
- body << content_tag(:option, prompt, :value => "") if prompt
+ body << content_tag(:option, prompt, { :value => "" }, true) if prompt
grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
@@ -593,11 +593,11 @@ module ActionView
private
def add_options(option_tags, options, value = nil)
if options[:include_blank]
- option_tags = "<option value=\"\">#{options[:include_blank] if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
+ option_tags = "<option value=\"\">#{html_escape(options[:include_blank]) if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
end
if value.blank? && options[:prompt]
prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- option_tags = "<option value=\"\">#{prompt}</option>\n" + option_tags
+ option_tags = "<option value=\"\">#{html_escape(prompt)}</option>\n" + option_tags
end
option_tags.html_safe
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 5c0ff5d59c..28b8a27eef 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -139,7 +139,7 @@ module ActionView
function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
- return function
+ return function.html_safe
end
# All the methods were moved to GeneratorMethods so that
diff --git a/actionpack/lib/action_view/helpers/record_identification_helper.rb b/actionpack/lib/action_view/helpers/record_identification_helper.rb
deleted file mode 100644
index 372f1cb8aa..0000000000
--- a/actionpack/lib/action_view/helpers/record_identification_helper.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-module ActionView
- # = Action View Record Identification Helpers
- #
- # See ActionController::RecordIdentifier for documentation on these methods.
- module Helpers
- module RecordIdentificationHelper
- # See ActionController::RecordIdentifier.partial_path -- this is just a delegate to that for convenient access in the view.
- def partial_path(*args, &block)
- ActionController::RecordIdentifier.partial_path(*args, &block)
- end
-
- # See ActionController::RecordIdentifier.dom_class -- this is just a delegate to that for convenient access in the view.
- def dom_class(*args, &block)
- ActionController::RecordIdentifier.dom_class(*args, &block)
- end
-
- # See ActionController::RecordIdentifier.dom_id -- this is just a delegate to that for convenient access in the view.
- def dom_id(*args, &block)
- ActionController::RecordIdentifier.dom_id(*args, &block)
- end
- end
- end
-end \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb
index 7433f08777..e4a9210cde 100644
--- a/actionpack/lib/action_view/helpers/record_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb
@@ -1,7 +1,11 @@
+require 'action_controller/record_identifier'
+
module ActionView
# = Action View Record Tag Helpers
module Helpers
module RecordTagHelper
+ include ActionController::RecordIdentifier
+
# Produces a wrapper DIV element with id and class parameters that
# relate to the specified Active Record object. Usage example:
#
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 0e3cc54fd1..b493a0cb0e 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -398,7 +398,7 @@ module ActionView
def link_to_unless(condition, name, options = {}, html_options = {}, &block)
if condition
if block_given?
- block.arity <= 1 ? yield(name) : yield(name, options, html_options)
+ block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
else
name
end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 56aebca957..137281e5e9 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -37,7 +37,7 @@ module ActionView
include ActionController::TemplateAssertions
include ActionView::Context
- include ActionController::PolymorphicRoutes
+ include ActionDispatch::Routing::PolymorphicRoutes
include ActionController::RecordIdentifier
include AbstractController::Helpers
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 765e111226..53cdd358b4 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -482,21 +482,6 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
assert_redirected_to :controller => 'admin/user'
end
- def test_assert_valid
- get :get_valid_record
- assert_deprecated { assert_valid assigns('record') }
- end
-
- def test_assert_valid_failing
- get :get_invalid_record
-
- begin
- assert_deprecated { assert_valid assigns('record') }
- assert false
- rescue ActiveSupport::TestCase::Assertion => e
- end
- end
-
def test_assert_response_uses_exception_message
@controller = AssertResponseWithUnexpectedErrorController.new
get :index
diff --git a/actionpack/test/controller/record_identifier_test.rb b/actionpack/test/controller/record_identifier_test.rb
index 6a84475758..835a0e970b 100644
--- a/actionpack/test/controller/record_identifier_test.rb
+++ b/actionpack/test/controller/record_identifier_test.rb
@@ -26,20 +26,6 @@ class Sheep
end
end
-class Comment::Nested < Comment; end
-
-class Test::Unit::TestCase
- protected
- def comments_url
- 'http://www.example.com/comments'
- end
-
- def comment_url(comment)
- "http://www.example.com/comments/#{comment.id}"
- end
-end
-
-
class RecordIdentifierTest < Test::Unit::TestCase
include ActionController::RecordIdentifier
@@ -76,30 +62,4 @@ class RecordIdentifierTest < Test::Unit::TestCase
def test_dom_class_with_prefix
assert_equal "custom_prefix_#{@singular}", dom_class(@record, :custom_prefix)
end
-
- def test_singular_class_name
- assert_equal @singular, singular_class_name(@record)
- end
-
- def test_singular_class_name_for_class
- assert_equal @singular, singular_class_name(@klass)
- end
-
- def test_plural_class_name
- assert_equal @plural, plural_class_name(@record)
- end
-
- def test_plural_class_name_for_class
- assert_equal @plural, plural_class_name(@klass)
- end
-
- def test_uncountable
- assert_equal true, uncountable?(@uncountable)
- assert_equal false, uncountable?(@klass)
- end
-
- private
- def method_missing(method, *args)
- RecordIdentifier.send(method, *args)
- end
end
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 0f64b77647..a24de62b19 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -79,6 +79,14 @@ class RescueController < ActionController::Base
render :text => 'no way'
end
+ rescue_from ActionView::TemplateError do
+ render :text => 'action_view templater error'
+ end
+
+ rescue_from IOError do
+ render :text => 'io error'
+ end
+
before_filter(:only => :before_filter_raises) { raise 'umm nice' }
def before_filter_raises
@@ -141,6 +149,14 @@ class RescueController < ActionController::Base
def missing_template
end
+
+ def io_error_in_view
+ raise ActionView::TemplateError.new(nil, {}, IOError.new('this is io error'))
+ end
+
+ def zero_division_error_in_view
+ raise ActionView::TemplateError.new(nil, {}, ZeroDivisionError.new('this is zero division error'))
+ end
protected
def deny_access
@@ -228,6 +244,17 @@ class ControllerInheritanceRescueControllerTest < ActionController::TestCase
end
class RescueControllerTest < ActionController::TestCase
+
+ def test_io_error_in_view
+ get :io_error_in_view
+ assert_equal 'io error', @response.body
+ end
+
+ def test_zero_division_error_in_view
+ get :zero_division_error_in_view
+ assert_equal 'action_view templater error', @response.body
+ end
+
def test_rescue_handler
get :not_authorized
assert_response :forbidden
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index f9fc7a0976..950ad9266f 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -461,6 +461,13 @@ XML
def test_assert_routing_in_module
assert_routing 'admin/user', :controller => 'admin/user', :action => 'index'
end
+
+ def test_assert_routing_with_glob
+ with_routing do |set|
+ set.draw { |map| match('*path' => "pages#show") }
+ assert_routing('/company/about', { :controller => 'pages', :action => 'show', :path => 'company/about' })
+ end
+ end
def test_params_passing
get :test_params, :page => {:name => "Page name", :month => '4', :year => '2004', :day => '6'}
diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb
index 170c5b8565..6a1a4f556f 100644
--- a/actionpack/test/dispatch/middleware_stack_test.rb
+++ b/actionpack/test/dispatch/middleware_stack_test.rb
@@ -66,6 +66,16 @@ class MiddlewareStackTest < ActiveSupport::TestCase
assert_equal BazMiddleware, @stack[0].klass
end
+ test "raise an error on invalid index" do
+ assert_raise RuntimeError do
+ @stack.insert("HiyaMiddleware", BazMiddleware)
+ end
+
+ assert_raise RuntimeError do
+ @stack.insert_after("HiyaMiddleware", BazMiddleware)
+ end
+ end
+
test "lazy evaluates middleware class" do
assert_difference "@stack.size" do
@stack.use "MiddlewareStackTest::BazMiddleware"
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index e5ee412021..c8947aac80 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -392,19 +392,19 @@ class RequestTest < ActiveSupport::TestCase
[{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
test_hashes.each do |before_filter, after_filter, filter_words|
- request = stub_request('action_dispatch.parameter_filter' => filter_words)
- assert_equal after_filter, request.send(:process_parameter_filter, before_filter)
+ parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
+ assert_equal after_filter, parameter_filter.filter(before_filter)
filter_words << 'blah'
filter_words << lambda { |key, value|
value.reverse! if key =~ /bargain/
}
- request = stub_request('action_dispatch.parameter_filter' => filter_words)
+ parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
- assert_equal after_filter, request.send(:process_parameter_filter, before_filter)
+ assert_equal after_filter, parameter_filter.filter(before_filter)
end
end
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index f0e01bfff0..3864821ef0 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -44,7 +44,12 @@ class CookieStoreTest < ActionController::IntegrationTest
session[:foo] = 'bye!' * 1024
head :ok
end
-
+
+ def change_session_id
+ request.session_options[:id] = nil
+ get_session_id
+ end
+
def rescue_action(e) raise end
end
@@ -212,6 +217,19 @@ class CookieStoreTest < ActionController::IntegrationTest
end
end
+ def test_setting_session_id_to_nil_is_respected
+ with_test_route_set do
+ cookies[SessionKey] = SignedBar
+
+ get "/get_session_id"
+ sid = response.body
+ assert_equal sid.size, 36
+
+ get "/change_session_id"
+ assert_not_equal sid, response.body
+ end
+ end
+
def test_session_store_with_expire_after
with_test_route_set(:expire_after => 5.hours) do
# First request accesses the session
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 65b5f5ccc1..d14e5020c7 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -210,6 +210,12 @@ class FormOptionsHelperTest < ActionView::TestCase
assert grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]]).html_safe?
end
+ def test_grouped_options_for_select_with_prompt_returns_html_escaped_string
+ assert_dom_equal(
+ "<option value=\"\">&lt;Choose One&gt;</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, '<Choose One>'))
+ end
+
def test_optgroups_with_with_options_with_hash
assert_dom_equal(
"<optgroup label=\"Europe\"><option value=\"Denmark\">Denmark</option>\n<option value=\"Germany\">Germany</option></optgroup><optgroup label=\"North America\"><option value=\"United States\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup>",
@@ -367,6 +373,15 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_select_with_blank_as_string_escaped
+ @post = Post.new
+ @post.category = "<mus>"
+ assert_dom_equal(
+ "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">&lt;None&gt;</option>\n<option value=\"abe\">abe</option>\n<option value=\"&lt;mus&gt;\" selected=\"selected\">&lt;mus&gt;</option>\n<option value=\"hest\">hest</option></select>",
+ select("post", "category", %w( abe <mus> hest), :include_blank => '<None>')
+ )
+ end
+
def test_select_with_default_prompt
@post = Post.new
@post.category = ""
@@ -394,6 +409,14 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_select_with_given_prompt_escaped
+ @post = Post.new
+ assert_dom_equal(
+ "<select id=\"post_category\" name=\"post[category]\"><option value=\"\">&lt;The prompt&gt;</option>\n<option value=\"abe\">abe</option>\n<option value=\"&lt;mus&gt;\">&lt;mus&gt;</option>\n<option value=\"hest\">hest</option></select>",
+ select("post", "category", %w( abe <mus> hest), :prompt => '<The prompt>')
+ )
+ end
+
def test_select_with_prompt_and_blank
@post = Post.new
@post.category = ""
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index 0ff37f44c2..036a44730c 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -104,6 +104,12 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
assert_equal javascript_tag(create_generator(&block).to_s, {:defer => 'true'}), update_page_tag({:defer => 'true'}, &block)
end
+ def test_remote_function
+ res = remote_function(:url => authors_path, :with => "'author[name]='+$F('author_name')+'&author[dob]='+$F('author_dob')")
+ assert_equal "new Ajax.Request('/authors', {asynchronous:true, evalScripts:true, parameters:'author[name]='+$F('author_name')+'&author[dob]='+$F('author_dob')})", res
+ assert res.html_safe?
+ end
+
protected
def author_path(record)
"/authors/#{record.id}"
diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG
index a5e7f300d9..33602657f5 100644
--- a/activemodel/CHANGELOG
+++ b/activemodel/CHANGELOG
@@ -1,3 +1,8 @@
+*Rails 3.0.0 [Release Candidate] (unreleased)*
+
+* Added ActiveModel::MassAssignmentSecurity [Eric Chapweske, Josh Kalderimis]
+
+
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
* JSON supports a custom root option: to_json(:root => 'custom') #4515 [Jatinder Singh]
diff --git a/activemodel/README b/activemodel/README.rdoc
index 6f162ef408..6f162ef408 100644
--- a/activemodel/README
+++ b/activemodel/README.rdoc
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index 1dba664539..4e4bbcee96 100644
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -32,7 +32,7 @@ Rake::RDocTask.new do |rdoc|
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include("README", "CHANGELOG")
+ rdoc.rdoc_files.include("README.rdoc", "CHANGELOG")
rdoc.rdoc_files.include("lib/**/*.rb")
end
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index 6bd6fe49ff..c483ecbc3c 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'activemodel'
- s.files = Dir['CHANGELOG', 'MIT-LICENSE', 'README', 'lib/**/*']
+ s.files = Dir['CHANGELOG', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*']
s.require_path = 'lib'
s.has_rdoc = true
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index ca1e9f0ee8..dc83932dde 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -57,6 +57,35 @@ module ActiveModel
def model_name
@_model_name ||= ActiveModel::Name.new(self)
end
+
+ # Returns the plural class name of a record or class. Examples:
+ #
+ # ActiveModel::Naming.plural(post) # => "posts"
+ # ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
+ def self.plural(record_or_class)
+ model_name_from_record_or_class(record_or_class).plural
+ end
+
+ # Returns the singular class name of a record or class. Examples:
+ #
+ # ActiveModel::Naming.singular(post) # => "post"
+ # ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
+ def self.singular(record_or_class)
+ model_name_from_record_or_class(record_or_class).singular
+ end
+
+ # Identifies whether the class name of a record or class is uncountable. Examples:
+ #
+ # ActiveModel::Naming.uncountable?(Sheep) # => true
+ # ActiveModel::Naming.uncountable?(Post) => false
+ def self.uncountable?(record_or_class)
+ plural(record_or_class) == singular(record_or_class)
+ end
+
+ private
+ def self.model_name_from_record_or_class(record_or_class)
+ (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
+ end
end
end
diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb
index dc39b84ed8..5a8bff378a 100644
--- a/activemodel/test/cases/naming_test.rb
+++ b/activemodel/test/cases/naming_test.rb
@@ -1,4 +1,6 @@
require 'cases/helper'
+require 'models/contact'
+require 'models/sheep'
require 'models/track_back'
class NamingTest < ActiveModel::TestCase
@@ -26,3 +28,40 @@ class NamingTest < ActiveModel::TestCase
assert_equal 'post/track_backs/track_back', @model_name.partial_path
end
end
+
+class NamingHelpersTest < Test::Unit::TestCase
+ def setup
+ @klass = Contact
+ @record = @klass.new
+ @singular = 'contact'
+ @plural = 'contacts'
+ @uncountable = Sheep
+ end
+
+ def test_singular
+ assert_equal @singular, singular(@record)
+ end
+
+ def test_singular_for_class
+ assert_equal @singular, singular(@klass)
+ end
+
+ def test_plural
+ assert_equal @plural, plural(@record)
+ end
+
+ def test_plural_for_class
+ assert_equal @plural, plural(@klass)
+ end
+
+ def test_uncountable
+ assert uncountable?(@uncountable), "Expected 'sheep' to be uncoutable"
+ assert !uncountable?(@klass), "Expected 'contact' to be countable"
+ end
+
+ private
+ def method_missing(method, *args)
+ ActiveModel::Naming.send(method, *args)
+ end
+end
+
diff --git a/activemodel/test/models/contact.rb b/activemodel/test/models/contact.rb
index 605e435f39..f4f3078473 100644
--- a/activemodel/test/models/contact.rb
+++ b/activemodel/test/models/contact.rb
@@ -1,4 +1,5 @@
class Contact
+ extend ActiveModel::Naming
include ActiveModel::Conversion
attr_accessor :id, :name, :age, :created_at, :awesome, :preferences
diff --git a/activemodel/test/models/sheep.rb b/activemodel/test/models/sheep.rb
new file mode 100644
index 0000000000..175dbe6477
--- /dev/null
+++ b/activemodel/test/models/sheep.rb
@@ -0,0 +1,4 @@
+class Sheep
+ extend ActiveModel::Naming
+end
+ \ No newline at end of file
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a1a82fdff5..679fdafae8 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [RC1] (unreleased)*
+* Changed update_attribute to not run callbacks and update the record directly in the database [Neeraj Singh]
+
* Add scoping and unscoped as the syntax to replace the old with_scope and with_exclusive_scope [José Valim]
* New rake task, db:migrate:status, displays status of migrations #4947 [Kevin Skoglund]
diff --git a/activerecord/README b/activerecord/README.rdoc
index d68eb28a64..0446180207 100644
--- a/activerecord/README
+++ b/activerecord/README.rdoc
@@ -309,28 +309,13 @@ Admit the Database:
== Download
-The latest version of Active Record can be found at
+The latest version of Active Record can be installed with Rubygems:
-* http://rubyforge.org/project/showfiles.php?group_id=182
+* gem install activerecord
Documentation can be found at
-* http://ar.rubyonrails.com
-
-
-== Installation
-
-The prefered method of installing Active Record is through its GEM file. You'll need to have
-RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have,
-then use:
-
- % [sudo] gem install activerecord-1.10.0.gem
-
-You can also install Active Record the old-fashioned way with the following command:
-
- % [sudo] ruby install.rb
-
-from its distribution directory.
+* http://api.rubyonrails.org
== License
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 392b717e0a..d9124c9776 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -172,7 +172,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
+ rdoc.rdoc_files.include('README.rdoc', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/active_record/vendor/*')
rdoc.rdoc_files.include('dev-utils/*.rb')
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index ce10404feb..67d521d56b 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -14,12 +14,12 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'activerecord'
- s.files = Dir['CHANGELOG', 'README', 'examples/**/*', 'lib/**/*']
+ s.files = Dir['CHANGELOG', 'README.rdoc', 'examples/**/*', 'lib/**/*']
s.require_path = 'lib'
s.has_rdoc = true
- s.extra_rdoc_files = %w( README )
- s.rdoc_options.concat ['--main', 'README']
+ s.extra_rdoc_files = %w( README.rdoc )
+ s.rdoc_options.concat ['--main', 'README.rdoc']
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
diff --git a/activerecord/install.rb b/activerecord/install.rb
deleted file mode 100644
index c87398b1f4..0000000000
--- a/activerecord/install.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'rbconfig'
-require 'find'
-require 'ftools'
-
-include Config
-
-# this was adapted from rdoc's install.rb by ways of Log4r
-
-$sitedir = CONFIG["sitelibdir"]
-unless $sitedir
- version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
- $libdir = File.join(CONFIG["libdir"], "ruby", version)
- $sitedir = $:.find {|x| x =~ /site_ruby/ }
- if !$sitedir
- $sitedir = File.join($libdir, "site_ruby")
- elsif $sitedir !~ Regexp.quote(version)
- $sitedir = File.join($sitedir, version)
- end
-end
-
-# the actual gruntwork
-Dir.chdir("lib")
-
-Find.find("active_record", "active_record.rb") { |f|
- if f[-3..-1] == ".rb"
- File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
- else
- File::makedirs(File.join($sitedir, *f.split(/\//)))
- end
-}
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index cbec5789fd..08601f8ef9 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -112,13 +112,13 @@ module ActiveRecord
# Not all records have the same class, so group then preload
# group on the reflection itself so that if various subclass share the same association then we do not split them
# unnecessarily
- records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records|
+ records.group_by { |record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, _records|
raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection
# 'reflection.macro' can return 'belongs_to', 'has_many', etc. Thus,
# the following could call 'preload_belongs_to_association',
# 'preload_has_many_association', etc.
- send("preload_#{reflection.macro}_association", records, reflection, preload_options)
+ send("preload_#{reflection.macro}_association", _records, reflection, preload_options)
end
end
@@ -378,7 +378,7 @@ module ActiveRecord
:order => preload_options[:order] || options[:order]
}
- reflection.klass.unscoped.apply_finder_options(find_options).to_a
+ reflection.klass.scoped.apply_finder_options(find_options).to_a
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index d67df64f59..1b9b725dd4 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/enumerable'
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'
module ActiveRecord
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
@@ -1354,7 +1355,7 @@ module ActiveRecord
end
def association_accessor_methods(reflection, association_proxy_class)
- define_method(reflection.name) do |*params|
+ redefine_method(reflection.name) do |*params|
force_reload = params.first unless params.empty?
association = association_instance_get(reflection.name)
@@ -1371,12 +1372,12 @@ module ActiveRecord
association.target.nil? ? nil : association
end
- define_method("loaded_#{reflection.name}?") do
+ redefine_method("loaded_#{reflection.name}?") do
association = association_instance_get(reflection.name)
association && association.loaded?
end
-
- define_method("#{reflection.name}=") do |new_value|
+
+ redefine_method("#{reflection.name}=") do |new_value|
association = association_instance_get(reflection.name)
if association.nil? || association.target != new_value
@@ -1386,8 +1387,8 @@ module ActiveRecord
association.replace(new_value)
association_instance_set(reflection.name, new_value.nil? ? nil : association)
end
-
- define_method("set_#{reflection.name}_target") do |target|
+
+ redefine_method("set_#{reflection.name}_target") do |target|
return if target.nil? and association_proxy_class == BelongsToAssociation
association = association_proxy_class.new(self, reflection)
association.target = target
@@ -1396,7 +1397,7 @@ module ActiveRecord
end
def collection_reader_method(reflection, association_proxy_class)
- define_method(reflection.name) do |*params|
+ redefine_method(reflection.name) do |*params|
force_reload = params.first unless params.empty?
association = association_instance_get(reflection.name)
@@ -1409,8 +1410,8 @@ module ActiveRecord
association
end
-
- define_method("#{reflection.name.to_s.singularize}_ids") do
+
+ redefine_method("#{reflection.name.to_s.singularize}_ids") do
if send(reflection.name).loaded? || reflection.options[:finder_sql]
send(reflection.name).map(&:id)
else
@@ -1430,14 +1431,14 @@ module ActiveRecord
collection_reader_method(reflection, association_proxy_class)
if writer
- define_method("#{reflection.name}=") do |new_value|
+ redefine_method("#{reflection.name}=") do |new_value|
# Loads proxy class instance (defined in collection_reader_method) if not already loaded
association = send(reflection.name)
association.replace(new_value)
association
end
-
- define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
+
+ redefine_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
ids = (new_value || []).reject { |nid| nid.blank? }.map(&:to_i)
send("#{reflection.name}=", reflection.klass.find(ids).index_by(&:id).values_at(*ids))
end
@@ -1445,7 +1446,7 @@ module ActiveRecord
end
def association_constructor_method(constructor, reflection, association_proxy_class)
- define_method("#{constructor}_#{reflection.name}") do |*params|
+ redefine_method("#{constructor}_#{reflection.name}") do |*params|
attributees = params.first unless params.empty?
replace_existing = params[1].nil? ? true : params[1]
association = association_instance_get(reflection.name)
@@ -1486,8 +1487,8 @@ module ActiveRecord
end
def add_touch_callbacks(reflection, touch_attribute)
- method_name = "belongs_to_touch_after_save_or_destroy_for_#{reflection.name}".to_sym
- define_method(method_name) do
+ method_name = :"belongs_to_touch_after_save_or_destroy_for_#{reflection.name}"
+ redefine_method(method_name) do
association = send(reflection.name)
if touch_attribute == true
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index f4e34657a5..f346a19a3a 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -218,9 +218,9 @@ module ActiveRecord
# are actually removed from the database, that depends precisely on
# +delete_records+. They are in any case removed from the collection.
def delete(*records)
- remove_records(records) do |records, old_records|
+ remove_records(records) do |_records, old_records|
delete_records(old_records) if old_records.any?
- records.each { |record| @target.delete(record) }
+ _records.each { |record| @target.delete(record) }
end
end
@@ -231,7 +231,7 @@ module ActiveRecord
# ignoring the +:dependent+ option.
def destroy(*records)
records = find(records) if records.any? {|record| record.kind_of?(Fixnum) || record.kind_of?(String)}
- remove_records(records) do |records, old_records|
+ remove_records(records) do |_records, old_records|
old_records.each { |record| record.destroy }
end
@@ -396,11 +396,12 @@ module ActiveRecord
if @target.is_a?(Array) && @target.any?
@target = find_target.map do |f|
i = @target.index(f)
- t = @target.delete_at(i) if i
- if t && t.changed?
- t
+ if i
+ @target.delete_at(i).tap do |t|
+ keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
+ t.attributes = f.attributes.except(*keys)
+ end
else
- f.mark_for_destruction if t && t.marked_for_destruction?
f
end
end + @target
@@ -477,7 +478,14 @@ module ActiveRecord
callback(:before_add, record)
yield(record) if block_given?
@target ||= [] unless loaded?
- @target << record unless @reflection.options[:uniq] && @target.include?(record)
+ index = @target.index(record)
+ unless @reflection.options[:uniq] && index
+ if index
+ @target[index] = record
+ else
+ @target << record
+ end
+ end
callback(:after_add, record)
set_inverse_instance(record, @owner)
record
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 c989c3536d..e61af93d1e 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
@@ -45,17 +45,23 @@ module ActiveRecord
if @reflection.options[:insert_sql]
@owner.connection.insert(interpolate_sql(@reflection.options[:insert_sql], record))
else
- relation = Arel::Table.new(@reflection.options[:join_table])
+ relation = Arel::Table.new(@reflection.options[:join_table])
+ timestamps = record_timestamp_columns(record)
+ timezone = record.send(:current_time_from_proper_timezone) if timestamps.any?
+
attributes = columns.inject({}) do |attrs, column|
- case column.name.to_s
+ name = column.name
+ case name.to_s
when @reflection.primary_key_name.to_s
- attrs[relation[column.name]] = owner_quoted_id
+ attrs[relation[name]] = @owner.id
when @reflection.association_foreign_key.to_s
- attrs[relation[column.name]] = record.quoted_id
+ attrs[relation[name]] = record.id
+ when *timestamps
+ attrs[relation[name]] = timezone
else
- if record.has_attribute?(column.name)
- value = @owner.send(:quote_value, record[column.name], column)
- attrs[relation[column.name]] = value unless value.nil?
+ if record.has_attribute?(name)
+ value = @owner.send(:quote_value, record[name], column)
+ attrs[relation[name]] = value unless value.nil?
end
end
attrs
@@ -117,6 +123,14 @@ module ActiveRecord
build_record(attributes, &block)
end
end
+
+ def record_timestamp_columns(record)
+ if record.record_timestamps
+ record.send(:all_timestamp_attributes).map(&:to_s)
+ else
+ []
+ end
+ 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 be8d1bd76b..6072481411 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -199,11 +199,14 @@ module ActiveRecord
def log(sql, name)
name ||= "SQL"
- result = nil
- ActiveSupport::Notifications.instrument("sql.active_record",
- :sql => sql, :name => name, :connection_id => self.object_id) do
- @runtime += Benchmark.ms { result = yield }
+ instrumenter = ActiveSupport::Notifications.instrumenter
+
+ result = instrumenter.instrument("sql.active_record",
+ :sql => sql, :name => name, :connection_id => object_id) do
+ yield
end
+ @runtime += instrumenter.elapsed
+
result
rescue Exception => e
message = "#{e.class.name}: #{e.message}: #{sql}"
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 5bf43b3a72..657303fd14 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -871,7 +871,7 @@ module ActiveRecord
table_names.each do |table_name|
table_name = table_name.to_s.tr('./', '_')
- define_method(table_name) do |*fixtures|
+ redefine_method(table_name) do |*fixtures|
force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
@fixture_cache[table_name] ||= {}
diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb
index 71065f9908..278e192e59 100644
--- a/activerecord/lib/active_record/log_subscriber.rb
+++ b/activerecord/lib/active_record/log_subscriber.rb
@@ -6,14 +6,16 @@ module ActiveRecord
end
def sql(event)
+ return unless logger.debug?
+
name = '%s (%.1fms)' % [event.payload[:name], event.duration]
sql = event.payload[:sql].squeeze(' ')
if odd?
- name = color(name, :cyan, true)
+ name = color(name, CYAN, true)
sql = color(sql, nil, true)
else
- name = color(name, :magenta, true)
+ name = color(name, MAGENTA, true)
end
debug " #{name} #{sql}"
@@ -29,4 +31,4 @@ module ActiveRecord
end
end
-ActiveRecord::LogSubscriber.attach_to :active_record \ No newline at end of file
+ActiveRecord::LogSubscriber.attach_to :active_record
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index 849ec9c884..417ff4b5eb 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -26,7 +26,7 @@ module ActiveRecord
# You can define a \scope that applies to all finders using
# ActiveRecord::Base.default_scope.
def scoped(options = nil)
- if options.present?
+ if options
scoped.apply_finder_options(options)
else
current_scoped_methods ? relation.merge(current_scoped_methods) : relation.clone
@@ -105,7 +105,7 @@ module ActiveRecord
extension ? relation.extending(extension) : relation
end
- singleton_class.send :define_method, name, &scopes[name]
+ singleton_class.send(:redefine_method, name, &scopes[name])
end
def named_scope(*args, &block)
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 68f5be63d6..b587abd5d0 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -112,6 +112,8 @@ module ActiveRecord
# * does not work on attr_accessor attributes. The attribute that is being updated must be column name.
#
def update_attribute(name, value)
+ raise ActiveRecordError, "#{name.to_s} is marked as readonly" if self.class.readonly_attributes.include? name.to_s
+
changes = record_update_timestamps || {}
if name
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index eff51a7c87..78fdb77216 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -22,6 +22,12 @@ module ActiveRecord
load "active_record/railties/databases.rake"
end
+ # When loading console, force ActiveRecord to be loaded to avoid cross
+ # references when loading a constant for the first time.
+ console do
+ ActiveRecord::Base
+ end
+
initializer "active_record.initialize_timezone" do
ActiveSupport.on_load(:active_record) do
self.time_zone_aware_attributes = true
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 5024787c3c..2c17c74ab4 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -274,7 +274,7 @@ namespace :db do
task :setup => [ 'db:create', 'db:schema:load', 'db:seed' ]
desc 'Load the seed data from db/seeds.rb'
- task :seed => :environment do
+ task :seed => 'db:abort_if_pending_migrations' do
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
load(seed_file) if File.exist?(seed_file)
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 7499100f55..86a210d2be 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -13,14 +13,15 @@ module ActiveRecord
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a
delegate :insert, :to => :arel
- attr_reader :table, :klass
+ attr_reader :table, :klass, :loaded
attr_accessor :extensions
+ alias :loaded? :loaded
def initialize(klass, table)
@klass, @table = klass, table
@implicit_readonly = nil
- @loaded = nil
+ @loaded = false
SINGLE_VALUE_METHODS.each {|v| instance_variable_set(:"@#{v}_value", nil)}
(ASSOCIATION_METHODS + MULTI_VALUE_METHODS).each {|v| instance_variable_set(:"@#{v}_values", [])}
@@ -292,10 +293,6 @@ module ActiveRecord
where(@klass.primary_key => id_or_array).delete_all
end
- def loaded?
- @loaded
- end
-
def reload
reset
to_a # force reload
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index df2f429c5d..7ea7fb5c51 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -294,7 +294,6 @@ module ActiveRecord
private
def get_session(env, sid)
Base.silence do
- sid ||= generate_sid
session = find_session(sid)
env[SESSION_RECORD_KEY] = session
[sid, session.data]
diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index 341cc87be5..6c1e376745 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -39,8 +39,9 @@ module ActiveRecord
if record_timestamps
current_time = current_time_from_proper_timezone
- write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
- write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
+ timestamp_attributes_for_create.each do |column|
+ write_attribute(column.to_s, current_time) if respond_to?(column) && self.send(column).nil?
+ end
timestamp_attributes_for_update_in_model.each do |column|
write_attribute(column.to_s, current_time) if self.send(column).nil?
@@ -65,7 +66,19 @@ module ActiveRecord
end
def timestamp_attributes_for_update_in_model #:nodoc:
- [:updated_at, :updated_on].select { |elem| respond_to?(elem) }
+ timestamp_attributes_for_update.select { |elem| respond_to?(elem) }
+ end
+
+ def timestamp_attributes_for_update #:nodoc:
+ [:updated_at, :updated_on]
+ end
+
+ def timestamp_attributes_for_create #:nodoc:
+ [:created_at, :created_on]
+ end
+
+ def all_timestamp_attributes #:nodoc:
+ timestamp_attributes_for_update + timestamp_attributes_for_create
end
def current_time_from_proper_timezone #:nodoc:
diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb
index 6e6645511c..ed4efdc1c0 100644
--- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb
@@ -101,6 +101,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase
#we need to actually modify some data, so we make execute point to the original method
ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do
alias_method :execute_with_stub, :execute
+ remove_method :execute
alias_method :execute, :execute_without_stub
end
yield
diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb
index 74588b4f47..9e285e57dc 100644
--- a/activerecord/test/cases/aggregations_test.rb
+++ b/activerecord/test/cases/aggregations_test.rb
@@ -125,7 +125,7 @@ class OverridingAggregationsTest < ActiveRecord::TestCase
class Name; end
class DifferentName; end
- class Person < ActiveRecord::Base
+ class Person < ActiveRecord::Base
composed_of :composed_of, :mapping => %w(person_first_name first_name)
end
diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb
index 665c387d5d..588adc38e3 100644
--- a/activerecord/test/cases/ar_schema_test.rb
+++ b/activerecord/test/cases/ar_schema_test.rb
@@ -28,7 +28,7 @@ if ActiveRecord::Base.connection.supports_migrations?
assert_equal 7, ActiveRecord::Migrator::current_version
end
- def test_schema_raises_an_error_for_invalid_column_ntype
+ def test_schema_raises_an_error_for_invalid_column_type
assert_raise NoMethodError do
ActiveRecord::Schema.define(:version => 8) do
create_table :vegetables do |t|
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index fb1e6e7e70..4d5769d173 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -5,8 +5,6 @@ require 'models/company'
require 'models/topic'
require 'models/reply'
require 'models/computer'
-require 'models/customer'
-require 'models/order'
require 'models/post'
require 'models/author'
require 'models/tag'
diff --git a/activerecord/test/cases/associations/callbacks_test.rb b/activerecord/test/cases/associations/callbacks_test.rb
index 91b1af125e..15537d6940 100644
--- a/activerecord/test/cases/associations/callbacks_test.rb
+++ b/activerecord/test/cases/associations/callbacks_test.rb
@@ -1,8 +1,6 @@
require "cases/helper"
require 'models/post'
-require 'models/comment'
require 'models/author'
-require 'models/category'
require 'models/project'
require 'models/developer'
diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
index f5d59c9a43..b93e49613d 100644
--- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
+++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
@@ -2,7 +2,6 @@ require "cases/helper"
require 'models/post'
require 'models/comment'
require 'models/author'
-require 'models/category'
require 'models/categorization'
require 'models/company'
require 'models/topic'
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index b11969a841..6b4a1d9408 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -2,20 +2,14 @@ require "cases/helper"
require 'models/developer'
require 'models/project'
require 'models/company'
-require 'models/topic'
-require 'models/reply'
-require 'models/computer'
require 'models/customer'
require 'models/order'
require 'models/categorization'
require 'models/category'
require 'models/post'
require 'models/author'
-require 'models/comment'
require 'models/tag'
require 'models/tagging'
-require 'models/person'
-require 'models/reader'
require 'models/parrot'
require 'models/pirate'
require 'models/treasure'
@@ -24,6 +18,8 @@ require 'models/club'
require 'models/member'
require 'models/membership'
require 'models/sponsor'
+require 'models/country'
+require 'models/treaty'
require 'active_support/core_ext/string/conversions'
class ProjectWithAfterCreateHook < ActiveRecord::Base
@@ -83,6 +79,55 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
:parrots, :pirates, :treasures, :price_estimates, :tags, :taggings
+ def setup_data_for_habtm_case
+ ActiveRecord::Base.connection.execute('delete from countries_treaties')
+
+ country = Country.new(:name => 'India')
+ country.country_id = 'c1'
+ country.save!
+
+ treaty = Treaty.new(:name => 'peace')
+ treaty.treaty_id = 't1'
+ country.treaties << treaty
+ end
+
+ def test_should_property_quote_string_primary_keys
+ setup_data_for_habtm_case
+
+ con = ActiveRecord::Base.connection
+ sql = 'select * from countries_treaties'
+ record = con.select_rows(sql).last
+ assert_equal 'c1', record[0]
+ assert_equal 't1', record[1]
+ end
+
+ def test_should_record_timestamp_for_join_table
+ setup_data_for_habtm_case
+
+ con = ActiveRecord::Base.connection
+ sql = 'select * from countries_treaties'
+ record = con.select_rows(sql).last
+ assert_not_nil record[2]
+ assert_not_nil record[3]
+ assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[2]
+ assert_match %r{\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}}, record[3]
+ end
+
+ def test_should_record_timestamp_for_join_table_only_if_timestamp_should_be_recorded
+ begin
+ Treaty.record_timestamps = false
+ setup_data_for_habtm_case
+
+ con = ActiveRecord::Base.connection
+ sql = 'select * from countries_treaties'
+ record = con.select_rows(sql).last
+ assert_nil record[2]
+ assert_nil record[3]
+ ensure
+ Treaty.record_timestamps = true
+ end
+ end
+
def test_has_and_belongs_to_many
david = Developer.find(1)
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 34d24a2948..fa5c2e49df 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -412,7 +412,7 @@ class InverseBelongsToTests < ActiveRecord::TestCase
i = interests(:trainspotting)
m = i.man
assert_not_nil m.interests
- iz = m.interests.detect {|iz| iz.id == i.id}
+ iz = m.interests.detect { |_iz| _iz.id == i.id}
assert_not_nil iz
assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child"
i.topic = 'Eating cheese with a spoon'
@@ -516,7 +516,7 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
i = interests(:llama_wrangling)
m = i.polymorphic_man
assert_not_nil m.polymorphic_interests
- iz = m.polymorphic_interests.detect {|iz| iz.id == i.id}
+ iz = m.polymorphic_interests.detect { |_iz| _iz.id == i.id}
assert_not_nil iz
assert_equal i.topic, iz.topic, "Interest topics should be the same before changes to child"
i.topic = 'Eating cheese with a spoon'
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 4ae776c35a..a1c794c084 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -2,11 +2,6 @@ require "cases/helper"
require 'models/developer'
require 'models/project'
require 'models/company'
-require 'models/topic'
-require 'models/reply'
-require 'models/computer'
-require 'models/customer'
-require 'models/order'
require 'models/categorization'
require 'models/category'
require 'models/post'
@@ -17,18 +12,31 @@ require 'models/tagging'
require 'models/person'
require 'models/reader'
require 'models/parrot'
-require 'models/pirate'
-require 'models/treasure'
-require 'models/price_estimate'
-require 'models/club'
-require 'models/member'
-require 'models/membership'
-require 'models/sponsor'
+require 'models/ship_part'
+require 'models/ship'
class AssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :developers, :projects, :developers_projects,
:computers, :people, :readers
+ def test_loading_the_association_target_should_keep_child_records_marked_for_destruction
+ ship = Ship.create!(:name => "The good ship Dollypop")
+ part = ship.parts.create!(:name => "Mast")
+ part.mark_for_destruction
+ ship.parts.send(:load_target)
+ assert ship.parts[0].marked_for_destruction?
+ end
+
+ def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction
+ ship = Ship.create!(:name => "The good ship Dollypop")
+ part = ship.parts.create!(:name => "Mast")
+ part.mark_for_destruction
+ ShipPart.find(part.id).update_attribute(:name, 'Deck')
+ ship.parts.send(:load_target)
+ assert_equal 'Deck', ship.parts[0].name
+ end
+
+
def test_include_with_order_works
assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 831dd446ad..df6895f0d0 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -123,6 +123,14 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"]
else
assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"].to_s(:db)
+
+ developer.created_at = "345643456"
+ assert_equal developer.created_at_before_type_cast, "345643456"
+ assert_equal developer.created_at, nil
+
+ developer.created_at = "2010-03-21T21:23:32+01:00"
+ assert_equal developer.created_at_before_type_cast, "2010-03-21T21:23:32+01:00"
+ assert_equal developer.created_at, Time.parse("2010-03-21T21:23:32+01:00")
end
end
@@ -1816,8 +1824,8 @@ class BasicsTest < ActiveRecord::TestCase
def test_to_xml_with_block
value = "Rockin' the block"
- xml = Company.new.to_xml(:skip_instruct => true) do |xml|
- xml.tag! "arbitrary-element", value
+ xml = Company.new.to_xml(:skip_instruct => true) do |_xml|
+ _xml.tag! "arbitrary-element", value
end
assert_equal "<company>", xml.first(9)
assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 860d330a7f..a107c1a474 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -10,7 +10,6 @@ require 'models/entrant'
require 'models/project'
require 'models/developer'
require 'models/customer'
-require 'models/job'
class DynamicFinderMatchTest < ActiveRecord::TestCase
def test_find_no_match
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 8008b86f81..93f8749255 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -36,7 +36,7 @@ class FixturesTest < ActiveRecord::TestCase
fixtures = nil
assert_nothing_raised { fixtures = create_fixtures(name) }
assert_kind_of(Fixtures, fixtures)
- fixtures.each { |name, fixture|
+ fixtures.each { |_name, fixture|
fixture.each { |key, value|
assert_match(MATCH_ATTRIBUTE_NAME, key)
}
@@ -229,9 +229,9 @@ if Account.connection.respond_to?(:reset_pk_sequence!)
def test_create_fixtures_resets_sequences_when_not_cached
@instances.each do |instance|
- max_id = create_fixtures(instance.class.table_name).inject(0) do |max_id, (name, fixture)|
+ max_id = create_fixtures(instance.class.table_name).inject(0) do |_max_id, (name, fixture)|
fixture_id = fixture['id'].to_i
- fixture_id > max_id ? fixture_id : max_id
+ fixture_id > _max_id ? fixture_id : _max_id
end
# Clone the last fixture to check that it gets the next greatest id.
diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb
index cde383783b..342daa19df 100644
--- a/activerecord/test/cases/log_subscriber_test.rb
+++ b/activerecord/test/cases/log_subscriber_test.rb
@@ -4,6 +4,7 @@ require "active_support/log_subscriber/test_helper"
class LogSubscriberTest < ActiveRecord::TestCase
include ActiveSupport::LogSubscriber::TestHelper
+ include ActiveSupport::BufferedLogger::Severity
def setup
@old_logger = ActiveRecord::Base.logger
@@ -39,4 +40,21 @@ class LogSubscriberTest < ActiveRecord::TestCase
assert_match(/CACHE/, @logger.logged(:debug).last)
assert_match(/SELECT .*?FROM .?developers.?/i, @logger.logged(:debug).last)
end
+
+ def test_basic_query_doesnt_log_when_level_is_not_debug
+ @logger.level = INFO
+ Developer.all
+ wait
+ assert_equal 0, @logger.logged(:debug).size
+ end
+
+ def test_cached_queries_doesnt_log_when_level_is_not_debug
+ @logger.level = INFO
+ ActiveRecord::Base.cache do
+ Developer.all
+ Developer.all
+ end
+ wait
+ assert_equal 0, @logger.logged(:debug).size
+ end
end
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index 4e8ce1dac1..774b50e2e4 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -8,7 +8,6 @@ require 'models/author'
require 'models/developer'
require 'models/project'
require 'models/comment'
-require 'models/category'
class MethodScopingTest < ActiveRecord::TestCase
fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
@@ -543,4 +542,4 @@ class NestedScopingTest < ActiveRecord::TestCase
assert_equal 1, scoped_authors.size
assert_equal authors(:david).attributes, scoped_authors.first.attributes
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index dc85b395d3..7c037b20c5 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -270,27 +270,27 @@ class NamedScopeTest < ActiveRecord::TestCase
assert Topic.base.many?
end
- def test_should_build_with_proxy_options
+ def test_should_build_on_top_of_named_scope
topic = Topic.approved.build({})
assert topic.approved
end
- def test_should_build_new_with_proxy_options
+ def test_should_build_new_on_top_of_named_scope
topic = Topic.approved.new
assert topic.approved
end
- def test_should_create_with_proxy_options
+ def test_should_create_on_top_of_named_scope
topic = Topic.approved.create({})
assert topic.approved
end
- def test_should_create_with_bang_with_proxy_options
+ def test_should_create_with_bang_on_top_of_named_scope
topic = Topic.approved.create!({})
assert topic.approved
end
- def test_should_build_with_proxy_options_chained
+ def test_should_build_on_top_of_chained_named_scopes
topic = Topic.approved.by_lifo.build({})
assert topic.approved
assert_equal 'lifo', topic.author_name
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index c9ea0d8c40..df09bbd46a 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -59,6 +59,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
pirate.save!
assert_equal 1, pirate.birds_with_reject_all_blank.count
+ assert_equal 'Tweetie', pirate.birds_with_reject_all_blank.first.name
end
def test_should_raise_an_ArgumentError_for_non_existing_associations
@@ -74,7 +75,7 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
ship = pirate.create_ship(:name => 'Nights Dirty Lightning')
assert_no_difference('Ship.count') do
- pirate.update_attributes(:ship_attributes => { '_destroy' => true })
+ pirate.update_attributes(:ship_attributes => { '_destroy' => true, :id => ship.id })
end
end
@@ -100,7 +101,8 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
assert_no_difference('Ship.count') { pirate.save! }
- # pirate.reject_empty_ships_on_create returns false for saved records
+ # pirate.reject_empty_ships_on_create returns false for saved pirate records
+ # in the previous step note that pirate gets saved but ship fails
pirate.ship_attributes = { :name => 'Red Pearl', :_reject_me_if_new => true }
assert_difference('Ship.count') { pirate.save! }
end
@@ -266,6 +268,28 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
end
assert_equal 'Mayflower', @ship.reload.name
end
+
+ def test_should_update_existing_when_update_only_is_true_and_id_is_given
+ @ship.delete
+ @ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
+
+ assert_no_difference('Ship.count') do
+ @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id })
+ end
+ assert_equal 'Mayflower', @ship.reload.name
+ end
+
+ def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction
+ Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => true
+ @ship.delete
+ @ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
+
+ assert_difference('Ship.count', -1) do
+ @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id, :_destroy => true })
+ end
+ Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => false
+ end
+
end
class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
@@ -411,6 +435,27 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
end
assert_equal 'Arr', @pirate.reload.catchphrase
end
+
+ def test_should_update_existing_when_update_only_is_true_and_id_is_given
+ @pirate.delete
+ @pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
+
+ assert_no_difference('Pirate.count') do
+ @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id })
+ end
+ assert_equal 'Arr', @pirate.reload.catchphrase
+ end
+
+ def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction
+ Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => true
+ @pirate.delete
+ @pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
+
+ assert_difference('Pirate.count', -1) do
+ @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id, :_destroy => true })
+ end
+ Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => false
+ end
end
module NestedAttributesOnACollectionAssociationTests
@@ -811,7 +856,25 @@ class TestHasManyAutosaveAssociationWhichItselfHasAutosaveAssociations < ActiveR
@part = @ship.parts.create!(:name => "Mast")
@trinket = @part.trinkets.create!(:name => "Necklace")
end
-
+
+ test "if association is not loaded and association record is saved and then in memory record attributes should be saved" do
+ @ship.parts_attributes=[{:id => @part.id,:name =>'Deck'}]
+ assert_equal 1, @ship.parts.proxy_target.size
+ assert_equal 'Deck', @ship.parts[0].name
+ end
+
+ test "if association is not loaded and child doesn't change and I am saving a grandchild then in memory record should be used" do
+ @ship.parts_attributes=[{:id => @part.id,:trinkets_attributes =>[{:id => @trinket.id, :name => 'Ruby'}]}]
+ assert_equal 1, @ship.parts.proxy_target.size
+ assert_equal 'Mast', @ship.parts[0].name
+ assert_no_difference("@ship.parts[0].trinkets.proxy_target.size") do
+ @ship.parts[0].trinkets.proxy_target.size
+ end
+ assert_equal 'Ruby', @ship.parts[0].trinkets[0].name
+ @ship.save
+ assert_equal 'Ruby', @ship.parts[0].trinkets[0].name
+ end
+
test "when grandchild changed in memory, saving parent should save grandchild" do
@trinket.name = "changed"
@ship.save
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 4ea5df0945..1cc3a337c3 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -5,25 +5,19 @@ require 'models/topic'
require 'models/reply'
require 'models/category'
require 'models/company'
-require 'models/customer'
require 'models/developer'
require 'models/project'
-require 'models/default'
-require 'models/auto_id'
-require 'models/column_name'
-require 'models/subscriber'
-require 'models/keyboard'
-require 'models/comment'
require 'models/minimalistic'
require 'models/warehouse_thing'
require 'models/parrot'
+require 'models/minivan'
require 'models/loose_person'
require 'rexml/document'
require 'active_support/core_ext/exception'
class PersistencesTest < ActiveRecord::TestCase
- fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
+ fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts, :minivans
def test_create
topic = Topic.new
@@ -220,6 +214,11 @@ class PersistencesTest < ActiveRecord::TestCase
assert !Topic.find(1).approved?
end
+ def test_update_attribute_for_readonly_attribute
+ minivan = Minivan.find('m1')
+ assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
+ end
+
def test_update_attribute_with_one_changed_and_one_updated
t = Topic.order('id').limit(1).first
title, author_name = t.title, t.author_name
diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 73f4b3848c..1e44237e0a 100644
--- a/activerecord/test/cases/pk_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -13,7 +13,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase
topic = Topic.new
assert topic.to_key.nil?
topic = Topic.find(1)
- assert_equal topic.to_key, [1]
+ assert_equal [1], topic.to_key
end
def test_to_key_with_customized_primary_key
@@ -26,7 +26,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase
def test_to_key_with_primary_key_after_destroy
topic = Topic.find(1)
topic.destroy
- assert_equal topic.to_key, [1]
+ assert_equal [1], topic.to_key
end
def test_integer_key
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 68abca70b3..f0d97a00d0 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -1,8 +1,6 @@
require "cases/helper"
require 'models/topic'
-require 'models/reply'
require 'models/task'
-require 'models/course'
require 'models/category'
require 'models/post'
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index a5a3b3ef38..a50a4d4165 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -5,6 +5,8 @@ require 'models/developer'
require 'models/project'
require 'models/comment'
require 'models/category'
+require 'models/person'
+require 'models/reference'
class RelationScopingTest < ActiveRecord::TestCase
fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects
@@ -218,7 +220,7 @@ class NestedRelationScopingTest < ActiveRecord::TestCase
end
class HasManyScopingTest< ActiveRecord::TestCase
- fixtures :comments, :posts
+ fixtures :comments, :posts, :people, :references
def setup
@welcome = Post.find(1)
@@ -250,6 +252,23 @@ class HasManyScopingTest< ActiveRecord::TestCase
assert_equal 'a comment...', @welcome.comments.what_are_you
end
end
+
+ def test_should_maintain_default_scope_on_associations
+ person = people(:michael)
+ magician = BadReference.find(1)
+ assert_equal [magician], people(:michael).bad_references
+ end
+
+ def test_should_default_scope_on_associations_is_overriden_by_association_conditions
+ person = people(:michael)
+ assert_equal [], people(:michael).fixed_bad_references
+ end
+
+ def test_should_maintain_default_scope_on_eager_loaded_associations
+ michael = Person.where(:id => people(:michael).id).includes(:bad_references).first
+ magician = BadReference.find(1)
+ assert_equal [magician], michael.bad_references
+ end
end
class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase
@@ -399,4 +418,4 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal nil, PoorDeveloperCalledJamis.create!(:salary => nil).salary
assert_equal 50000, PoorDeveloperCalledJamis.create!(:name => 'David').salary
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index ffde8daa07..cb252d56fe 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1,5 +1,4 @@
require "cases/helper"
-require 'models/tag'
require 'models/tagging'
require 'models/post'
require 'models/topic'
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index df123c9de8..ffc2cd638f 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -1,6 +1,5 @@
require "cases/helper"
require 'models/topic'
-require 'models/reply'
class TransactionCallbacksTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
index 454e42ed37..628029f8df 100644
--- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -1,6 +1,5 @@
require "cases/helper"
require 'models/topic'
-require 'models/reply'
class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
def setup
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
index 3f1b0e333f..fd771ef4be 100644
--- a/activerecord/test/cases/validations_test.rb
+++ b/activerecord/test/cases/validations_test.rb
@@ -4,11 +4,6 @@ require 'models/topic'
require 'models/reply'
require 'models/person'
require 'models/developer'
-require 'models/warehouse_thing'
-require 'models/guid'
-require 'models/owner'
-require 'models/pet'
-require 'models/event'
require 'models/parrot'
require 'models/company'
diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb
index 751946ffc5..b11b340e94 100644
--- a/activerecord/test/cases/xml_serialization_test.rb
+++ b/activerecord/test/cases/xml_serialization_test.rb
@@ -2,7 +2,6 @@ require "cases/helper"
require 'models/contact'
require 'models/post'
require 'models/author'
-require 'models/tagging'
require 'models/comment'
require 'models/company_in_module'
diff --git a/activerecord/test/fixtures/minivans.yml b/activerecord/test/fixtures/minivans.yml
index e7a2ab77eb..f1224a4c1a 100644
--- a/activerecord/test/fixtures/minivans.yml
+++ b/activerecord/test/fixtures/minivans.yml
@@ -2,3 +2,4 @@ cool_first:
minivan_id: m1
name: my_minivan
speedometer_id: s1
+ color: blue
diff --git a/activerecord/test/models/country.rb b/activerecord/test/models/country.rb
new file mode 100644
index 0000000000..15e3a1de0b
--- /dev/null
+++ b/activerecord/test/models/country.rb
@@ -0,0 +1,7 @@
+class Country < ActiveRecord::Base
+
+ set_primary_key :country_id
+
+ has_and_belongs_to_many :treaties
+
+end
diff --git a/activerecord/test/models/minivan.rb b/activerecord/test/models/minivan.rb
index c753319a20..602438d16f 100644
--- a/activerecord/test/models/minivan.rb
+++ b/activerecord/test/models/minivan.rb
@@ -3,4 +3,7 @@ class Minivan < ActiveRecord::Base
belongs_to :speedometer
has_one :dashboard, :through => :speedometer
-end \ No newline at end of file
+
+ attr_readonly :color
+
+end
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index 2a73b1ee01..951ec93c53 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -4,6 +4,8 @@ class Person < ActiveRecord::Base
has_many :posts_with_no_comments, :through => :readers, :source => :post, :include => :comments, :conditions => 'comments.id is null'
has_many :references
+ has_many :bad_references
+ has_many :fixed_bad_references, :conditions => { :favourite => true }, :class_name => 'BadReference'
has_many :jobs, :through => :references
has_one :favourite_reference, :class_name => 'Reference', :conditions => ['favourite=?', true]
has_many :posts_with_comments_sorted_by_comment_id, :through => :readers, :source => :post, :include => :comments, :order => 'comments.id'
diff --git a/activerecord/test/models/reference.rb b/activerecord/test/models/reference.rb
index 479e8b72c6..4a17c936f5 100644
--- a/activerecord/test/models/reference.rb
+++ b/activerecord/test/models/reference.rb
@@ -2,3 +2,8 @@ class Reference < ActiveRecord::Base
belongs_to :person
belongs_to :job
end
+
+class BadReference < ActiveRecord::Base
+ self.table_name ='references'
+ default_scope :conditions => {:favourite => false }
+end
diff --git a/activerecord/test/models/treaty.rb b/activerecord/test/models/treaty.rb
new file mode 100644
index 0000000000..b46537f0d2
--- /dev/null
+++ b/activerecord/test/models/treaty.rb
@@ -0,0 +1,7 @@
+class Treaty < ActiveRecord::Base
+
+ set_primary_key :treaty_id
+
+ has_and_belongs_to_many :countries
+
+end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 641726b43f..f3fd37cd61 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -300,6 +300,7 @@ ActiveRecord::Schema.define do
t.string :minivan_id
t.string :name
t.string :speedometer_id
+ t.string :color
end
create_table :minimalistics, :force => true do |t|
@@ -600,6 +601,21 @@ ActiveRecord::Schema.define do
t.string :title
end
+ create_table :countries, :force => true, :id => false, :primary_key => 'country_id' do |t|
+ t.string :country_id
+ t.string :name
+ end
+ create_table :treaties, :force => true, :id => false, :primary_key => 'treaty_id' do |t|
+ t.string :treaty_id
+ t.string :name
+ end
+ create_table :countries_treaties, :force => true, :id => false do |t|
+ t.string :country_id, :null => false
+ t.string :treaty_id, :null => false
+ t.datetime :created_at
+ t.datetime :updated_at
+ end
+
except 'SQLite' do
# fk_test_has_fk should be before fk_test_has_pk
create_table :fk_test_has_fk, :force => true do |t|
diff --git a/activeresource/README b/activeresource/README.rdoc
index 127ac5b4a9..127ac5b4a9 100644
--- a/activeresource/README
+++ b/activeresource/README.rdoc
diff --git a/activeresource/Rakefile b/activeresource/Rakefile
index 04b08ed8cb..b1e5ca91d3 100644
--- a/activeresource/Rakefile
+++ b/activeresource/Rakefile
@@ -35,7 +35,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include('README', 'CHANGELOG')
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/activeresource.rb')
}
diff --git a/activeresource/activeresource.gemspec b/activeresource/activeresource.gemspec
index ca74c0dd7d..a71168722b 100644
--- a/activeresource/activeresource.gemspec
+++ b/activeresource/activeresource.gemspec
@@ -14,12 +14,12 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'activeresource'
- s.files = Dir['CHANGELOG', 'README', 'examples/**/*', 'lib/**/*']
+ s.files = Dir['CHANGELOG', 'README.rdoc', 'examples/**/*', 'lib/**/*']
s.require_path = 'lib'
s.has_rdoc = true
- s.extra_rdoc_files = %w( README )
- s.rdoc_options.concat ['--main', 'README']
+ s.extra_rdoc_files = %w( README.rdoc )
+ s.rdoc_options.concat ['--main', 'README.rdoc']
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
diff --git a/activesupport/README b/activesupport/README.rdoc
index 9fb9a80cbe..aa86f1fd65 100644
--- a/activesupport/README
+++ b/activesupport/README.rdoc
@@ -7,22 +7,13 @@ Ruby sweeter.
== Download
-The latest version of Active Support can be found at
+The latest version of Active Support can be installed with Rubygems:
-* http://rubyforge.org/project/showfiles.php?group_id=182
+* gem install activesupport
Documentation can be found at
-* http://as.rubyonrails.com
-
-
-== Installation
-
-The preferred method of installing Active Support is through its GEM file. You'll need to have
-RubyGems[http://rubygems.rubyforge.org/wiki/wiki.pl] installed for that, though. If you have it,
-then use:
-
- % [sudo] gem install activesupport-1.0.0.gem
+* http://api.rubyonrails.org
== License
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 2aebe05de2..77b1a8431d 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -28,7 +28,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include('README', 'CHANGELOG')
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
rdoc.rdoc_files.include('lib/active_support.rb')
rdoc.rdoc_files.include('lib/active_support/**/*.rb')
}
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 8611a1e5fa..df7f68fecf 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'activesupport'
- s.files = Dir['CHANGELOG', 'README', 'lib/**/*']
+ s.files = Dir['CHANGELOG', 'README.rdoc', 'lib/**/*']
s.require_path = 'lib'
s.has_rdoc = true
diff --git a/activesupport/install.rb b/activesupport/install.rb
deleted file mode 100644
index 9c54d8c1a9..0000000000
--- a/activesupport/install.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'rbconfig'
-require 'find'
-require 'ftools'
-
-include Config
-
-# this was adapted from rdoc's install.rb by ways of Log4r
-
-$sitedir = CONFIG["sitelibdir"]
-unless $sitedir
- version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
- $libdir = File.join(CONFIG["libdir"], "ruby", version)
- $sitedir = $:.find {|x| x =~ /site_ruby/ }
- if !$sitedir
- $sitedir = File.join($libdir, "site_ruby")
- elsif $sitedir !~ Regexp.quote(version)
- $sitedir = File.join($sitedir, version)
- end
-end
-
-# the actual gruntwork
-Dir.chdir("lib")
-
-Find.find("active_support", "active_support.rb") { |f|
- if f[-3..-1] == ".rb"
- File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
- else
- File::makedirs(File.join($sitedir, *f.split(/\//)))
- end
-}
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 29c3843d16..b861a6f62a 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -101,7 +101,11 @@ module ActiveSupport
@guard.synchronize do
unless buffer.empty?
old_buffer = buffer
- @log.write(old_buffer.join)
+ all_content = StringIO.new
+ old_buffer.each do |content|
+ all_content << content
+ end
+ @log.write(all_content.string)
end
# Important to do this even if buffer was empty or else @buffer will
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index 9c4d5fae26..2d88cb57e5 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -5,9 +5,7 @@ class Module
options = syms.extract_options!
syms.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
- unless defined? @@#{sym}
- @@#{sym} = nil
- end
+ @@#{sym} = nil unless defined? @@#{sym}
def self.#{sym}
@@#{sym}
@@ -28,10 +26,6 @@ class Module
options = syms.extract_options!
syms.each do |sym|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
- unless defined? @@#{sym}
- @@#{sym} = nil
- end
-
def self.#{sym}=(obj)
@@#{sym} = obj
end
diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb
index 2714a46b28..b8c01aca0e 100644
--- a/activesupport/lib/active_support/core_ext/module/remove_method.rb
+++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb
@@ -3,4 +3,9 @@ class Module
remove_method(method)
rescue NameError
end
+
+ def redefine_method(method, &block)
+ remove_possible_method(method)
+ define_method(method, &block)
+ end
end \ No newline at end of file
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 06f077e920..f2e7c2351e 100644
--- a/activesupport/lib/active_support/core_ext/object/to_param.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_param.rb
@@ -44,6 +44,6 @@ class Hash
def to_param(namespace = nil)
collect do |key, value|
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
- end.sort * '&'
+ end * '&'
end
end
diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb
index 891d718af3..7611aff964 100644
--- a/activesupport/lib/active_support/log_subscriber.rb
+++ b/activesupport/lib/active_support/log_subscriber.rb
@@ -63,15 +63,9 @@ module ActiveSupport
@@flushable_loggers = nil
log_subscriber.public_methods(false).each do |event|
- notifier.subscribe("#{event}.#{namespace}") do |*args|
- next if log_subscriber.logger.nil?
-
- begin
- log_subscriber.send(event, ActiveSupport::Notifications::Event.new(*args))
- rescue Exception => e
- log_subscriber.logger.error "Could not log #{args[0].inspect} event. #{e.class}: #{e.message}"
- end
- end
+ next if 'call' == event.to_s
+
+ notifier.subscribe("#{event}.#{namespace}", log_subscriber)
end
end
@@ -92,6 +86,17 @@ module ActiveSupport
flushable_loggers.each(&:flush)
end
+ def call(message, *args)
+ return unless logger
+
+ method = message.split('.').first
+ begin
+ send(method, ActiveSupport::Notifications::Event.new(message, *args))
+ rescue Exception => e
+ logger.error "Could not log #{message.inspect} event. #{e.class}: #{e.message}"
+ end
+ end
+
protected
%w(info debug warn error fatal unknown).each do |level|
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 96506a4b2b..9e52cb97a9 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -1,4 +1,5 @@
require 'active_support/log_subscriber'
+require 'active_support/buffered_logger'
module ActiveSupport
class LogSubscriber
@@ -33,7 +34,7 @@ module ActiveSupport
module TestHelper
def setup
@logger = MockLogger.new
- @notifier = ActiveSupport::Notifications::Notifier.new(queue)
+ @notifier = ActiveSupport::Notifications::Fanout.new
ActiveSupport::LogSubscriber.colorize_logging = false
@@ -47,10 +48,14 @@ module ActiveSupport
end
class MockLogger
+ include ActiveSupport::BufferedLogger::Severity
+
attr_reader :flush_count
+ attr_accessor :level
- def initialize
+ def initialize(level = DEBUG)
@flush_count = 0
+ @level = level
@logged = Hash.new { |h,k| h[k] = [] }
end
@@ -65,6 +70,14 @@ module ActiveSupport
def flush
@flush_count += 1
end
+
+ ActiveSupport::BufferedLogger::Severity.constants.each do |severity|
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{severity.downcase}?
+ #{severity} >= @level
+ end
+ EOT
+ end
end
# Wait notifications to be published.
@@ -81,10 +94,6 @@ module ActiveSupport
def set_logger(logger)
ActiveSupport::LogSubscriber.logger = logger
end
-
- def queue
- ActiveSupport::Notifications::Fanout.new
- end
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index 1444fc1609..93d1907edc 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -47,34 +47,12 @@ module ActiveSupport
delegate :instrument, :to => :instrumenter
def notifier
- @notifier ||= Notifier.new
+ @notifier ||= Fanout.new
end
def instrumenter
Thread.current[:"instrumentation_#{notifier.object_id}"] ||= Instrumenter.new(notifier)
end
end
-
- class Notifier
- def initialize(queue = Fanout.new)
- @queue = queue
- end
-
- def publish(*args)
- @queue.publish(*args)
- end
-
- def subscribe(pattern = nil, &block)
- @queue.bind(pattern).subscribe(&block)
- end
-
- def unsubscribe(subscriber)
- @queue.unsubscribe(subscriber)
- end
-
- def wait
- @queue.wait
- end
- end
end
end
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index 300ec842a9..64f315cb6a 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -8,14 +8,11 @@ module ActiveSupport
@listeners_for = {}
end
- def bind(pattern)
- Binding.new(self, pattern)
- end
-
- def subscribe(pattern = nil, &block)
+ def subscribe(pattern = nil, block = Proc.new)
@listeners_for.clear
- @subscribers << Subscriber.new(pattern, &block)
- @subscribers.last
+ Subscriber.new(pattern, block).tap do |s|
+ @subscribers << s
+ end
end
def unsubscribe(subscriber)
@@ -24,69 +21,35 @@ module ActiveSupport
end
def publish(name, *args)
- if listeners = @listeners_for[name]
- listeners.each { |s| s.publish(name, *args) }
- else
- @listeners_for[name] = @subscribers.select { |s| s.publish(name, *args) }
- end
+ listeners_for(name).each { |s| s.publish(name, *args) }
end
- # This is a sync queue, so there is not waiting.
- def wait
+ def listeners_for(name)
+ @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
end
- # Used for internal implementation only.
- class Binding #:nodoc:
- def initialize(queue, pattern)
- @queue = queue
- @pattern =
- case pattern
- when Regexp, NilClass
- pattern
- else
- /^#{Regexp.escape(pattern.to_s)}$/
- end
- end
-
- def subscribe(&block)
- @queue.subscribe(@pattern, &block)
- end
+ # This is a sync queue, so there is not waiting.
+ def wait
end
class Subscriber #:nodoc:
- def initialize(pattern, &block)
+ def initialize(pattern, delegate)
@pattern = pattern
- @block = block
+ @delegate = delegate
end
- def publish(*args)
- return unless subscribed_to?(args.first)
- push(*args)
- true
- end
-
- def drained?
- true
+ def publish(message, *args)
+ @delegate.call(message, *args)
end
def subscribed_to?(name)
- !@pattern || @pattern =~ name.to_s
+ !@pattern || @pattern === name.to_s
end
def matches?(subscriber_or_name)
- case subscriber_or_name
- when String
- @pattern && @pattern =~ subscriber_or_name
- when self
- true
- end
+ self === subscriber_or_name ||
+ @pattern && @pattern === subscriber_or_name
end
-
- private
-
- def push(*args)
- @block.call(*args)
- end
end
end
end
diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb
index 7e89402822..e98189f899 100644
--- a/activesupport/lib/active_support/notifications/instrumenter.rb
+++ b/activesupport/lib/active_support/notifications/instrumenter.rb
@@ -9,23 +9,30 @@ module ActiveSupport
def initialize(notifier)
@id = unique_id
@notifier = notifier
+ @started = nil
+ @finished = nil
end
# Instrument the given block by measuring the time taken to execute it
# and publish it. Notice that events get sent even if an error occurs
# in the passed-in block
def instrument(name, payload={})
- time = Time.now
begin
+ @started = Time.now
yield(payload) if block_given?
rescue Exception => e
payload[:exception] = [e.class.name, e.message]
raise e
ensure
- @notifier.publish(name, time, Time.now, @id, payload)
+ @finished = Time.now
+ @notifier.publish(name, @started, @finished, @id, payload)
end
end
+ def elapsed
+ 1000.0 * (@finished.to_f - @started.to_f)
+ end
+
private
def unique_id
SecureRandom.hex(10)
@@ -33,7 +40,7 @@ module ActiveSupport
end
class Event
- attr_reader :name, :time, :end, :transaction_id, :payload
+ attr_reader :name, :time, :end, :transaction_id, :payload, :duration
def initialize(name, start, ending, transaction_id, payload)
@name = name
@@ -41,14 +48,11 @@ module ActiveSupport
@time = start
@transaction_id = transaction_id
@end = ending
- end
-
- def duration
- @duration ||= 1000.0 * (@end - @time)
+ @duration = 1000.0 * (@end - @time)
end
def parent_of?(event)
- start = (self.time - event.time) * 1000
+ start = (time - event.time) * 1000
start <= 0 && (start + duration >= event.duration)
end
end
diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb
index 850febb959..97c0ef14db 100644
--- a/activesupport/test/buffered_logger_test.rb
+++ b/activesupport/test/buffered_logger_test.rb
@@ -1,9 +1,12 @@
require 'abstract_unit'
+require 'multibyte_test_helpers'
require 'stringio'
require 'fileutils'
require 'active_support/buffered_logger'
class BufferedLoggerTest < Test::Unit::TestCase
+ include MultibyteTestHelpers
+
Logger = ActiveSupport::BufferedLogger
def setup
@@ -146,4 +149,16 @@ class BufferedLoggerTest < Test::Unit::TestCase
@logger.expects :clear_buffer
@logger.flush
end
+
+ def test_buffer_multibyte
+ @logger.auto_flushing = 2
+ @logger.info(UNICODE_STRING)
+ @logger.info(BYTE_STRING)
+ assert @output.string.include?(UNICODE_STRING)
+ byte_string = @output.string.dup
+ if byte_string.respond_to?(:force_encoding)
+ byte_string.force_encoding("ASCII-8BIT")
+ end
+ assert byte_string.include?(BYTE_STRING)
+ end
end
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 7b2c10908f..5d9846a216 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -2,6 +2,8 @@ require 'abstract_unit'
require 'active_support/core_ext/hash'
require 'bigdecimal'
require 'active_support/core_ext/string/access'
+require 'active_support/ordered_hash'
+require 'active_support/core_ext/object/conversions'
class HashExtTest < Test::Unit::TestCase
def setup
@@ -449,6 +451,33 @@ class IWriteMyOwnXML
end
end
+class HashExtToParamTests < Test::Unit::TestCase
+ class ToParam < String
+ def to_param
+ "#{self}-1"
+ end
+ end
+
+ def test_string_hash
+ assert_equal '', {}.to_param
+ assert_equal 'hello=world', { :hello => "world" }.to_param
+ assert_equal 'hello=10', { "hello" => 10 }.to_param
+ assert_equal 'hello=world&say_bye=true', ActiveSupport::OrderedHash[:hello, "world", "say_bye", true].to_param
+ end
+
+ def test_number_hash
+ assert_equal '10=20&30=40&50=60', ActiveSupport::OrderedHash[10, 20, 30, 40, 50, 60].to_param
+ end
+
+ def test_to_param_hash
+ assert_equal 'custom=param-1&custom2=param2-1', ActiveSupport::OrderedHash[ToParam.new('custom'), ToParam.new('param'), ToParam.new('custom2'), ToParam.new('param2')].to_param
+ end
+
+ def test_to_param_hash_escapes_its_keys_and_values
+ assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param
+ end
+end
+
class HashToXmlTest < Test::Unit::TestCase
def setup
@xml_options = { :root => :person, :skip_instruct => true, :indent => 0 }
diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb
index 597f949059..8839b75601 100644
--- a/activesupport/test/multibyte_test_helpers.rb
+++ b/activesupport/test/multibyte_test_helpers.rb
@@ -4,6 +4,9 @@ module MultibyteTestHelpers
UNICODE_STRING = 'こにちわ'
ASCII_STRING = 'ohayo'
BYTE_STRING = "\270\236\010\210\245"
+ if BYTE_STRING.respond_to?(:force_encoding)
+ BYTE_STRING.force_encoding("ASCII-8BIT")
+ end
def chars(str)
ActiveSupport::Multibyte::Chars.new(str)
@@ -16,4 +19,4 @@ module MultibyteTestHelpers
def assert_equal_codepoints(expected, actual, message=nil)
assert_equal(inspect_codepoints(expected), inspect_codepoints(actual), message)
end
-end \ No newline at end of file
+end
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index 3e16e01d89..41e8ca4ae7 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -11,14 +11,11 @@ module Notifications
@named_subscription = @notifier.subscribe("named.subscription") { |*args| @named_events << event(*args) }
end
- private
- def event(*args)
- ActiveSupport::Notifications::Event.new(*args)
- end
+ private
- def drain
- @notifier.wait
- end
+ def event(*args)
+ ActiveSupport::Notifications::Event.new(*args)
+ end
end
class UnsubscribeTest < TestCase
@@ -132,13 +129,10 @@ module Notifications
def test_instrument_returns_block_result
assert_equal 2, instrument(:awesome) { 1 + 1 }
- drain
end
def test_instrument_yields_the_paylod_for_further_modification
assert_equal 2, instrument(:awesome) { |p| p[:result] = 1 + 1 }
- drain
-
assert_equal 1, @events.size
assert_equal :awesome, @events.first.name
assert_equal Hash[:result => 2], @events.first.payload
@@ -154,15 +148,11 @@ module Notifications
1 + 1
end
- drain
-
assert_equal 1, @events.size
assert_equal :wot, @events.first.name
assert_equal Hash[:payload => "child"], @events.first.payload
end
- drain
-
assert_equal 2, @events.size
assert_equal :awesome, @events.last.name
assert_equal Hash[:payload => "notifications"], @events.last.payload
@@ -177,16 +167,22 @@ module Notifications
assert_equal "FAIL", e.message
end
- drain
assert_equal 1, @events.size
assert_equal Hash[:payload => "notifications",
:exception => ["RuntimeError", "FAIL"]], @events.last.payload
end
+ def test_elapsed
+ instrument(:something) do
+ sleep(0.001)
+ end
+
+ # Elapsed returns duration in ms
+ assert_in_delta 1, ActiveSupport::Notifications.instrumenter.elapsed, 100
+ end
+
def test_event_is_pushed_even_without_block
instrument(:awesome, :payload => "notifications")
- drain
-
assert_equal 1, @events.size
assert_equal :awesome, @events.last.name
assert_equal Hash[:payload => "notifications"], @events.last.payload
@@ -200,7 +196,7 @@ module Notifications
assert_equal :foo, event.name
assert_equal time, event.time
- assert_in_delta 10.0, event.duration, 0.00000000000001
+ assert_in_delta 10.0, event.duration, 0.00001
end
def test_events_consumes_information_given_as_payload
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 8e2bac7f00..6a8db7c4a6 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [Release Candidate] (unreleased)*
+* Added console to Rails::Railtie as a hook called just after console starts. [José Valim]
+
* Rails no longer autoload code in lib for application. You need to explicitly require it. [José Valim]
* Rails::LogSubscriber was renamed to ActiveSupport::LogSubscriber [José Valim]
@@ -13,26 +15,26 @@
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
-* Version bump
-* Removed Rails Metal [YK & JV].
+* Removed Rails Metal [Yehuda Katz, José Valim].
+
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
-* Renamed config.cookie_secret to config.secret_token and pass it as env key. [JV]
+* Renamed config.cookie_secret to config.secret_token and pass it as env key. [José Valim]
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
-* Session store configuration has changed [YK & CL]
+* Session store configuration has changed [Yehuda Katz, Carl Lerche]
config.session_store :cookie_store, {:key => "..."}
config.cookie_secret = "fdsfhisdghfidugnfdlg"
* railtie_name and engine_name are deprecated. You can now add any object to
- the configuration object: config.your_plugin = {} [JV]
+ the configuration object: config.your_plugin = {} [José Valim]
* Added config.generators.templates to provide alternative paths for the generators
- to look for templates [JV]
+ to look for templates [José Valim]
*Rails 3.0.0 [beta 1] (February 4, 2010)*
diff --git a/railties/README b/railties/README
deleted file mode 100644
index d8be15e346..0000000000
--- a/railties/README
+++ /dev/null
@@ -1,281 +0,0 @@
-== Welcome to Rails
-
-Rails is a web-application framework that includes everything needed to create
-database-backed web applications according to the Model-View-Control pattern.
-
-This pattern splits the view (also called the presentation) into "dumb"
-templates that are primarily responsible for inserting pre-built data in between
-HTML tags. The model contains the "smart" domain objects (such as Account,
-Product, Person, Post) that holds all the business logic and knows how to
-persist themselves to a database. The controller handles the incoming requests
-(such as Save New Account, Update Product, Show Post) by manipulating the model
-and directing data to the view.
-
-In Rails, the model is handled by what's called an object-relational mapping
-layer entitled Active Record. This layer allows you to present the data from
-database rows as objects and embellish these data objects with business logic
-methods. You can read more about Active Record in
-link:files/vendor/rails/activerecord/README.html.
-
-The controller and view are handled by the Action Pack, which handles both
-layers by its two parts: Action View and Action Controller. These two layers
-are bundled in a single package due to their heavy interdependence. This is
-unlike the relationship between the Active Record and Action Pack that is much
-more separate. Each of these packages can be used independently outside of
-Rails. You can read more about Action Pack in
-link:files/vendor/rails/actionpack/README.html.
-
-
-== Getting Started
-
-1. At the command prompt, create a new Rails application:
- <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
-
-2. Change directory to <tt>myapp</tt> and start the web server:
- <tt>cd myapp; rails server</tt> (run with --help for options)
-
-3. Go to http://localhost:3000/ and you'll see:
- "Welcome aboard: You're riding Ruby on Rails!"
-
-4. Follow the guidelines to start developing your application. You can find
-the following resources handy:
-
-* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
-* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
-
-
-== Web Servers
-
-By default, Rails will try to use Mongrel if it's installed when started with
-<tt>rails server</tt>, otherwise Rails will use WEBrick, the web server that
-ships with Ruby.
-
-Mongrel is a Ruby-based web server with a C component (which requires
-compilation) that is suitable for development. If you have Ruby Gems installed,
-getting up and running with mongrel is as easy as:
- <tt>sudo gem install mongrel</tt>.
-
-You can find more info at: http://mongrel.rubyforge.org
-
-You can alternatively run Rails applications with other Ruby web servers, e.g.,
-{Thin}[http://code.macournoyer.com/thin/], {Ebb}[http://ebb.rubyforge.org/], and
-Apache with {mod_rails}[http://www.modrails.com/]. However, <tt>rails server</tt>
-doesn't search for or start them.
-
-For production use, often a web/proxy server, e.g., {Apache}[http://apache.org],
-{Nginx}[http://nginx.net/], {LiteSpeed}[http://litespeedtech.com/],
-{Lighttpd}[http://www.lighttpd.net/], or {IIS}[http://www.iis.net/], is deployed
-as the front end server with the chosen Ruby web server running in the back end
-and receiving the proxied requests via one of several protocols (HTTP, CGI, FCGI).
-
-
-== Debugging Rails
-
-Sometimes your application goes wrong. Fortunately there are a lot of tools that
-will help you debug it and get it back on the rails.
-
-First area to check is the application log files. Have "tail -f" commands
-running on the server.log and development.log. Rails will automatically display
-debugging and runtime information to these files. Debugging info will also be
-shown in the browser on requests from 127.0.0.1.
-
-You can also log your own messages directly into the log file from your code
-using the Ruby logger class from inside your controllers. Example:
-
- class WeblogController < ActionController::Base
- def destroy
- @weblog = Weblog.find(params[:id])
- @weblog.destroy
- logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
- end
- end
-
-The result will be a message in your log file along the lines of:
-
- Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
-
-More information on how to use the logger is at http://www.ruby-doc.org/core/
-
-Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
-several books available online as well:
-
-* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
-* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
-
-These two books will bring you up to speed on the Ruby language and also on
-programming in general.
-
-
-== Debugger
-
-Debugger support is available through the debugger command when you start your
-Mongrel or WEBrick server with --debugger. This means that you can break out of
-execution at any point in the code, investigate and change the model, and then,
-resume execution! You need to install ruby-debug to run the server in debugging
-mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example:
-
- class WeblogController < ActionController::Base
- def index
- @posts = Post.find(:all)
- debugger
- end
- end
-
-So the controller will accept the action, run the first line, then present you
-with a IRB prompt in the server window. Here you can do things like:
-
- >> @posts.inspect
- => "[#<Post:0x14a6be8
- @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
- #<Post:0x14a6620
- @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
- >> @posts.first.title = "hello from a debugger"
- => "hello from a debugger"
-
-...and even better, you can examine how your runtime objects actually work:
-
- >> f = @posts.first
- => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
- >> f.
- Display all 152 possibilities? (y or n)
-
-Finally, when you're ready to resume execution, you can enter "cont".
-
-
-== Console
-
-The console is a Ruby shell, which allows you to interact with your
-application's domain model. Here you'll have all parts of the application
-configured, just like it is when the application is running. You can inspect
-domain models, change values, and save to the database. Starting the script
-without arguments will launch it in the development environment.
-
-To start the console, run <tt>rails console</tt> from the application
-directory.
-
-Options:
-
-* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications
- made to the database.
-* Passing an environment name as an argument will load the corresponding
- environment. Example: <tt>rails console production</tt>.
-
-To reload your controllers and models after launching the console run
-<tt>reload!</tt>
-
-More information about irb can be found at:
-link:http://www.rubycentral.com/pickaxe/irb.html
-
-
-== dbconsole
-
-You can go to the command line of your database directly through <tt>rails
-dbconsole</tt>. You would be connected to the database with the credentials
-defined in database.yml. Starting the script without arguments will connect you
-to the development database. Passing an argument will connect you to a different
-database, like <tt>rails dbconsole production</tt>. Currently works for MySQL,
-PostgreSQL and SQLite 3.
-
-== Description of Contents
-
-The default directory structure of a generated Ruby on Rails application:
-
- |-- app
- | |-- controllers
- | |-- helpers
- | |-- models
- | `-- views
- | `-- layouts
- |-- config
- | |-- environments
- | |-- initializers
- | `-- locales
- |-- db
- |-- doc
- |-- lib
- | `-- tasks
- |-- log
- |-- public
- | |-- images
- | |-- javascripts
- | `-- stylesheets
- |-- script
- | `-- performance
- |-- test
- | |-- fixtures
- | |-- functional
- | |-- integration
- | |-- performance
- | `-- unit
- |-- tmp
- | |-- cache
- | |-- pids
- | |-- sessions
- | `-- sockets
- `-- vendor
- `-- plugins
-
-app
- Holds all the code that's specific to this particular application.
-
-app/controllers
- Holds controllers that should be named like weblogs_controller.rb for
- automated URL mapping. All controllers should descend from
- ApplicationController which itself descends from ActionController::Base.
-
-app/models
- Holds models that should be named like post.rb. Models descend from
- ActiveRecord::Base by default.
-
-app/views
- Holds the template files for the view that should be named like
- weblogs/index.html.erb for the WeblogsController#index action. All views use
- eRuby syntax by default.
-
-app/views/layouts
- Holds the template files for layouts to be used with views. This models the
- common header/footer method of wrapping views. In your views, define a layout
- using the <tt>layout :default</tt> and create a file named default.html.erb.
- Inside default.html.erb, call <% yield %> to render the view using this
- layout.
-
-app/helpers
- Holds view helpers that should be named like weblogs_helper.rb. These are
- generated for you automatically when using generators for controllers.
- Helpers can be used to wrap functionality for your views into methods.
-
-config
- Configuration files for the Rails environment, the routing map, the database,
- and other dependencies.
-
-db
- Contains the database schema in schema.rb. db/migrate contains all the
- sequence of Migrations for your schema.
-
-doc
- This directory is where your application documentation will be stored when
- generated using <tt>rake doc:app</tt>
-
-lib
- Application specific libraries. Basically, any kind of custom code that
- doesn't belong under controllers, models, or helpers. This directory is in
- the load path.
-
-public
- The directory available for the web server. Contains subdirectories for
- images, stylesheets, and javascripts. Also contains the dispatchers and the
- default HTML files. This should be set as the DOCUMENT_ROOT of your web
- server.
-
-script
- Helper scripts for automation and generation.
-
-test
- Unit and functional tests along with fixtures. When using the rails generate
- command, template test files will be generated for you and placed in this
- directory.
-
-vendor
- External libraries that the application depends on. Also includes the plugins
- subdirectory. If the app has frozen rails, those gems also go here, under
- vendor/rails/. This directory is in the load path.
diff --git a/railties/README.rdoc b/railties/README.rdoc
new file mode 100644
index 0000000000..a1718a7d96
--- /dev/null
+++ b/railties/README.rdoc
@@ -0,0 +1,25 @@
+= Railties -- Gluing the Engine to the Rails
+
+Railties is responsible to glue all frameworks together. Overall, it:
+
+* handles all the bootstrapping process for a Rails application;
+
+* manager rails command line interface;
+
+* provides Rails generators core;
+
+
+== Download
+
+The latest version of Railties can be installed with Rubygems:
+
+* gem install railties
+
+Documentation can be found at
+
+* http://api.rubyonrails.org
+
+
+== License
+
+Railties is released under the MIT license.
diff --git a/railties/Rakefile b/railties/Rakefile
index ddc872e18b..19c860f257 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -35,13 +35,6 @@ end
# Update spinoffs -------------------------------------------------------------------
-desc "Updates application README to the latest version Railties README"
-task :update_readme do
- readme = "lib/rails/generators/rails/app/templates/README"
- rm readme
- cp "./README", readme
-end
-
desc 'Generate guides (for authors), use ONLY=foo to process just "foo.textile"'
task :generate_guides do
ENV["WARN_BROKEN_LINKS"] = "1" # authors can't disable this
@@ -66,7 +59,7 @@ Rake::RDocTask.new { |rdoc|
rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=object'
rdoc.options << '--charset' << 'utf-8'
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : '../doc/template/horo'
- rdoc.rdoc_files.include('README', 'CHANGELOG')
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('lib/rails/generators/**/templates/*')
}
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 297dad2ccc..e53c7715bb 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -781,6 +781,28 @@ end
This may come in handy if you need to define a method that may already exist, since redefining a method issues a warning "method redefined; discarding old redefined_method_name".
+h5. +redefine_method(method_name, &block)+
+
+The method first removes method with given name (using +remove_possible_method+) and then defines new one.
+
+<ruby>
+class A; end
+
+A.class_eval do
+ redefine_method(:foobar) do |foo|
+ #do something here
+ end
+
+ #Code above does the same as this:
+
+ method_name = :foobar
+ remove_possible_method(method_name)
+ define_method(method_name) do |foo|
+ #do something here
+ end
+end
+</ruby>
+
NOTE: Defined in +active_support/core_ext/module/remove_method.rb+.
h4. Parents
diff --git a/railties/guides/source/contributing_to_rails.textile b/railties/guides/source/contributing_to_rails.textile
index 5590895508..f0e9a4b5ec 100644
--- a/railties/guides/source/contributing_to_rails.textile
+++ b/railties/guides/source/contributing_to_rails.textile
@@ -62,26 +62,39 @@ git clone git://github.com/rails/rails.git
cd rails
</shell>
-h4. Pick a Branch
+h4. Set up and Run the Tests
-Currently, there is active work being done on both the 2-3-stable branch of Rails and on the master branch (which will become Rails 3.0). If you want to work with the master branch, you're all set. To work with 2.3, you'll need to set up and switch to your own local tracking branch:
+All of the Rails tests must pass with any code you submit, otherwise you have no chance of getting code accepted. This means you need to be able to run the tests. First, you need to install all Rails dependencies with bundler:
<shell>
-git branch --track 2-3-stable origin/2-3-stable
-git checkout 2-3-stable
+gem install bundler
+bundle install --without db
</shell>
-TIP: You may want to "put your git branch name in your shell prompt":http://github.com/guides/put-your-git-branch-name-in-your-shell-prompt to make it easier to remember which version of the code you're working with.
+The second command will install all dependencies, except MySQL and PostgreSQL. We will come back at these soon. With dependencies installed, you can run the whole Rails test suite with:
-h4. Set up and Run the Tests
+<shell>
+rake test
+</shell>
-All of the Rails tests must pass with any code you submit, otherwise you have no chance of getting code accepted. This means you need to be able to run the tests. Rails needs the +mocha+ gem for running some tests, so install it with:
+You can also run tests for an specific framework, like Action Pack, by going into its directory and executing the same command:
<shell>
-gem install mocha
+cd actionpack
+rake test
</shell>
-For the tests that touch the database, this means creating test databases. If you're using MySQL, create a user named +rails+ with privileges on the test databases.
+h4. Testing Active Record
+
+By default, when you run Active Record tests, it will execute the test suite three times, one for each of the main databases: SQLite3, MySQL and PostgreSQL. If you are adding a feature that is not specific to the database, you can run the test suite (or just one file) for just one of them. Here is an example for SQLite3:
+
+<shell>
+cd activerecord
+rake test_sqlite3
+rake test_sqlite3 TEST=test/cases/validations_test.rb
+</shell>
+
+If you want to use another database, as MySQL, you need to create a user named +rails+ with privileges on the test databases.
<shell>
mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.*
@@ -90,7 +103,13 @@ mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.*
to 'rails'@'localhost';
</shell>
-Enter this from the +activerecord+ directory to create the test databases:
+Then ensure you run bundle install without the +--without db+ option:
+
+<shell>
+bundle install
+</shell>
+
+Finally, enter this from the +activerecord+ directory to create the test databases:
<shell>
rake mysql:build_databases
@@ -100,18 +119,26 @@ NOTE: Using the rake task to create the test databases ensures they have the cor
If you’re using another database, check the files under +activerecord/test/connections+ in the Rails source code for default connection information. You can edit these files if you _must_ on your machine to provide different credentials, but obviously you should not push any such changes back to Rails.
-Now if you go back to the root of the Rails source on your machine and run +rake+ with no parameters, you should see every test in all of the Rails components pass. If you want to run the all ActiveRecord tests (or just a single one) with another database adapter, enter this from the +activerecord+ directory:
+You can now run tests as you did for +sqlite3+:
<shell>
-rake test_sqlite3
-rake test_sqlite3 TEST=test/cases/validations_test.rb
+rake test_mysql
</shell>
-You can replace +sqlite3+ with +jdbcmysql+, +jdbcsqlite3+, +jdbcpostgresql+, +mysql+ or +postgresql+. 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 +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.
+h4. Older versions of Rails
-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.
+If you want to work add a fix to older versions of Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to Rails 2.3 branch:
+
+<shell>
+git branch --track 2-3-stable origin/2-3-stable
+git checkout 2-3-stable
+</shell>
+
+TIP: You may want to "put your git branch name in your shell prompt":http://github.com/guides/put-your-git-branch-name-in-your-shell-prompt to make it easier to remember which version of the code you're working with.
h3. Helping to Resolve Existing Issues
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 458177b954..3f9bca0bd6 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -149,6 +149,13 @@ module Rails
self
end
+ def load_console(sandbox=false)
+ initialize_console(sandbox)
+ railties.all { |r| r.load_console }
+ super()
+ self
+ end
+
def app
@app ||= begin
config.middleware = config.middleware.merge_into(default_middleware_stack)
@@ -212,5 +219,11 @@ module Rails
def initialize_generators
require "rails/generators"
end
+
+ def initialize_console(sandbox=false)
+ require "rails/console/app"
+ require "rails/console/sandbox" if sandbox
+ require "rails/console/helpers"
+ end
end
end
diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb
index 50df6ba405..834a120c01 100644
--- a/railties/lib/rails/commands/console.rb
+++ b/railties/lib/rails/commands/console.rb
@@ -23,10 +23,7 @@ module Rails
opt.parse!(ARGV)
end
- @app.initialize!
- require "rails/console/app"
- require "rails/console/sandbox" if options[:sandbox]
- require "rails/console/helpers"
+ @app.load_console(options[:sandbox])
if options[:debugger]
begin
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index 0becb780de..e5af12b901 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -56,12 +56,11 @@ module Rails
return @options[method] if args.empty?
- if method == :rails
- namespace, configuration = :rails, args.shift
- elsif args.first.is_a?(Hash)
+ if method == :rails || args.first.is_a?(Hash)
namespace, configuration = method, args.shift
else
namespace, configuration = args.shift, args.shift
+ namespace = namespace.to_sym if namespace.respond_to?(:to_sym)
@options[:rails][method] = namespace
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index 7a94d6e05c..190ab04cf5 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -46,13 +46,6 @@ module <%= app_const_base %>
# config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
<% end -%>
- # Configure generators values. Many other options are available, be sure to check the documentation.
- # config.generators do |g|
- # g.orm :active_record
- # g.template_engine :erb
- # g.test_framework :test_unit, :fixture => true
- # end
-
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index dbdbfea509..1d6a2de87d 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -156,6 +156,12 @@ module Rails
@rake_tasks
end
+ def console(&blk)
+ @load_console ||= []
+ @load_console << blk if blk
+ @load_console
+ end
+
def generators(&blk)
@generators ||= []
@generators << blk if blk
@@ -170,20 +176,16 @@ module Rails
def eager_load!
end
- def rake_tasks
- self.class.rake_tasks
- end
-
- def generators
- self.class.generators
+ def load_console
+ self.class.console.each(&:call)
end
def load_tasks
- rake_tasks.each { |blk| blk.call }
+ self.class.rake_tasks.each(&:call)
end
def load_generators
- generators.each { |blk| blk.call }
+ self.class.generators.each(&:call)
end
end
end
diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake
index 492f05e3cc..843d2b4e82 100644
--- a/railties/lib/rails/tasks/documentation.rake
+++ b/railties/lib/rails/tasks/documentation.rake
@@ -55,46 +55,46 @@ namespace :doc do
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
rdoc.title = "Rails Framework Documentation"
rdoc.options << '--line-numbers' << '--inline-source'
- rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('README.rdoc')
gem_path('actionmailer') do |actionmailer|
- %w(README CHANGELOG MIT-LICENSE lib/action_mailer/base.rb).each do |file|
+ %w(README.rdoc CHANGELOG MIT-LICENSE lib/action_mailer/base.rb).each do |file|
rdoc.rdoc_files.include("#{actionmailer}/#{file}")
end
end
gem_path('actionpack') do |actionpack|
- %w(README CHANGELOG MIT-LICENSE lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file|
+ %w(README.rdoc CHANGELOG MIT-LICENSE lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file|
rdoc.rdoc_files.include("#{actionpack}/#{file}")
end
end
gem_path('activemodel') do |activemodel|
- %w(README CHANGELOG MIT-LICENSE lib/active_model/**/*.rb).each do |file|
+ %w(README.rdoc CHANGELOG MIT-LICENSE lib/active_model/**/*.rb).each do |file|
rdoc.rdoc_files.include("#{activemodel}/#{file}")
end
end
gem_path('activerecord') do |activerecord|
- %w(README CHANGELOG lib/active_record/**/*.rb).each do |file|
+ %w(README.rdoc CHANGELOG lib/active_record/**/*.rb).each do |file|
rdoc.rdoc_files.include("#{activerecord}/#{file}")
end
end
gem_path('activeresource') do |activeresource|
- %w(README CHANGELOG lib/active_resource.rb lib/active_resource/*).each do |file|
+ %w(README.rdoc CHANGELOG lib/active_resource.rb lib/active_resource/*).each do |file|
rdoc.rdoc_files.include("#{activeresource}/#{file}")
end
end
gem_path('activesupport') do |activesupport|
- %w(README CHANGELOG lib/active_support/**/*.rb).each do |file|
+ %w(README.rdoc CHANGELOG lib/active_support/**/*.rb).each do |file|
rdoc.rdoc_files.include("#{activesupport}/#{file}")
end
end
gem_path('railties') do |railties|
- %w(README CHANGELOG lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file|
+ %w(README.rdoc CHANGELOG lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file|
rdoc.rdoc_files.include("#{railties}/#{file}")
end
end
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
index 247b926af9..38dcb17ff1 100644
--- a/railties/railties.gemspec
+++ b/railties/railties.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.homepage = 'http://www.rubyonrails.org'
s.rubyforge_project = 'rails'
- s.files = Dir['CHANGELOG', 'README', 'bin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}']
+ s.files = Dir['CHANGELOG', 'README.rdoc', 'bin/**/*', 'guides/**/*', 'lib/**/{*,.[a-z]*}']
s.require_path = 'lib'
s.rdoc_options << '--exclude' << '.'
diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb
index 8ff69f0208..a72e6916dd 100644
--- a/railties/test/application/console_test.rb
+++ b/railties/test/application/console_test.rb
@@ -9,10 +9,8 @@ class ConsoleTest < Test::Unit::TestCase
end
def load_environment
- # Load steps taken from rails/commands/console.rb
require "#{rails_root}/config/environment"
- require 'rails/console/app'
- require 'rails/console/helpers'
+ Rails.application.load_console
end
def test_app_method_should_return_integration_session
@@ -75,4 +73,21 @@ class ConsoleTest < Test::Unit::TestCase
assert_equal 'Once upon a time in a world...',
helper.truncate('Once upon a time in a world far far away')
end
+
+ def test_active_record_does_not_panic_when_referencing_an_observed_constant
+ add_to_config "config.active_record.observers = :user_observer"
+
+ app_file "app/models/user.rb", <<-MODEL
+ class User < ActiveRecord::Base
+ end
+ MODEL
+
+ app_file "app/models/user_observer.rb", <<-MODEL
+ class UserObserver < ActiveRecord::Observer
+ end
+ MODEL
+
+ load_environment
+ assert_nothing_raised { User }
+ end
end
diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb
index cbf0decd07..d258625f42 100644
--- a/railties/test/application/generators_test.rb
+++ b/railties/test/application/generators_test.rb
@@ -103,5 +103,20 @@ module ApplicationTests
assert_equal({ :plugin => { :generator => "-g" } }, c.generators.aliases)
end
end
+
+ test "generators with string and hash for options should generate symbol keys" do
+ with_bare_config do |c|
+ c.generators do |g|
+ g.orm 'datamapper', :migration => false
+ end
+
+ expected = {
+ :rails => { :orm => :datamapper },
+ :datamapper => { :migration => false }
+ }
+
+ assert_equal expected, c.generators.options
+ end
+ end
end
end
diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb
index fc8548af1f..7e035be764 100644
--- a/railties/test/application/initializers/notifications_test.rb
+++ b/railties/test/application/initializers/notifications_test.rb
@@ -1,17 +1,6 @@
require "isolation/abstract_unit"
module ApplicationTests
- class MockLogger
- def method_missing(*args)
- @logged ||= []
- @logged << args.last
- end
-
- def logged
- @logged.compact.map { |l| l.to_s.strip }
- end
- end
-
class NotificationsTest < Test::Unit::TestCase
include ActiveSupport::Testing::Isolation
@@ -34,15 +23,17 @@ module ApplicationTests
RUBY
require "#{app_path}/config/environment"
+ require "active_support/log_subscriber/test_helper"
- ActiveRecord::Base.logger = logger = MockLogger.new
+ logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
+ ActiveRecord::Base.logger = logger
# Mimic Active Record notifications
instrument "sql.active_record", :name => "SQL", :sql => "SHOW tables"
wait
- assert_equal 1, logger.logged.size
- assert_match /SHOW tables/, logger.logged.last
+ assert_equal 1, logger.logged(:debug).size
+ assert_match /SHOW tables/, logger.logged(:debug).last
end
end
end
diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb
index c74cc01dc1..db0fd87491 100644
--- a/railties/test/railties/railtie_test.rb
+++ b/railties/test/railties/railtie_test.rb
@@ -103,6 +103,22 @@ module RailtiesTest
assert $ran_block
end
+ test "console block is executed when MyApp.load_console is called" do
+ $ran_block = false
+
+ class MyTie < Rails::Railtie
+ console do
+ $ran_block = true
+ end
+ end
+
+ require "#{app_path}/config/environment"
+
+ assert !$ran_block
+ AppTemplate::Application.load_console
+ assert $ran_block
+ end
+
test "railtie can add initializers" do
$ran_block = false