aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/lib/action_mailer/base.rb3
-rw-r--r--actionmailer/test/base_test.rb13
-rw-r--r--actionmailer/test/fixtures/anonymous/welcome.erb1
-rw-r--r--actionpack/CHANGELOG.md4
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb14
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb1
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb1
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb7
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb5
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb1
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb3
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb6
-rw-r--r--actionpack/lib/action_controller/test_case.rb7
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb18
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/dom.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb3
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb3
-rw-r--r--actionpack/lib/action_view/context.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb25
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb3
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb26
-rw-r--r--actionpack/lib/action_view/helpers/debug_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb52
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb24
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb3
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_field.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/file_field.rb4
-rw-r--r--actionpack/lib/action_view/helpers/tags/hidden_field.rb4
-rw-r--r--actionpack/lib/action_view/helpers/tags/number_field.rb1
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb47
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb8
-rw-r--r--actionpack/test/dispatch/routing_test.rb49
-rw-r--r--actionpack/test/fixtures/routes/bogus.rb1
-rw-r--r--actionpack/test/fixtures/routes/external.rb1
-rw-r--r--actionpack/test/template/form_options_helper_test.rb36
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb16
-rw-r--r--actionpack/test/template/text_helper_test.rb8
-rw-r--r--actionpack/test/template/url_helper_test.rb16
-rw-r--r--activemodel/README.rdoc2
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb14
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activemodel/lib/active_model/mass_assignment_security.rb2
-rw-r--r--activemodel/lib/active_model/mass_assignment_security/sanitizer.rb31
-rw-r--r--activemodel/lib/active_model/serialization.rb2
-rw-r--r--activemodel/lib/active_model/validations.rb6
-rw-r--r--activemodel/lib/active_model/validations/acceptance.rb4
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb4
-rw-r--r--activemodel/lib/active_model/validations/exclusion.rb38
-rw-r--r--activemodel/lib/active_model/validations/format.rb52
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb26
-rw-r--r--activemodel/lib/active_model/validations/length.rb43
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb50
-rw-r--r--activemodel/lib/active_model/validations/presence.rb28
-rw-r--r--activemodel/lib/active_model/validations/with.rb10
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb19
-rw-r--r--activemodel/test/cases/dirty_test.rb2
-rw-r--r--activemodel/test/cases/mass_assignment_security/sanitizer_test.rb8
-rw-r--r--activemodel/test/cases/mass_assignment_security_test.rb2
-rw-r--r--activemodel/test/cases/validations_test.rb15
-rw-r--r--activerecord/CHANGELOG.md20
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb15
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb56
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb14
-rw-r--r--activerecord/lib/active_record/core.rb14
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb1
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb55
-rw-r--r--activerecord/lib/active_record/relation/merger.rb3
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb34
-rw-r--r--activerecord/lib/active_record/schema.rb17
-rw-r--r--activerecord/lib/active_record/session_store.rb15
-rw-r--r--activerecord/lib/active_record/transactions.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb19
-rw-r--r--activerecord/test/cases/adapters/sqlite3/copy_table_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb17
-rw-r--r--activerecord/test/cases/ar_schema_test.rb7
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb12
-rw-r--r--activerecord/test/cases/base_test.rb18
-rw-r--r--activerecord/test/cases/calculations_test.rb15
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb4
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb10
-rw-r--r--activerecord/test/cases/migration_test.rb25
-rw-r--r--activerecord/test/cases/readonly_test.rb1
-rw-r--r--activerecord/test/cases/relation_test.rb7
-rw-r--r--activerecord/test/cases/relations_test.rb7
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb21
-rw-r--r--activerecord/test/cases/session_store/sql_bypass_test.rb (renamed from activerecord/test/cases/session_store/sql_bypass.rb)5
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb37
-rw-r--r--activerecord/test/schema/schema.rb1
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb6
-rw-r--r--activesupport/lib/active_support/callbacks.rb25
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_merge.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/hash/diff.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/keys.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/module/aliasing.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/object/deep_dup.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/object/duplicable.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/object/instance_variables.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/range/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/inquiry.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/interpolation.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb14
-rw-r--r--activesupport/lib/active_support/deprecation/behaviors.rb4
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/inflections.rb2
-rw-r--r--activesupport/lib/active_support/inflector/inflections.rb9
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb13
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb2
-rw-r--r--activesupport/lib/active_support/json/encoding.rb2
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb8
-rw-r--r--activesupport/lib/active_support/multibyte.rb3
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb11
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb3
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb12
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb4
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb15
-rw-r--r--activesupport/test/core_ext/duplicable_test.rb4
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb24
-rw-r--r--activesupport/test/inflector_test_cases.rb1
-rw-r--r--activesupport/test/log_subscriber_test.rb2
-rw-r--r--activesupport/test/time_zone_test.rb18
-rw-r--r--guides/source/active_model_basics.textile4
-rw-r--r--guides/source/active_record_querying.textile18
-rw-r--r--guides/source/active_support_core_extensions.textile30
-rw-r--r--guides/source/ajax_on_rails.textile4
-rw-r--r--guides/source/asset_pipeline.textile37
-rw-r--r--guides/source/configuring.textile2
-rw-r--r--guides/source/getting_started.textile291
-rw-r--r--guides/source/i18n.textile6
-rw-r--r--guides/source/layouts_and_rendering.textile6
-rw-r--r--guides/source/migrations.textile16
-rw-r--r--railties/CHANGELOG.md2
-rw-r--r--railties/lib/rails.rb3
-rw-r--r--railties/lib/rails/engine.rb10
-rw-r--r--railties/lib/rails/generators.rb4
-rw-r--r--railties/lib/rails/generators/actions.rb42
-rw-r--r--railties/lib/rails/generators/app_base.rb11
-rw-r--r--railties/lib/rails/generators/base.rb3
-rw-r--r--railties/lib/rails/generators/migration.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt2
-rw-r--r--railties/test/generators/app_generator_test.rb5
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb9
-rw-r--r--railties/test/railties/engine_test.rb10
172 files changed, 1261 insertions, 874 deletions
diff --git a/Gemfile b/Gemfile
index 7a88756028..7ae8344b1f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -60,7 +60,7 @@ platforms :ruby do
gem 'nokogiri', '>= 1.4.5'
# AR
- gem 'sqlite3', '~> 1.3.5'
+ gem 'sqlite3', '~> 1.3.6'
group :db do
gem 'pg', '>= 0.11.0'
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index e24a7f52d5..4f0cff0612 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -3,6 +3,7 @@ require 'action_mailer/collector'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/except'
+require 'active_support/core_ext/module/anonymous'
require 'action_mailer/log_subscriber'
module ActionMailer #:nodoc:
@@ -401,7 +402,7 @@ module ActionMailer #:nodoc:
end
def mailer_name
- @mailer_name ||= name.underscore
+ @mailer_name ||= anonymous? ? "anonymous" : name.underscore
end
attr_writer :mailer_name
alias :controller_path :mailer_name
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index aed3ee1874..1d747ed18a 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -610,6 +610,19 @@ class BaseTest < ActiveSupport::TestCase
assert_equal Set.new(["notify"]), FooMailer.action_methods
end
+ test "mailer can be anonymous" do
+ mailer = Class.new(ActionMailer::Base) do
+ def welcome
+ mail
+ end
+ end
+
+ assert_equal "anonymous", mailer.mailer_name
+
+ assert_equal "Welcome", mailer.welcome.subject
+ assert_equal "Anonymous mailer body", mailer.welcome.body.encoded.strip
+ end
+
protected
# Execute the block setting the given values and restoring old values after
diff --git a/actionmailer/test/fixtures/anonymous/welcome.erb b/actionmailer/test/fixtures/anonymous/welcome.erb
new file mode 100644
index 0000000000..8361da62c4
--- /dev/null
+++ b/actionmailer/test/fixtures/anonymous/welcome.erb
@@ -0,0 +1 @@
+Anonymous mailer body
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index c50b581cb5..432e90199a 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
+* Remove `:disable_with` in favor of `'data-disable-with'` option from `submit_tag`, `button_tag` and `button_to` helpers.
+
+ *Carlos Galdino + Rafael Mendonça França*
+
* Remove `:mouseover` option from `image_tag` helper. *Rafael Mendonça França*
* The `select` method (select tag) forces :include_blank if `required` is true and
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index 307594d54a..dd4eddbe9a 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -60,7 +60,8 @@ module ActionController #:nodoc:
end
module ClassMethods
- # Expires the page that was cached with the +path+ as a key. Example:
+ # Expires the page that was cached with the +path+ as a key.
+ #
# expire_page "/lists/show"
def expire_page(path)
return unless perform_caching
@@ -72,7 +73,8 @@ module ActionController #:nodoc:
end
end
- # Manually cache the +content+ in the key determined by +path+. Example:
+ # Manually cache the +content+ in the key determined by +path+.
+ #
# cache_page "I'm the cached content", "/lists/show"
def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
return unless perform_caching
@@ -93,8 +95,6 @@ module ActionController #:nodoc:
#
# You can also pass a :gzip option to override the class configuration one.
#
- # Usage:
- #
# # cache the index action
# caches_page :index
#
@@ -142,7 +142,8 @@ module ActionController #:nodoc:
end
end
- # Expires the page that was cached with the +options+ as a key. Example:
+ # Expires the page that was cached with the +options+ as a key.
+ #
# expire_page :controller => "lists", :action => "show"
def expire_page(options = {})
return unless self.class.perform_caching
@@ -161,7 +162,8 @@ module ActionController #:nodoc:
end
# Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used.
- # If no options are provided, the url of the current request being handled is used. Example:
+ # If no options are provided, the url of the current request being handled is used.
+ #
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
return unless self.class.perform_caching && caching_allowed?
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 5b25a0d303..2193dde667 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -108,7 +108,6 @@ module ActionController
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a <tt>private</tt> instruction, so that
# intermediate caches must not cache the response.
#
- # Examples:
# expires_in 20.minutes
# expires_in 3.hours, :public => true
# expires_in 3.hours, :public => true, :must_revalidate => true
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 1a4bca12d2..86d061e3b7 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -16,7 +16,6 @@ module ActionController
# Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
# controller which inherits from it.
#
- # ==== Examples
# The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if
# a \Time object is blank:
#
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 7917926978..0b800c3c62 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -16,8 +16,6 @@ module ActionController #:nodoc:
# Defines mime types that are rendered by default when invoking
# <tt>respond_with</tt>.
#
- # Examples:
- #
# respond_to :html, :xml, :json
#
# Specifies that all actions in the controller respond to requests
@@ -185,7 +183,6 @@ module ActionController #:nodoc:
# end
#
# Be sure to check respond_with and respond_to documentation for more examples.
- #
def respond_to(*mimes, &block)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
@@ -323,7 +320,6 @@ module ActionController #:nodoc:
# a successful html +post+ request.
# 2. <tt>:action</tt> - overwrites the default render action used after an
# unsuccessful html +post+ request.
- #
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
@@ -339,7 +335,6 @@ module ActionController #:nodoc:
# Collect mimes declared in the class method respond_to valid for the
# current action.
- #
def collect_mimes_from_class_level #:nodoc:
action = action_name.to_s
@@ -362,7 +357,6 @@ module ActionController #:nodoc:
#
# Sends :not_acceptable to the client and returns nil if no suitable format
# is available.
- #
def retrieve_collector_from_mimes(mimes=nil, &block) #:nodoc:
mimes ||= collect_mimes_from_class_level
collector = Collector.new(mimes)
@@ -401,7 +395,6 @@ module ActionController #:nodoc:
# A subsequent call to #negotiate_format(request) will enable the Collector
# to determine which specific mime-type it should respond with for the current
# request, with this response then being accessible by calling #response.
- #
class Collector
include AbstractController::Collector
attr_accessor :order, :format
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 5e7bd44562..ee0e69d87c 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -24,7 +24,6 @@ module ActionController
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
- # Examples:
# redirect_to :action => "show", :id => 5
# redirect_to post
# redirect_to "http://www.rubyonrails.org"
@@ -35,7 +34,6 @@ module ActionController
#
# The redirection happens as a "302 Moved" header unless otherwise specified.
#
- # Examples:
# redirect_to post_url(@post), :status => :found
# redirect_to :action=>'atom', :status => :moved_permanently
# redirect_to post_url(@post), :status => 301
@@ -51,14 +49,12 @@ module ActionController
# around this you can return a <tt>303 See Other</tt> status code which will be
# followed using a GET request.
#
- # Examples:
# redirect_to posts_url, :status => :see_other
# redirect_to :action => 'index', :status => 303
#
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
#
- # Examples:
# redirect_to post_url(@post), :alert => "Watch it, mister!"
# redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road"
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
@@ -69,6 +65,7 @@ module ActionController
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
+ logger.debug { "Redirected by #{caller(1).first rescue "unknown"}" } if logger
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(options)
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 4a0c1c7dd7..1927c8bdc7 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -49,7 +49,6 @@ module ActionController
# is the value paired with its key and the second is the remaining
# hash of options passed to +render+.
#
- # === Example
# Create a csv renderer:
#
# ActionController::Renderers.add :csv do |obj, options|
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 0bff1825d9..95b0e99ed5 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -51,8 +51,6 @@ module ActionController #:nodoc:
module ClassMethods
# Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked.
#
- # Example:
- #
# class FooController < ApplicationController
# protect_from_forgery :except => :index
#
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 8e7b56dbcc..e28c05cc2d 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -6,8 +6,6 @@ module ActionController
# url options like the +host+. In order to do so, this module requires the host class
# to implement +env+ and +request+, which need to be a Rack-compatible.
#
- # Example:
- #
# class RootUrl
# include ActionController::UrlFor
# include Rails.application.routes.url_helpers
@@ -19,7 +17,6 @@ module ActionController
# @url = root_path # named route from the application.
# end
# end
- #
module UrlFor
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index e7af3f5b8d..16a5decc62 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -3,7 +3,7 @@ require 'active_support/core_ext/module'
module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# pretty much any other model type that has an id. These patterns are then used to try elevate the view actions to
- # a higher logical level. Example:
+ # a higher logical level.
#
# # routes
# resources :posts
@@ -30,7 +30,7 @@ module ActionController
JOIN = '_'.freeze
NEW = 'new'.freeze
- # The DOM class convention is to use the singular form of an object or class. Examples:
+ # The DOM class convention is to use the singular form of an object or class.
#
# dom_class(post) # => "post"
# dom_class(Person) # => "person"
@@ -45,7 +45,7 @@ module ActionController
end
# The DOM id convention is to use the singular form of an object or class with the id following an underscore.
- # If no id is found, prefix with "new_" instead. Examples:
+ # If no id is found, prefix with "new_" instead.
#
# dom_id(Post.find(45)) # => "post_45"
# dom_id(Post.new) # => "new_post"
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index ad02375f12..76d07891c9 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -56,8 +56,6 @@ module ActionController
# Asserts that the request was rendered with the appropriate template file or partials.
#
- # ==== Examples
- #
# # assert that the "new" view template was rendered
# assert_template "new"
#
@@ -84,7 +82,6 @@ module ActionController
#
# # assert that the "_customer" partial was rendered with a specific object
# assert_template :partial => '_customer', :locals => { :customer => @customer }
- #
def assert_template(options = {}, message = nil)
# Force body to be read in case the
# template is being streamed
@@ -350,7 +347,6 @@ module ActionController
# == \Testing named routes
#
# If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
- # Example:
#
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
@@ -369,12 +365,11 @@ module ActionController
module ClassMethods
# Sets the controller class name. Useful if the name can't be inferred from test class.
- # Normalizes +controller_class+ before using. Examples:
+ # Normalizes +controller_class+ before using.
#
# tests WidgetController
# tests :widget
# tests 'widget'
- #
def tests(controller_class)
case controller_class
when String, Symbol
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 132b0c82bc..6413929be3 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -10,8 +10,6 @@ module ActionDispatch
# value of the params hash and all subhashes is passed to it, the value
# or key can be replaced using String#replace or similar method.
#
- # Examples:
- #
# env["action_dispatch.parameter_filter"] = [:password]
# => replaces the value to all keys matching /password/i with "[FILTERED]"
#
@@ -22,7 +20,6 @@ module ActionDispatch
# v.reverse! if k =~ /secret/i
# end
# => reverses the value to all keys matching /secret/i
- #
module FilterParameters
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 17776c2356..9928b7cc3a 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -11,7 +11,7 @@ module ActionDispatch
# The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
# to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
# action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
- # then expose the flash to its template. Actually, that exposure is automatically done. Example:
+ # then expose the flash to its template. Actually, that exposure is automatically done.
#
# class PostsController < ActionController::Base
# def create
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index dbcf703ec3..7efc094f98 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -27,7 +27,7 @@ module ActionDispatch
# CGI::Session instance as an argument. It's important that the secret
# is not vulnerable to a dictionary attack. Therefore, you should choose
# a secret consisting of random numbers and letters and more than 30
- # characters. Examples:
+ # characters.
#
# :secret => '449fe2e7daee471bffae2fd8dc02313d'
# :secret => Proc.new { User.current_user.secret_key }
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 7a22b65c44..67a208263b 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -495,8 +495,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP GET.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# get 'bacon', :to => 'food#bacon'
def get(*args, &block)
map_method(:get, args, &block)
@@ -505,8 +503,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP POST.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# post 'bacon', :to => 'food#bacon'
def post(*args, &block)
map_method(:post, args, &block)
@@ -515,8 +511,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP PATCH.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# patch 'bacon', :to => 'food#bacon'
def patch(*args, &block)
map_method(:patch, args, &block)
@@ -525,8 +519,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP PUT.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# put 'bacon', :to => 'food#bacon'
def put(*args, &block)
map_method(:put, args, &block)
@@ -535,8 +527,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP DELETE.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# delete 'broccoli', :to => 'food#broccoli'
def delete(*args, &block)
map_method(:delete, args, &block)
@@ -681,7 +671,6 @@ module ActionDispatch
# Scopes routes to a specific controller
#
- # Example:
# controller "food" do
# match "bacon", :action => "bacon"
# end
@@ -1336,10 +1325,11 @@ module ActionDispatch
msg = "Your router tried to #draw the external file #{name}.rb,\n" \
"but the file was not found in:\n\n"
msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n")
- raise msg
+ raise ArgumentError, msg
end
-
- instance_eval(path.join("#{name}.rb").read)
+
+ route_path = path.join("#{name}.rb")
+ instance_eval(route_path.read, route_path.to_s)
end
# match 'path' => 'controller#action'
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index ee02f4b531..fd3bed7e8f 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -132,8 +132,6 @@ module ActionDispatch
# Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
# +url_for+ is forwarded to the Routes module.
#
- # Examples:
- #
# url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080'
# # => 'http://somehost.org:8080/tasks/testing'
# url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true
diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
index edea6dab39..7dc3d0f97c 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
@@ -5,11 +5,8 @@ module ActionDispatch
module DomAssertions
# \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
#
- # ==== Examples
- #
# # assert that the referenced method generates the appropriate HTML string
# assert_dom_equal '<a href="http://www.example.com">Apples</a>', link_to("Apples", "http://www.example.com")
- #
def assert_dom_equal(expected, actual, message = "")
expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root
@@ -18,11 +15,8 @@ module ActionDispatch
# The negated form of +assert_dom_equivalent+.
#
- # ==== Examples
- #
# # assert that the referenced method does not generate the specified HTML string
# assert_dom_not_equal '<a href="http://www.example.com">Apples</a>', link_to("Oranges", "http://www.example.com")
- #
def assert_dom_not_equal(expected, actual, message = "")
expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 8f6fff5d32..3d121b6b9c 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -15,14 +15,11 @@ module ActionDispatch
# or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>.
# See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list.
#
- # ==== Examples
- #
# # assert that the response was a redirection
# assert_response :redirect
#
# # assert that the response code was status code 401 (unauthorized)
# assert_response 401
- #
def assert_response(type, message = nil)
message ||= "Expected response to be a <#{type}>, but was <#{@response.response_code}>"
@@ -42,8 +39,6 @@ module ActionDispatch
# This match can be partial, such that <tt>assert_redirected_to(:controller => "weblog")</tt> will also
# match the redirection of <tt>redirect_to(:controller => "weblog", :action => "show")</tt> and so on.
#
- # ==== Examples
- #
# # assert that the redirection was to the "index" action on the WeblogController
# assert_redirected_to :controller => "weblog", :action => "index"
#
@@ -55,7 +50,6 @@ module ActionDispatch
#
# # asserts that the redirection matches the regular expression
# assert_redirected_to %r(\Ahttp://example.org)
- #
def assert_redirected_to(options = {}, message=nil)
assert_response(:redirect, message)
return true if options === @response.location
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 1f4b905d18..567ca0c392 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -26,7 +26,6 @@ module ActionDispatch
#
# The +message+ parameter allows you to pass in an error message that is displayed upon failure.
#
- # ==== Examples
# # Check the default route (i.e., the index action)
# assert_recognizes({:controller => 'items', :action => 'index'}, 'items')
#
@@ -57,7 +56,6 @@ module ActionDispatch
#
# The +defaults+ parameter is unused.
#
- # ==== Examples
# # Asserts that the default action is generated for a route with no action
# assert_generates "/items", :controller => "items", :action => "index"
#
@@ -100,7 +98,6 @@ module ActionDispatch
# The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
# +message+ parameter allows you to specify a custom error message to display upon failure.
#
- # ==== Examples
# # Assert a basic route: a controller with the default action (index)
# assert_routing '/home', :controller => 'home', :action => 'index'
#
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index ea1ed20f3c..5f9c3bbf48 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -39,7 +39,6 @@ module ActionDispatch
# The selector may be a CSS selector expression (String), an expression
# with substitution values (Array) or an HTML::Selector object.
#
- # ==== Examples
# # Selects all div tags
# divs = css_select("div")
#
@@ -58,7 +57,6 @@ module ActionDispatch
# inputs = css_select(form, "input")
# ...
# end
- #
def css_select(*args)
# See assert_select to understand what's going on here.
arg = args.shift
@@ -340,7 +338,6 @@ module ActionDispatch
# The content of each element is un-encoded, and wrapped in the root
# element +encoded+. It then calls the block with all un-encoded elements.
#
- # ==== Examples
# # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix)
# assert_select "feed[xmlns='http://www.w3.org/2005/Atom']" do
# # Select each entry item and then the title item
@@ -401,8 +398,6 @@ module ActionDispatch
# You must enable deliveries for this assertion to work, use:
# ActionMailer::Base.perform_deliveries = true
#
- # ==== Examples
- #
# assert_select_email do
# assert_select "h1", "Email alert"
# end
@@ -413,7 +408,6 @@ module ActionDispatch
# # Work with items here...
# end
# end
- #
def assert_select_email(&block)
deliveries = ActionMailer::Base.deliveries
assert !deliveries.empty?, "No e-mail in delivery list"
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index 5c735e61b2..68f1347e7c 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -48,8 +48,6 @@ module ActionDispatch
# * if the condition is +true+, the value must not be +nil+.
# * if the condition is +false+ or +nil+, the value must be +nil+.
#
- # === Examples
- #
# # Assert that there is a "span" tag
# assert_tag :tag => "span"
#
@@ -104,7 +102,6 @@ module ActionDispatch
# Identical to +assert_tag+, but asserts that a matching tag does _not_
# exist. (See +assert_tag+ for a full discussion of the syntax.)
#
- # === Examples
# # Assert that there is not a "div" containing a "p"
# assert_no_tag :tag => "div", :descendant => { :tag => "p" }
#
diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb
index 083856b2ca..245849d706 100644
--- a/actionpack/lib/action_view/context.rb
+++ b/actionpack/lib/action_view/context.rb
@@ -5,7 +5,7 @@ module ActionView
# = Action View Context
#
- # Action View contexts are supplied to Action Controller to render template.
+ # Action View contexts are supplied to Action Controller to render a template.
# The default Action View context is ActionView::Base.
#
# In order to work with ActionController, a Context must just include this module.
@@ -25,7 +25,7 @@ module ActionView
end
# Encapsulates the interaction with the view flow so it
- # returns the correct buffer on yield. This is usually
+ # returns the correct buffer on +yield+. This is usually
# overwriten by helpers to add more behavior.
# :api: plugin
def _layout_for(name=nil)
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 8368ebfbca..a7a4ce21ff 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -252,7 +252,6 @@ module ActionView
# The following call would generate such a tag:
#
# <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %>
- #
def favicon_link_tag(source='favicon.ico', options={})
tag('link', {
:rel => 'shortcut icon',
@@ -290,7 +289,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by +video_tag+ to build the video path.
#
- # ==== Examples
# video_path("hd") # => /videos/hd
# video_path("hd.avi") # => /videos/hd.avi
# video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
@@ -312,7 +310,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by +audio_tag+ to build the audio path.
#
- # ==== Examples
# audio_path("horse") # => /audios/horse
# audio_path("horse.wav") # => /audios/horse.wav
# audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
@@ -323,7 +320,7 @@ module ActionView
end
alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
- # Computes the full URL to a audio asset in the public audios directory.
+ # Computes the full URL to an audio asset in the public audios directory.
# This will use +audio_path+ internally, so most of their behaviors will be the same.
def audio_url(source)
URI.join(current_host, path_to_audio(source)).to_s
@@ -333,7 +330,6 @@ module ActionView
# Computes the path to a font asset.
# Full paths from the document root will be passed through.
#
- # ==== Examples
# font_path("font") # => /assets/font
# font_path("font.ttf") # => /assets/font.ttf
# font_path("dir/font.ttf") # => /assets/dir/font.ttf
@@ -364,7 +360,6 @@ module ActionView
# width="30" and height="45". <tt>:size</tt> will be ignored if the
# value is not in the correct format.
#
- # ==== Examples
# image_tag("icon") # =>
# <img src="/assets/icon" alt="Icon" />
# image_tag("icon.png") # =>
@@ -413,7 +408,6 @@ module ActionView
# width="30" and height="45". <tt>:size</tt> will be ignored if the
# value is not in the correct format.
#
- # ==== Examples
# video_tag("trailer") # =>
# <video src="/videos/trailer" />
# video_tag("trailer.ogg") # =>
@@ -446,15 +440,14 @@ module ActionView
# The +source+ can be full path or file that exists in
# your public audios directory.
#
- # ==== Examples
- # audio_tag("sound") # =>
- # <audio src="/audios/sound" />
- # audio_tag("sound.wav") # =>
- # <audio src="/audios/sound.wav" />
- # audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
- # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
- # audio_tag("sound.wav", "sound.mid") # =>
- # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
+ # audio_tag("sound") # =>
+ # <audio src="/audios/sound" />
+ # audio_tag("sound.wav") # =>
+ # <audio src="/audios/sound.wav" />
+ # audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
+ # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
+ # audio_tag("sound.wav", "sound.mid") # =>
+ # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
def audio_tag(*sources)
multiple_sources_tag('audio', sources)
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
index 7bff0c1149..4292d29f60 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
@@ -76,7 +76,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by javascript_include_tag to build the script path.
#
- # ==== Examples
# javascript_path "xmlhr" # => /javascripts/xmlhr.js
# javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
# javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
@@ -114,7 +113,6 @@ module ActionView
# You can modify the HTML attributes of the script tag by passing a hash as the
# last argument.
#
- # ==== Examples
# javascript_include_tag "xmlhr"
# # => <script src="/javascripts/xmlhr.js?1284139606"></script>
#
@@ -160,8 +158,6 @@ module ActionView
# <tt>config.perform_caching</tt> is set to true (which is the case by default for the Rails
# production environment, but not for the development environment).
#
- # ==== Examples
- #
# # assuming config.perform_caching is false
# javascript_include_tag :all, :cache => true
# # => <script src="/javascripts/jquery.js?1284139606"></script>
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
index 4bcb8b9718..57b0627225 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -54,7 +54,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by +stylesheet_link_tag+ to build the stylesheet path.
#
- # ==== Examples
# stylesheet_path "style" # => /stylesheets/style.css
# stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
# stylesheet_path "/dir/style.css" # => /dir/style.css
@@ -79,7 +78,6 @@ module ActionView
# to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
# apply to all media types.
#
- # ==== Examples
# stylesheet_link_tag "style" # =>
# <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
#
@@ -117,7 +115,6 @@ module ActionView
# is set to true (which is the case by default for the Rails production environment, but not for the development
# environment). Examples:
#
- # ==== Examples
# stylesheet_link_tag :all, :cache => true # when config.perform_caching is false =>
# <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" />
# <link href="/stylesheets/styleB.css" media="screen" rel="stylesheet" />
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index 850dd5f448..33799d7d71 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -10,7 +10,6 @@ module ActionView
#
# See ActionController::Caching::Fragments for usage instructions.
#
- # ==== Examples
# If you want to cache a navigation menu, you can do following:
#
# <% cache do %>
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index d9d6f90211..397738dd98 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -13,7 +13,6 @@ module ActionView
# The capture method allows you to extract part of a template into a
# variable. You can then use this variable anywhere in your templates or layout.
#
- # ==== Examples
# The capture method can be used in ERB templates...
#
# <% @greeting = capture do %>
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f0a593d2c1..659aacf6d7 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -64,7 +64,6 @@ module ActionView
# distance_of_time_in_words(from_time, to_time, :include_seconds => true) # => about 6 years
# distance_of_time_in_words(to_time, from_time, :include_seconds => true) # => about 6 years
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
- #
def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {})
if include_seconds_or_options.is_a?(Hash)
options = include_seconds_or_options
@@ -140,7 +139,6 @@ module ActionView
# Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
#
- # ==== Examples
# time_ago_in_words(3.minutes.from_now) # => 3 minutes
# time_ago_in_words(Time.now - 15.hours) # => about 15 hours
# time_ago_in_words(Time.now) # => less than a minute
@@ -148,7 +146,6 @@ module ActionView
#
# from_time = Time.now - 3.days - 14.minutes - 25.seconds
# time_ago_in_words(from_time) # => 3 days
- #
def time_ago_in_words(from_time, include_seconds_or_options = {})
distance_of_time_in_words(from_time, Time.now, include_seconds_or_options)
end
@@ -197,7 +194,6 @@ module ActionView
#
# NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
#
- # ==== Examples
# # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute.
# date_select("article", "written_on")
#
@@ -253,7 +249,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# # Creates a time select tag that, when POSTed, will be stored in the article variable in the sunrise attribute.
# time_select("article", "sunrise")
#
@@ -286,7 +281,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# # Generates a datetime select that, when POSTed, will be stored in the article variable in the written_on
# # attribute.
# datetime_select("article", "written_on")
@@ -325,7 +319,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# my_date_time = Time.now + 4.days
#
# # Generates a datetime select that defaults to the datetime in my_date_time (four days after today).
@@ -362,7 +355,6 @@ module ActionView
# select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours
# select_datetime(my_date_time, :prompt => true) # generic prompts for all
- #
def select_datetime(datetime = Time.current, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_datetime
end
@@ -374,7 +366,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# my_date = Time.now + 6.days
#
# # Generates a date select that defaults to the date in my_date (six days after today).
@@ -403,7 +394,6 @@ module ActionView
# select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours
# select_date(my_date, :prompt => true) # generic prompts for all
- #
def select_date(date = Date.current, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_date
end
@@ -414,7 +404,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds
#
# # Generates a time select that defaults to the time in my_time.
@@ -442,7 +431,6 @@ module ActionView
# select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours
# select_time(my_time, :prompt => true) # generic prompts for all
- #
def select_time(datetime = Time.current, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_time
end
@@ -451,7 +439,6 @@ module ActionView
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
#
- # ==== Examples
# my_time = Time.now + 16.minutes
#
# # Generates a select field for seconds that defaults to the seconds for the time in my_time.
@@ -467,7 +454,6 @@ module ActionView
# # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_second(14, :prompt => 'Choose seconds')
- #
def select_second(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_second
end
@@ -477,7 +463,6 @@ module ActionView
# selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
#
- # ==== Examples
# my_time = Time.now + 6.hours
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time.
@@ -493,7 +478,6 @@ module ActionView
# # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_minute(14, :prompt => 'Choose minutes')
- #
def select_minute(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_minute
end
@@ -502,7 +486,6 @@ module ActionView
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
# Override the field name using the <tt>:field_name</tt> option, 'hour' by default.
#
- # ==== Examples
# my_time = Time.now + 6.hours
#
# # Generates a select field for hours that defaults to the hour for the time in my_time.
@@ -521,7 +504,6 @@ module ActionView
#
# # Generate a select field for hours in the AM/PM format
# select_hour(my_time, :ampm => true)
- #
def select_hour(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_hour
end
@@ -531,7 +513,6 @@ module ActionView
# If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
#
- # ==== Examples
# my_date = Time.now + 2.days
#
# # Generates a select field for days that defaults to the day for the date in my_date.
@@ -550,7 +531,6 @@ module ActionView
# # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_day(5, :prompt => 'Choose day')
- #
def select_day(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_day
end
@@ -565,7 +545,6 @@ module ActionView
# If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
#
- # ==== Examples
# # Generates a select field for months that defaults to the current month that
# # will use keys like "January", "March".
# select_month(Date.today)
@@ -597,7 +576,6 @@ module ActionView
# # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_month(14, :prompt => 'Choose month')
- #
def select_month(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_month
end
@@ -608,7 +586,6 @@ module ActionView
# greater than <tt>:end_year</tt>. The <tt>date</tt> can also be substituted for a year given as a number.
# Override the field name using the <tt>:field_name</tt> option, 'year' by default.
#
- # ==== Examples
# # Generates a select field for years that defaults to the current year that
# # has ascending year values.
# select_year(Date.today, :start_year => 1992, :end_year => 2007)
@@ -628,14 +605,12 @@ module ActionView
# # Generates a select field for years with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_year(14, :prompt => 'Choose year')
- #
def select_year(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_year
end
# Returns an html time tag for the given date or time.
#
- # ==== Examples
# time_tag Date.today # =>
# <time datetime="2010-11-04">November 04, 2010</time>
# time_tag Time.now # =>
@@ -649,7 +624,6 @@ module ActionView
# <span>Right now</span>
# <% end %>
# # => <time datetime="2010-11-04T17:55:45+01:00"><span>Right now</span></time>
- #
def time_tag(date_or_time, *args, &block)
options = args.extract_options!
format = options.delete(:format) || :long
diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb
index c0cc7d347c..878a8734a4 100644
--- a/actionpack/lib/action_view/helpers/debug_helper.rb
+++ b/actionpack/lib/action_view/helpers/debug_helper.rb
@@ -8,8 +8,6 @@ module ActionView
# If the object cannot be converted to YAML using +to_yaml+, +inspect+ will be called instead.
# Useful for inspecting an object at the time of rendering.
#
- # ==== Example
- #
# @user = User.new({ :username => 'testing', :password => 'xyz', :age => 42}) %>
# debug(@user)
# # =>
@@ -25,7 +23,6 @@ module ActionView
#
# new_record: true
# </pre>
-
def debug(object)
begin
Marshal::dump(object)
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 0fbd6ac41b..cc1f133196 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -900,7 +900,6 @@ module ActionView
# In that case it is preferable to either use +check_box_tag+ or to use
# hashes instead of arrays.
#
- # ==== Examples
# # Let's say that @post.validated? is 1:
# check_box("post", "validated")
# # => <input name="post[validated]" type="hidden" value="0" />
@@ -926,7 +925,6 @@ module ActionView
# To force the radio button to be checked pass <tt>:checked => true</tt> in the
# +options+ hash. You may pass HTML options there as well.
#
- # ==== Examples
# # Let's say that @post.category returns "rails":
# radio_button("post", "category", "rails")
# radio_button("post", "category", "java")
@@ -945,8 +943,6 @@ module ActionView
# assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by
# some browsers.
#
- # ==== Examples
- #
# search_field(:user, :name)
# # => <input id="user_name" name="user[name]" type="search" />
# search_field(:user, :name, :autosave => false)
@@ -962,7 +958,6 @@ module ActionView
# # => <input autosave="false" id="user_name" incremental="true" name="user[name]" onsearch="true" type="search" />
# search_field(:user, :name, :autosave => true, :onsearch => true)
# # => <input autosave="com.example.www" id="user_name" incremental="true" name="user[name]" onsearch="true" results="10" type="search" />
- #
def search_field(object_name, method, options = {})
Tags::SearchField.new(object_name, method, self, options).render
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index cafcd93f58..52eb1aa447 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -264,7 +264,6 @@ module ActionView
# Finally, this method supports a <tt>:default</tt> option, which selects
# a default ActiveSupport::TimeZone if the object's time zone is +nil+.
#
- # Examples:
# time_zone_select( "user", "time_zone", nil, :include_blank => true)
#
# time_zone_select( "user", "time_zone", nil, :default => "Pacific Time (US & Canada)" )
@@ -461,8 +460,11 @@ module ActionView
# * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
# which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
# as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
- # * +prompt+ - set to true or a prompt string. When the select element doesn't have a value yet, this
+ #
+ # Options:
+ # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this
# prepends an option with a generic prompt - "Please select" - or the given prompt string.
+ # * <tt>:divider</tt> - the divider for the options groups.
#
# Sample usage (Array):
# grouped_options = [
@@ -491,15 +493,51 @@ module ActionView
# <option value="Canada">Canada</option>
# </optgroup>
#
+ # Sample usage (divider):
+ # grouped_options = [
+ # [['United States','US'], 'Canada'],
+ # ['Denmark','Germany','France']
+ # ]
+ # grouped_options_for_select(grouped_options, divider: '---------')
+ #
+ # Possible output:
+ # <optgroup label="---------">
+ # <option value="Denmark">Denmark</option>
+ # <option value="Germany">Germany</option>
+ # <option value="France">France</option>
+ # </optgroup>
+ # <optgroup label="---------">
+ # <option value="US">United States</option>
+ # <option value="Canada">Canada</option>
+ # </optgroup>
+ #
# <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
# wrap the output in an appropriate <tt><select></tt> tag.
- def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
+ def grouped_options_for_select(*args)
+ grouped_options = args.shift
+ options = args.extract_options!
+ selected_key = args.shift
+ if prompt = args.shift
+ ActiveSupport::Deprecation.warn 'Passing the prompt to grouped_options_for_select as an argument is deprecated. Please pass it in an options hash.'
+ else
+ prompt = options[:prompt]
+ divider = options[:divider]
+ end
+
body = "".html_safe
- body.safe_concat content_tag(:option, prompt, :value => "") if prompt
+
+ if prompt
+ body.safe_concat content_tag(:option, prompt_text(prompt), :value => "")
+ end
grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
- grouped_options.each do |label, container|
+ grouped_options.each do |container|
+ if divider
+ label, container = divider, container
+ else
+ label, container = container
+ end
body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), :label => label)
end
@@ -715,6 +753,10 @@ module ActionView
def value_for_collection(item, value)
value.respond_to?(:call) ? value.call(item) : item.send(value)
end
+
+ def prompt_text(prompt)
+ prompt = prompt.kind_of?(String) ? prompt : I18n.translate('helpers.select.prompt', :default => 'Please select')
+ end
end
class FormBuilder
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 248cc2f6a3..9e5c66f4a9 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -386,9 +386,6 @@ module ActionView
# drivers will provide a prompt with the question specified. If the user accepts,
# the form is processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
- # disabled version of the submit button when the form is submitted. This feature is
- # provided by the unobtrusive JavaScript driver.
# * Any other key creates standard HTML options for the tag.
#
# ==== Examples
@@ -401,14 +398,14 @@ module ActionView
# submit_tag "Save edits", :disabled => true
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
#
- # submit_tag "Complete sale", :disable_with => "Please wait..."
+ # submit_tag "Complete sale", :data => { :disable_with => "Please wait..." }
# # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
#
# submit_tag nil, :class => "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
- # submit_tag "Edit", :disable_with => "Editing...", :class => "edit_button"
- # # => <input class="edit_button" data-disable-with="Editing..." name="commit" type="submit" value="Edit" />
+ # submit_tag "Edit", :class => "edit_button"
+ # # => <input class="edit_button" name="commit" type="submit" value="Edit" />
#
# submit_tag "Save", :confirm => "Are you sure?"
# # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
@@ -416,10 +413,6 @@ module ActionView
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
- if disable_with = options.delete("disable_with")
- options["data-disable-with"] = disable_with
- end
-
if confirm = options.delete("confirm")
options["data-confirm"] = confirm
end
@@ -441,10 +434,6 @@ module ActionView
# processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to
# use this input.
- # * <tt>:disable_with</tt> - Value of this parameter will be
- # used as the value for a disabled version of the submit
- # button when the form is submitted. This feature is provided
- # by the unobtrusive JavaScript driver.
# * Any other key creates standard HTML options for the tag.
#
# ==== Examples
@@ -458,18 +447,11 @@ module ActionView
# # <strong>Ask me!</strong>
# # </button>
#
- # button_tag "Checkout", :disable_with => "Please wait..."
- # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
- #
def button_tag(content_or_options = nil, options = nil, &block)
options = content_or_options if block_given? && content_or_options.is_a?(Hash)
options ||= {}
options = options.stringify_keys
- if disable_with = options.delete("disable_with")
- options["data-disable-with"] = disable_with
- end
-
if confirm = options.delete("confirm")
options["data-confirm"] = confirm
end
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index 7768c8c151..a727b910e5 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -69,8 +69,6 @@ module ActionView
# html-scanner tokenizer and so its HTML parsing ability is limited by
# that of html-scanner.
#
- # ==== Examples
- #
# strip_tags("Strip <i>these</i> tags!")
# # => Strip these tags!
#
@@ -85,7 +83,6 @@ module ActionView
# Strips all link tags from +text+ leaving just the link text.
#
- # ==== Examples
# strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>')
# # => Ruby on Rails
#
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index f7afa48256..d5cd60e8a1 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -103,7 +103,6 @@ module ActionView
# otherwise be recognized as markup. CDATA sections begin with the string
# <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>.
#
- # ==== Examples
# cdata_section("<hello world>")
# # => <![CDATA[<hello world>]]>
#
@@ -119,7 +118,6 @@ module ActionView
# Returns an escaped version of +html+ without affecting existing escaped entities.
#
- # ==== Examples
# escape_once("1 < 2 &amp; 3")
# # => "1 &lt; 2 &amp; 3"
#
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index 380ebe4b65..e077cd5b3c 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -140,8 +140,7 @@ module ActionView
option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\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 = content_tag('option', prompt, :value => '') + "\n" + option_tags
+ option_tags = content_tag('option', prompt_text(options[:prompt]), :value => '') + "\n" + option_tags
end
option_tags
end
diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb
index bb968e9f39..0e79609d52 100644
--- a/actionpack/lib/action_view/helpers/tags/date_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_field.rb
@@ -5,7 +5,6 @@ module ActionView
def render
options = @options.stringify_keys
options["value"] = @options.fetch("value") { value(object).try(:to_date) }
- options["size"] = nil
@options = options
super
end
diff --git a/actionpack/lib/action_view/helpers/tags/file_field.rb b/actionpack/lib/action_view/helpers/tags/file_field.rb
index 56442e1c14..59f2ff71b4 100644
--- a/actionpack/lib/action_view/helpers/tags/file_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/file_field.rb
@@ -2,10 +2,6 @@ module ActionView
module Helpers
module Tags
class FileField < TextField #:nodoc:
- def render
- @options.update(:size => nil)
- super
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/hidden_field.rb b/actionpack/lib/action_view/helpers/tags/hidden_field.rb
index ea86596e0b..a8d13dc1b1 100644
--- a/actionpack/lib/action_view/helpers/tags/hidden_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/hidden_field.rb
@@ -2,10 +2,6 @@ module ActionView
module Helpers
module Tags
class HiddenField < TextField #:nodoc:
- def render
- @options.update(:size => nil)
- super
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/number_field.rb b/actionpack/lib/action_view/helpers/tags/number_field.rb
index e89fdbec46..9cd04434f0 100644
--- a/actionpack/lib/action_view/helpers/tags/number_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/number_field.rb
@@ -4,7 +4,6 @@ module ActionView
class NumberField < TextField #:nodoc:
def render
options = @options.stringify_keys
- options['size'] ||= nil
if range = options.delete("in") || options.delete("within")
options.update("min" => range.min, "max" => range.max)
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 698f4434ba..67117077dc 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -37,7 +37,6 @@ module ActionView
# do not operate as expected in an eRuby code block. If you absolutely must
# output text within a non-output code block (i.e., <% %>), you can use the concat method.
#
- # ==== Examples
# <%
# concat "hello"
# # is the equivalent of <%= "hello" %>
@@ -67,8 +66,6 @@ module ActionView
# used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags
# or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
#
- # ==== Examples
- #
# truncate("Once upon a time in a world far far away")
# # => "Once upon a time in a world..."
#
@@ -93,7 +90,6 @@ module ActionView
# as a single-quoted string with <tt>\1</tt> where the phrase is to be inserted (defaults to
# '<mark>\1</mark>')
#
- # ==== Examples
# highlight('You searched for: rails', 'rails')
# # => You searched for: <mark>rails</mark>
#
@@ -133,7 +129,6 @@ module ActionView
# then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The resulting string
# will be stripped in any case. If the +phrase+ isn't found, nil is returned.
#
- # ==== Examples
# excerpt('This is an example', 'an', :radius => 5)
# # => ...s is an exam...
#
@@ -181,7 +176,6 @@ module ActionView
# +plural+ is supplied, it will use that when count is > 1, otherwise
# it will use the Inflector to determine the plural form
#
- # ==== Examples
# pluralize(1, 'person')
# # => 1 person
#
@@ -201,23 +195,23 @@ module ActionView
# breaks on the first whitespace character that does not exceed +line_width+
# (which is 80 by default).
#
- # ==== Examples
- #
# word_wrap('Once upon a time')
# # => Once upon a time
#
# word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
- # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\n a successor to the throne turned out to be more trouble than anyone could have\n imagined...
+ # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined...
#
# word_wrap('Once upon a time', :line_width => 8)
- # # => Once upon\na time
+ # # => Once\nupon a\ntime
#
# word_wrap('Once upon a time', :line_width => 1)
# # => Once\nupon\na\ntime
#
# You can still use <tt>word_wrap</tt> with the old API that accepts the
# +line_width+ as its optional second parameter:
- # word_wrap('Once upon a time', 8) # => Once upon\na time
+ #
+ # word_wrap('Once upon a time', 8)
+ # # => Once\nupon a\ntime
def word_wrap(text, *args)
options = args.extract_options!
unless args.blank?
@@ -241,6 +235,7 @@ module ActionView
#
# ==== Options
# * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
+ # * <tt>:wrapper_tag</tt> - String representing the tag wrapper, defaults to <tt>"p"</tt>
#
# ==== Examples
# my_text = "Here is some basic text...\n...with a line break."
@@ -259,16 +254,17 @@ module ActionView
# simple_format("<span>I'm allowed!</span> It's true.", {}, :sanitize => false)
# # => "<p><span>I'm allowed!</span> It's true.</p>"
def simple_format(text, html_options={}, options={})
- text = '' if text.nil?
- text = text.dup
- start_tag = tag('p', html_options, true)
text = sanitize(text) unless options[:sanitize] == false
- text = text.to_str
- text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
- text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
- text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
- text.insert 0, start_tag
- text.html_safe.safe_concat("</p>")
+ wrapper_tag = options.fetch(:wrapper_tag, :p)
+ paragraphs = split_paragraphs(text)
+
+ if paragraphs.empty?
+ content_tag(wrapper_tag, nil, html_options)
+ else
+ paragraphs.map { |paragraph|
+ content_tag(wrapper_tag, paragraph, html_options, options[:sanitize])
+ }.join("\n\n").html_safe
+ end
end
# Creates a Cycle object whose _to_s_ method cycles through elements of an
@@ -280,7 +276,6 @@ module ActionView
# and passing the name of the cycle. The current cycle string can be obtained
# anytime using the current_cycle method.
#
- # ==== Examples
# # Alternate CSS classes for even and odd numbers...
# @items = [1,2,3,4]
# <table>
@@ -326,7 +321,6 @@ module ActionView
# for complex table highlighting or any other design need which requires
# the current cycle string in more than one place.
#
- # ==== Example
# # Alternate background colors
# @items = [1,2,3,4]
# <% @items.each do |item| %>
@@ -342,7 +336,6 @@ module ActionView
# Resets a cycle so that it starts from the first element the next time
# it is called. Pass in +name+ to reset a named cycle.
#
- # ==== Example
# # Alternate CSS classes for even and odd numbers...
# @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
# <table>
@@ -413,6 +406,14 @@ module ActionView
@_cycles = Hash.new unless defined?(@_cycles)
@_cycles[name] = cycle_object
end
+
+ def split_paragraphs(text)
+ return [] if text.blank?
+
+ text.to_str.gsub(/\r\n?/, "\n").split(/\n\n+/).map! do |t|
+ t.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') || t
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 802bf9d29f..7e69547dab 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -108,7 +108,7 @@ module ActionView
options
when nil, Hash
options ||= {}
- options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?)
+ options = { :only_path => options[:host].nil? }.merge!(options.symbolize_keys)
super
when :back
controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
@@ -322,11 +322,11 @@ module ActionView
#
#
# <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
- # :method => "delete", :remote => true, :disable_with => 'loading...') %>
+ # :method => "delete", :remote => true) %>
# # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
# # <div>
# # <input name='_method' value='delete' type='hidden' />
- # # <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
+ # # <input value='Destroy' type='submit' data-confirm='Are you sure?' />
# # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
# # </div>
# # </form>"
@@ -616,11 +616,9 @@ module ActionView
html_options = html_options.stringify_keys
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
- disable_with = html_options.delete("disable_with")
confirm = html_options.delete('confirm')
method = html_options.delete('method')
- html_options["data-disable-with"] = disable_with if disable_with
html_options["data-confirm"] = confirm if confirm
add_method_to_attributes!(html_options, method) if method
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 3cec816f1c..1a8f40037f 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -2324,6 +2324,55 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
end
end
+class TestDrawExternalFile < ActionDispatch::IntegrationTest
+ class ExternalController < ActionController::Base
+ def index
+ render :text => "external#index"
+ end
+ end
+
+ DRAW_PATH = Pathname.new(File.expand_path('../../fixtures/routes', __FILE__))
+
+ DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw_paths << DRAW_PATH
+ end
+
+ def app
+ DefaultScopeRoutes
+ end
+
+ def test_draw_external_file
+ DefaultScopeRoutes.draw do
+ scope :module => 'test_draw_external_file' do
+ draw :external
+ end
+ end
+
+ get '/external'
+ assert_equal "external#index", @response.body
+ end
+
+ def test_draw_nonexistent_file
+ exception = assert_raise ArgumentError do
+ DefaultScopeRoutes.draw do
+ draw :nonexistent
+ end
+ end
+ assert_match 'Your router tried to #draw the external file nonexistent.rb', exception.message
+ assert_match DRAW_PATH.to_s, exception.message
+ end
+
+ def test_draw_bogus_file
+ exception = assert_raise NoMethodError do
+ DefaultScopeRoutes.draw do
+ draw :bogus
+ end
+ end
+ assert_match "undefined method `wrong'", exception.message
+ assert_match 'test/fixtures/routes/bogus.rb:1', exception.backtrace.first
+ end
+end
+
class TestDefaultScope < ActionDispatch::IntegrationTest
module ::Blog
class PostsController < ActionController::Base
diff --git a/actionpack/test/fixtures/routes/bogus.rb b/actionpack/test/fixtures/routes/bogus.rb
new file mode 100644
index 0000000000..41fbf0cd64
--- /dev/null
+++ b/actionpack/test/fixtures/routes/bogus.rb
@@ -0,0 +1 @@
+wrong :route
diff --git a/actionpack/test/fixtures/routes/external.rb b/actionpack/test/fixtures/routes/external.rb
new file mode 100644
index 0000000000..d103c39f53
--- /dev/null
+++ b/actionpack/test/fixtures/routes/external.rb
@@ -0,0 +1 @@
+get '/external' => 'external#index'
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 2cff91adda..9b64bc9d81 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -296,10 +296,34 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
- def test_grouped_options_for_select_with_selected_and_prompt
+ def test_grouped_options_for_select_with_optional_divider
assert_dom_equal(
+ "<optgroup label=\"----------\"><option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"----------\"><option value=\"GB\">GB</option>\n<option value=\"Germany\">Germany</option></optgroup>",
+
+ grouped_options_for_select([['US',"Canada"] , ["GB", "Germany"]], divider: "----------")
+ )
+ end
+
+ def test_grouped_options_for_select_with_selected_and_prompt_deprecated
+ assert_deprecated 'Passing the prompt to grouped_options_for_select as an argument is deprecated. Please pass it in an options hash.' do
+ assert_dom_equal(
"<option value=\"\">Choose a product...</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option selected=\"selected\" value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", "Choose a product...")
+ )
+ end
+ end
+
+ def test_grouped_options_for_select_with_selected_and_prompt
+ assert_dom_equal(
+ "<option value=\"\">Choose a product...</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option selected=\"selected\" value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", prompt: "Choose a product...")
+ )
+ end
+
+ def test_grouped_options_for_select_with_selected_and_prompt_true
+ assert_dom_equal(
+ "<option value=\"\">Please select</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option selected=\"selected\" value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", prompt: true)
)
end
@@ -307,10 +331,18 @@ 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_deprecated
+ ActiveSupport::Deprecation.silence do
+ 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
+ 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>'))
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, prompt: '<Choose One>'))
end
def test_optgroups_with_with_options_with_hash
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 1e92ff99ff..7a645217b8 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -375,14 +375,7 @@ class FormTagHelperTest < ActionView::TestCase
def test_submit_tag
assert_dom_equal(
%(<input name='commit' data-disable-with="Saving..." onclick="alert('hello!')" type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')")
- )
- end
-
- def test_submit_tag_with_no_onclick_options
- assert_dom_equal(
- %(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...")
+ submit_tag("Save", 'data-disable-with' => "Saving...", :onclick => "alert('hello!')")
)
end
@@ -393,13 +386,6 @@ class FormTagHelperTest < ActionView::TestCase
)
end
- def test_submit_tag_with_confirmation_and_with_disable_with
- assert_dom_equal(
- %(<input name="commit" data-disable-with="Saving..." data-confirm="Are you sure?" type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?")
- )
- end
-
def test_button_tag
assert_dom_equal(
%(<button name="button" type="submit">Button</button>),
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index 5865b7f23c..e5cb273518 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -46,6 +46,14 @@ class TextHelperTest < ActionView::TestCase
assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :sanitize => false)
end
+ def test_simple_format_with_custom_wrapper
+ assert_equal "<div></div>", simple_format(nil, {}, :wrapper_tag => "div")
+ end
+
+ def test_simple_format_with_custom_wrapper_and_multi_line_breaks
+ assert_equal "<div>We want to put a wrapper...</div>\n\n<div>...right there.</div>", simple_format("We want to put a wrapper...\n\n...right there.", {}, :wrapper_tag => "div")
+ end
+
def test_simple_format_should_not_change_the_text_passed
text = "<b>Ok</b><script>code!</script>"
text_clone = text.dup
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index eaa8bdbd26..fb5b35bac6 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -97,7 +97,7 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_button_to_with_javascript_disable_with
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :disable_with => "Greeting...")
+ button_to("Hello", "http://www.example.com", 'data-disable-with' => "Greeting...")
)
end
@@ -112,20 +112,6 @@ class UrlHelperTest < ActiveSupport::TestCase
)
end
- def test_button_to_with_remote_and_javascript_disable_with
- assert_dom_equal(
- "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :remote => true, :disable_with => "Greeting...")
- )
- end
-
- def test_button_to_with_remote_and_javascript_confirm_and_javascript_disable_with
- assert_dom_equal(
- "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-disable-with=\"Greeting...\" data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?", :disable_with => "Greeting...")
- )
- end
-
def test_button_to_with_remote_false
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>",
diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc
index 0c7089598c..b4565b5881 100644
--- a/activemodel/README.rdoc
+++ b/activemodel/README.rdoc
@@ -41,7 +41,7 @@ behavior out of the box:
include ActiveModel::AttributeMethods
attribute_method_prefix 'clear_'
- define_attribute_methods [:name, :age]
+ define_attribute_methods :name, :age
attr_accessor :name, :age
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index 24575438c0..99918fdb96 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -28,7 +28,7 @@ module ActiveModel
# attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
# attribute_method_suffix '_contrived?'
# attribute_method_prefix 'clear_'
- # define_attribute_methods ['name']
+ # define_attribute_methods 'name'
#
# attr_accessor :name
#
@@ -86,7 +86,7 @@ module ActiveModel
# include ActiveModel::AttributeMethods
# attr_accessor :name
# attribute_method_prefix 'clear_'
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# private
#
@@ -124,7 +124,7 @@ module ActiveModel
# include ActiveModel::AttributeMethods
# attr_accessor :name
# attribute_method_suffix '_short?'
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# private
#
@@ -162,7 +162,7 @@ module ActiveModel
# include ActiveModel::AttributeMethods
# attr_accessor :name
# attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# private
#
@@ -216,7 +216,7 @@ module ActiveModel
# # Call to define_attribute_methods must appear after the
# # attribute_method_prefix, attribute_method_suffix or
# # attribute_method_affix declares.
- # define_attribute_methods [:name, :age, :address]
+ # define_attribute_methods :name, :age, :address
#
# private
#
@@ -224,8 +224,8 @@ module ActiveModel
# ...
# end
# end
- def define_attribute_methods(attr_names)
- attr_names.each { |attr_name| define_attribute_method(attr_name) }
+ def define_attribute_methods(*attr_names)
+ attr_names.flatten.each { |attr_name| define_attribute_method(attr_name) }
end
def define_attribute_method(attr_name)
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 3d35b5bb6f..3f2fd12db7 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -30,7 +30,7 @@ module ActiveModel
#
# include ActiveModel::Dirty
#
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# def name
# @name
diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb
index 5e5405fe27..893fbf92c3 100644
--- a/activemodel/lib/active_model/mass_assignment_security.rb
+++ b/activemodel/lib/active_model/mass_assignment_security.rb
@@ -229,7 +229,7 @@ module ActiveModel
protected
def sanitize_for_mass_assignment(attributes, role = nil)
- _mass_assignment_sanitizer.sanitize(attributes, mass_assignment_authorizer(role))
+ _mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(role))
end
def mass_assignment_authorizer(role)
diff --git a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb
index 4491e07a72..44ce5a489d 100644
--- a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb
+++ b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb
@@ -2,18 +2,18 @@ module ActiveModel
module MassAssignmentSecurity
class Sanitizer
# Returns all attributes not denied by the authorizer.
- def sanitize(attributes, authorizer)
+ def sanitize(klass, attributes, authorizer)
rejected = []
sanitized_attributes = attributes.reject do |key, value|
rejected << key if authorizer.deny?(key)
end
- process_removed_attributes(rejected) unless rejected.empty?
+ process_removed_attributes(klass, rejected) unless rejected.empty?
sanitized_attributes
end
protected
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
raise NotImplementedError, "#process_removed_attributes(attrs) suppose to be overwritten"
end
end
@@ -32,8 +32,21 @@ module ActiveModel
@target.respond_to?(:logger) && @target.logger
end
- def process_removed_attributes(attrs)
- logger.warn "Can't mass-assign protected attributes: #{attrs.join(', ')}" if logger?
+ def backtrace
+ if defined? Rails
+ Rails.backtrace_cleaner.clean(caller)
+ else
+ caller
+ end
+ end
+
+ def process_removed_attributes(klass, attrs)
+ if logger?
+ logger.warn do
+ "WARNING: Can't mass-assign protected attributes for #{klass.name}: #{attrs.join(', ')}\n" +
+ backtrace.map { |trace| "\t#{trace}" }.join("\n")
+ end
+ end
end
end
@@ -42,9 +55,9 @@ module ActiveModel
super()
end
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
return if (attrs - insensitive_attributes).empty?
- raise ActiveModel::MassAssignmentSecurity::Error.new(attrs)
+ raise ActiveModel::MassAssignmentSecurity::Error.new(klass, attrs)
end
def insensitive_attributes
@@ -53,8 +66,8 @@ module ActiveModel
end
class Error < StandardError
- def initialize(attrs)
- super("Can't mass-assign protected attributes: #{attrs.join(', ')}")
+ def initialize(klass, attrs)
+ super("Can't mass-assign protected attributes for #{klass.name}: #{attrs.join(', ')}")
end
end
end
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index 00cd05b7ef..3751e4a741 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -64,7 +64,7 @@ module ActiveModel
# person.to_json # => "{\"name\":\"Bob\"}"
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
#
- # Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and <tt>include</tt>.
+ # Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and <tt>:include</tt>.
# The following are all valid examples:
#
# person.serializable_hash(:only => 'name')
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index 3ed72bae3b..611e9ffd55 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -178,6 +178,12 @@ module ActiveModel
end
end
+ # Clean the +Errors+ object if instance is duped
+ def initialize_dup(other) # :nodoc:
+ @errors = nil
+ super
+ end
+
# Returns the +Errors+ object that holds all information about attribute error messages.
def errors
@errors ||= Errors.new(self)
diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb
index e628c6f306..38abd0c1fa 100644
--- a/activemodel/lib/active_model/validations/acceptance.rb
+++ b/activemodel/lib/active_model/validations/acceptance.rb
@@ -23,7 +23,7 @@ module ActiveModel
module HelperMethods
# Encapsulates the pattern of wanting to validate the acceptance of a
- # terms of service check box (or similar agreement). Example:
+ # terms of service check box (or similar agreement).
#
# class Person < ActiveRecord::Base
# validates_acceptance_of :terms_of_service
@@ -59,7 +59,7 @@ module ActiveModel
# The method, proc or string should return or evaluate to a true or
# false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_acceptance_of(*attr_names)
validates_with AcceptanceValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index 69ab74734d..ede34d15bc 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -19,7 +19,7 @@ module ActiveModel
module HelperMethods
# Encapsulates the pattern of wanting to validate a password or email
- # address field with a confirmation. For example:
+ # address field with a confirmation.
#
# Model:
# class Person < ActiveRecord::Base
@@ -60,7 +60,7 @@ module ActiveModel
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_confirmation_of(*attr_names)
validates_with ConfirmationValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index 5fedb1978b..4f09679541 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -15,34 +15,42 @@ module ActiveModel
end
module HelperMethods
- # Validates that the value of the specified attribute is not in a particular enumerable object.
+ # Validates that the value of the specified attribute is not in a
+ # particular enumerable object.
#
# class Person < ActiveRecord::Base
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
- # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] }, :message => "should not be the same as your username or first name"
+ # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] },
+ # :message => "should not be the same as your username or first name"
# end
#
# Configuration options:
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
- # This can be supplied as a proc or lambda which returns an enumerable. If the enumerable
- # is a range the test is performed with <tt>Range#cover?</tt>
- # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be
+ # part of. This can be supplied as a proc or lambda which returns an
+ # enumerable. If the enumerable is a range the test is performed with
+ # <tt>Range#cover?</tt> (backported in Active Support for 1.8), otherwise
+ # with <tt>include?</tt>.
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
+ # reserved").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
+ # is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank(default is +false+).
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_exclusion_of(*attr_names)
validates_with ExclusionValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index d3faa8c6a6..dd87e312f9 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -42,50 +42,62 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is of the correct form, going by the regular expression provided.
- # You can require that the attribute matches the regular expression:
+ # Validates whether the value of the specified attribute is of the correct
+ # form, going by the regular expression provided.You can require that the
+ # attribute matches the regular expression:
#
# class Person < ActiveRecord::Base
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
# end
#
- # Alternatively, you can require that the specified attribute does _not_ match the regular expression:
+ # Alternatively, you can require that the specified attribute does _not_
+ # match the regular expression:
#
# class Person < ActiveRecord::Base
# validates_format_of :email, :without => /NOSPAM/
# end
#
- # You can also provide a proc or lambda which will determine the regular expression that will be used to validate the attribute
+ # You can also provide a proc or lambda which will determine the regular
+ # expression that will be used to validate the attribute.
#
# class Person < ActiveRecord::Base
# # Admin can have number as a first letter in their screen name
- # validates_format_of :screen_name, :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
+ # validates_format_of :screen_name,
+ # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
# end
#
- # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
+ # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
#
- # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression
- # or a proc or lambda, or else an exception will be raised.
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
+ # In addition, both must be a regular expression or a proc or lambda, or
+ # else an exception will be raised.
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
- # * <tt>:with</tt> - Regular expression that if the attribute matches will result in a successful validation.
- # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
- # * <tt>:without</tt> - Regular expression that if the attribute does not match will result in a successful validation.
- # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
+ # is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank (default is +false+).
+ # * <tt>:with</tt> - Regular expression that if the attribute matches will
+ # result in a successful validation. This can be provided as a proc or lambda
+ # returning regular expression which will be called at runtime.
+ # * <tt>:without</tt> - Regular expression that if the attribute does not match
+ # will result in a successful validation. This can be provided as a proc or
+ # lambda returning regular expression which will be called at runtime.
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_format_of(*attr_names)
validates_with FormatValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index 15ae7b1959..ffdbed0fc1 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -15,7 +15,8 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is available in a particular enumerable object.
+ # Validates whether the value of the specified attribute is available in a
+ # particular enumerable object.
#
# class Person < ActiveRecord::Base
# validates_inclusion_of :gender, :in => %w( m f )
@@ -29,20 +30,25 @@ module ActiveModel
# supplied as a proc or lambda which returns an enumerable. If the enumerable
# is a range the test is performed with <tt>Range#cover?</tt>
# (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is not
+ # included in the list").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
+ # is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank (default is +false+).
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_inclusion_of(*attr_names)
validates_with InclusionValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 037f8c2db8..64b4fe2d74 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -72,35 +72,46 @@ module ActiveModel
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
# validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words.", :tokenizer => lambda { |str| str.scan(/\w+/) }
+ # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words.",
+ # :tokenizer => lambda { |str| str.scan(/\w+/) }
# end
#
# Configuration options:
# * <tt>:minimum</tt> - The minimum size of the attribute.
# * <tt>:maximum</tt> - The maximum size of the attribute.
# * <tt>:is</tt> - The exact size of the attribute.
- # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of the
+ # attribute.
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
- # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
- # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
- # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
- # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the
+ # maximum (default is: "is too long (maximum is %{count} characters)").
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the
+ # minimum (default is: "is too short (min is %{count} characters)").
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method
+ # and the attribute is the wrong size (default is: "is the wrong length
+ # (should be %{count} characters)").
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
+ # <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
+ # <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
- # count words as in above example.)
- # Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
+ # proc or string should return or evaluate to a true or false value.
+ # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
+ # (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to count words
+ # as in above example). Defaults to <tt>lambda{ |value| value.split(//) }</tt>
+ # which counts individual characters.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_length_of(*attr_names)
validates_with LengthValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index bb9f9679fc..40b5b92b84 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -79,9 +79,10 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is numeric by trying to convert it to
- # a float with Kernel.Float (if <tt>only_integer</tt> is false) or applying it to the regular expression
- # <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> is set to true).
+ # Validates whether the value of the specified attribute is numeric by trying
+ # to convert it to a float with Kernel.Float (if <tt>only_integer</tt> is false)
+ # or applying it to the regular expression <tt>/\A[\+\-]?\d+\Z/</tt> (if
+ # <tt>only_integer</tt> is set to true).
#
# class Person < ActiveRecord::Base
# validates_numericality_of :value, :on => :create
@@ -92,37 +93,50 @@ module ActiveModel
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
- # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+.
- # * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value.
- # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value.
+ # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer,
+ # e.g. an integral value (default is +false+).
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
+ # +false+). Notice that for fixnum and float columns empty strings are
+ # converted to +nil+.
+ # * <tt>:greater_than</tt> - Specifies the value must be greater than the
+ # supplied value.
+ # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater
+ # than or equal the supplied value.
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
- # * <tt>:less_than</tt> - Specifies the value must be less than the supplied value.
- # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value.
- # * <tt>:other_than</tt> - Specifies the value must be other than the supplied value.
+ # * <tt>:less_than</tt> - Specifies the value must be less than the supplied
+ # value.
+ # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or
+ # equal the supplied value.
+ # * <tt>:other_than</tt> - Specifies the value must be other than the supplied
+ # value.
# * <tt>:odd</tt> - Specifies the value must be an odd number.
# * <tt>:even</tt> - Specifies the value must be an even number.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
+ #
+ # The following checks can also be supplied with a proc or a symbol which
+ # corresponds to a method:
#
- # The following checks can also be supplied with a proc or a symbol which corresponds to a method:
# * <tt>:greater_than</tt>
# * <tt>:greater_than_or_equal_to</tt>
# * <tt>:equal_to</tt>
# * <tt>:less_than</tt>
# * <tt>:less_than_or_equal_to</tt>
#
+ # For example:
+ #
# class Person < ActiveRecord::Base
# validates_numericality_of :width, :less_than => Proc.new { |person| person.height }
# validates_numericality_of :width, :greater_than => :minimum_weight
# end
- #
def validates_numericality_of(*attr_names)
validates_with NumericalityValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb
index 9a643a6f5c..018ef1e733 100644
--- a/activemodel/lib/active_model/validations/presence.rb
+++ b/activemodel/lib/active_model/validations/presence.rb
@@ -11,7 +11,8 @@ module ActiveModel
end
module HelperMethods
- # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:
+ # Validates that the specified attributes are not blank (as defined by
+ # Object#blank?). Happens by default on save.
#
# class Person < ActiveRecord::Base
# validates_presence_of :first_name
@@ -19,25 +20,28 @@ module ActiveModel
#
# The first_name attribute must be in the object and it cannot be blank.
#
- # If you want to validate the presence of a boolean field (where the real values are true and false),
- # you will want to use <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
+ # If you want to validate the presence of a boolean field (where the real values
+ # are true and false), you will want to use
+ # <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
#
- # This is due to the way Object#blank? handles boolean values: <tt>false.blank? # => true</tt>.
+ # This is due to the way Object#blank? handles boolean values:
+ # <tt>false.blank? # => true</tt>.
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
+ # proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
- #
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_presence_of(*attr_names)
validates_with PresenceValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb
index 991c5f7b82..66cc9daa2c 100644
--- a/activemodel/lib/active_model/validations/with.rb
+++ b/activemodel/lib/active_model/validations/with.rb
@@ -62,8 +62,8 @@ module ActiveModel
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
# The method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
-
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
+ #
# If you pass any additional configuration options, they will be passed
# to the class and available as <tt>options</tt>:
#
@@ -77,7 +77,6 @@ module ActiveModel
# options[:my_custom_key] # => "my custom value"
# end
# end
- #
def validates_with(*args, &block)
options = args.extract_options!
args.each do |klass|
@@ -128,12 +127,11 @@ module ActiveModel
# Standard configuration options (:on, :if and :unless), which are
# available on the class version of +validates_with+, should instead be
# placed on the +validates+ method as these are applied and tested
- # in the callback
+ # in the callback.
#
# If you pass any additional configuration options, they will be passed
# to the class and available as +options+, please refer to the
- # class version of this method for more information
- #
+ # class version of this method for more information.
def validates_with(*args, &block)
options = args.extract_options!
args.each do |klass|
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 34298d31c2..a9db29ee21 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -10,7 +10,7 @@ class ModelWithAttributes
end
def attributes
- { :foo => 'value of foo' }
+ { :foo => 'value of foo', :baz => 'value of baz' }
end
private
@@ -127,29 +127,36 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send('a?b')
end
+ test '#define_attribute_methods works passing multiple arguments' do
+ ModelWithAttributes.define_attribute_methods(:foo, :baz)
+
+ assert_equal "value of foo", ModelWithAttributes.new.foo
+ assert_equal "value of baz", ModelWithAttributes.new.baz
+ end
+
test '#define_attribute_methods generates attribute methods' do
- ModelWithAttributes.define_attribute_methods([:foo])
+ ModelWithAttributes.define_attribute_methods(:foo)
assert_respond_to ModelWithAttributes.new, :foo
assert_equal "value of foo", ModelWithAttributes.new.foo
end
test '#define_attribute_methods generates attribute methods with spaces in their names' do
- ModelWithAttributesWithSpaces.define_attribute_methods([:'foo bar'])
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.send(:'foo bar')
end
test '#alias_attribute works with attributes with spaces in their names' do
- ModelWithAttributesWithSpaces.define_attribute_methods([:'foo bar'])
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar')
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar
end
test '#undefine_attribute_methods removes attribute methods' do
- ModelWithAttributes.define_attribute_methods([:foo])
+ ModelWithAttributes.define_attribute_methods(:foo)
ModelWithAttributes.undefine_attribute_methods
assert !ModelWithAttributes.new.respond_to?(:foo)
@@ -170,7 +177,7 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_deprecated { klass.attribute_method_suffix '' }
assert_deprecated { klass.attribute_method_prefix '' }
- klass.define_attribute_methods([:foo])
+ klass.define_attribute_methods(:foo)
assert_equal 'value of foo', klass.new.foo
end
diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb
index 98244a6290..eaaf910bac 100644
--- a/activemodel/test/cases/dirty_test.rb
+++ b/activemodel/test/cases/dirty_test.rb
@@ -3,7 +3,7 @@ require "cases/helper"
class DirtyTest < ActiveModel::TestCase
class DirtyModel
include ActiveModel::Dirty
- define_attribute_methods [:name, :color]
+ define_attribute_methods :name, :color
def initialize
@name = nil
diff --git a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
index 3660b9b1e5..418a24294a 100644
--- a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
+++ b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
@@ -19,7 +19,7 @@ class SanitizerTest < ActiveModel::TestCase
test "sanitize attributes" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
- attributes = @logger_sanitizer.sanitize(original_attributes, @authorizer)
+ attributes = @logger_sanitizer.sanitize(self.class, original_attributes, @authorizer)
assert attributes.key?('first_name'), "Allowed key shouldn't be rejected"
assert !attributes.key?('admin'), "Denied key should be rejected"
@@ -29,14 +29,14 @@ class SanitizerTest < ActiveModel::TestCase
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
log = StringIO.new
self.logger = ActiveSupport::Logger.new(log)
- @logger_sanitizer.sanitize(original_attributes, @authorizer)
+ @logger_sanitizer.sanitize(self.class, original_attributes, @authorizer)
assert_match(/admin/, log.string, "Should log removed attributes: #{log.string}")
end
test "debug mass assignment removal with StrictSanitizer" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
assert_raise ActiveModel::MassAssignmentSecurity::Error do
- @strict_sanitizer.sanitize(original_attributes, @authorizer)
+ @strict_sanitizer.sanitize(self.class, original_attributes, @authorizer)
end
end
@@ -44,7 +44,7 @@ class SanitizerTest < ActiveModel::TestCase
original_attributes = {'id' => 1, 'first_name' => 'allowed'}
assert_nothing_raised do
- @strict_sanitizer.sanitize(original_attributes, @authorizer)
+ @strict_sanitizer.sanitize(self.class, original_attributes, @authorizer)
end
end
diff --git a/activemodel/test/cases/mass_assignment_security_test.rb b/activemodel/test/cases/mass_assignment_security_test.rb
index a197dbe748..0c6352cd71 100644
--- a/activemodel/test/cases/mass_assignment_security_test.rb
+++ b/activemodel/test/cases/mass_assignment_security_test.rb
@@ -4,7 +4,7 @@ require 'models/mass_assignment_specific'
class CustomSanitizer < ActiveModel::MassAssignmentSecurity::Sanitizer
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
raise StandardError
end
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index a716d0896e..1f5023bf76 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -344,4 +344,19 @@ class ValidationsTest < ActiveModel::TestCase
Topic.validates :title, options
assert_equal({ :presence => true }, options)
end
+
+ def test_dup_validity_is_independent
+ Topic.validates_presence_of :title
+ topic = Topic.new("title" => "Litterature")
+ topic.valid?
+
+ duped = topic.dup
+ duped.title = nil
+ assert duped.invalid?
+
+ topic.title = nil
+ duped.title = 'Mathematics'
+ assert topic.invalid?
+ assert duped.valid?
+ end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index e53d688ad9..11fd0e7047 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,17 @@
## Rails 4.0.0 (unreleased) ##
+* It's not possible anymore to destroy a model marked as read only.
+
+ *Johannes Barre*
+
+
+* Added ability to ActiveRecord::Relation#from to accept other ActiveRecord::Relation objects
+
+ Record.from(subquery)
+ Record.from(subquery, :a)
+
+ *Radoslav Stankov*
+
* Added custom coders support for ActiveRecord::Store. Now you can set
your custom coder like this:
@@ -633,7 +645,7 @@
has_one :account
end
- user.build_account{ |a| a.credit_limit => 100.0 }
+ user.build_account{ |a| a.credit_limit = 100.0 }
The block is called after the instance has been initialized. *Andrew White*
@@ -4006,7 +4018,7 @@
* Fixed that adding a record to a has_and_belongs_to collection would always save it -- now it only saves if its a new record #1203 *Alisdair McDiarmid*
-* Fixed saving of in-memory association structures to happen as a after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
+* Fixed saving of in-memory association structures to happen as an after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
* Allow any Enumerable, not just Array, to work as bind variables #1344 *Jeremy Kemper*
@@ -5519,7 +5531,7 @@
* Fixed that adding a record to a has_and_belongs_to collection would always save it -- now it only saves if its a new record #1203 *Alisdair McDiarmid*
-* Fixed saving of in-memory association structures to happen as a after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
+* Fixed saving of in-memory association structures to happen as an after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
* Allow any Enumerable, not just Array, to work as bind variables #1344 *Jeremy Kemper*
@@ -6441,7 +6453,7 @@
post.categories.push_with_attributes(category, :added_on => Date.today)
post.categories.first.added_on # => Date.today
- NOTE: The categories table doesn't have a added_on column, it's the categories_post join table that does!
+ NOTE: The categories table doesn't have an added_on column, it's the categories_post join table that does!
* Fixed that :exclusively_dependent and :dependent can't be activated at the same time on has_many associations *Jeremy Kemper*
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index c30e8e08b8..68f8bbeb1c 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -543,7 +543,7 @@ module ActiveRecord
# end
#
# @group = Group.first
- # @group.users.collect { |u| u.avatar }.flatten # select all avatars for all users in the group
+ # @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
# @group.avatars # selects all avatars by going through the User join model.
#
# An important caveat with going through +has_one+ or +has_many+ associations on the
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 00321ec860..3af5ff3eab 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -242,8 +242,12 @@ module ActiveRecord
# This method is abstract in the sense that it relies on
# +count_records+, which is a method descendants have to provide.
def size
- if !find_target? || (loaded? && !options[:uniq])
- target.size
+ if !find_target? || loaded?
+ if options[:uniq]
+ target.uniq.size
+ else
+ target.size
+ end
elsif !loaded? && options[:group]
load_target.size
elsif !loaded? && !options[:uniq] && target.is_a?(Array)
@@ -468,6 +472,8 @@ module ActiveRecord
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
"new records could not be saved."
end
+
+ new_target
end
def concat_records(records)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index f17baec722..df78ba6c5a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -23,7 +23,7 @@ module ActiveRecord
end
def sql_type
- base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
+ base.type_to_sql(type.to_sym, limit, precision, scale)
end
def to_sql
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 1933ce2b46..01bd3ae26c 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -124,6 +124,7 @@ module ActiveRecord
when :binary then "#{klass}.binary_to_string(#{var_name})"
when :boolean then "#{klass}.value_to_boolean(#{var_name})"
when :hstore then "#{klass}.string_to_hstore(#{var_name})"
+ when :inet, :cidr then "#{klass}.string_to_cidr(#{var_name})"
else var_name
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index c82afc232c..df3d5e4657 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -137,6 +137,14 @@ module ActiveRecord
end
end
+ class Cidr < Type
+ def type_cast(value)
+ return if value.nil?
+
+ ConnectionAdapters::PostgreSQLColumn.string_to_cidr value
+ end
+ end
+
class TypeMap
def initialize
@mapping = {}
@@ -212,11 +220,9 @@ module ActiveRecord
# FIXME: why are we keeping these types as strings?
alias_type 'tsvector', 'text'
alias_type 'interval', 'text'
- alias_type 'cidr', 'text'
- alias_type 'inet', 'text'
- alias_type 'macaddr', 'text'
alias_type 'bit', 'text'
alias_type 'varbit', 'text'
+ alias_type 'macaddr', 'text'
# FIXME: I don't think this is correct. We should probably be returning a parsed date,
# but the tests pass with a string returned.
@@ -237,6 +243,9 @@ module ActiveRecord
register_type 'polygon', OID::Identity.new
register_type 'circle', OID::Identity.new
register_type 'hstore', OID::Hstore.new
+
+ register_type 'cidr', OID::Cidr.new
+ alias_type 'inet', 'cidr'
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 4d5459939b..6714970103 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -8,6 +8,8 @@ require 'arel/visitors/bind_visitor'
gem 'pg', '~> 0.11'
require 'pg'
+require 'ipaddr'
+
module ActiveRecord
module ConnectionHandling
# Establishes a connection to the database that's used by all Active Record objects
@@ -79,6 +81,25 @@ module ActiveRecord
end
end
+ def string_to_cidr(string)
+ if string.nil?
+ nil
+ elsif String === string
+ IPAddr.new(string)
+ else
+ string
+ end
+
+ end
+
+ def cidr_to_string(object)
+ if IPAddr === object
+ "#{object.to_s}/#{object.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
+ else
+ object
+ end
+ end
+
private
HstorePair = begin
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
@@ -197,6 +218,13 @@ module ActiveRecord
:decimal
when 'hstore'
:hstore
+ # Network address types
+ when 'inet'
+ :inet
+ when 'cidr'
+ :cidr
+ when 'macaddr'
+ :macaddr
# Character types
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
:string
@@ -211,9 +239,6 @@ module ActiveRecord
# Geometric types
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
:string
- # Network address types
- when /^(?:cidr|inet|macaddr)$/
- :string
# Bit strings
when /^bit(?: varying)?(?:\(\d+\))?$/
:string
@@ -282,6 +307,18 @@ module ActiveRecord
def hstore(name, options = {})
column(name, 'hstore', options)
end
+
+ def inet(name, options = {})
+ column(name, 'inet', options)
+ end
+
+ def cidr(name, options = {})
+ column(name, 'cidr', options)
+ end
+
+ def macaddr(name, options = {})
+ column(name, 'macaddr', options)
+ end
end
ADAPTER_NAME = 'PostgreSQL'
@@ -301,7 +338,10 @@ module ActiveRecord
:boolean => { :name => "boolean" },
:xml => { :name => "xml" },
:tsvector => { :name => "tsvector" },
- :hstore => { :name => "hstore" }
+ :hstore => { :name => "hstore" },
+ :inet => { :name => "inet" },
+ :cidr => { :name => "cidr" },
+ :macaddr => { :name => "macaddr" }
}
# Returns 'PostgreSQL' as adapter name for identification purposes.
@@ -510,6 +550,11 @@ module ActiveRecord
when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
else super
end
+ when IPAddr
+ case column.sql_type
+ when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
+ else super
+ end
when Float
if value.infinite? && column.type == :datetime
"'#{value.to_s.downcase}'"
@@ -549,6 +594,9 @@ module ActiveRecord
when Hash
return super unless 'hstore' == column.sql_type
PostgreSQLColumn.hstore_to_string(value)
+ when IPAddr
+ return super unless ['inet','cidr'].includes? column.sql_type
+ PostgreSQLColumn.cidr_to_string(value)
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 44e407a561..d4ffa82b17 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -21,10 +21,6 @@ module ActiveRecord
config[:database] = File.expand_path(config[:database], Rails.root)
end
- unless 'sqlite3' == config[:adapter]
- raise ArgumentError, 'adapter name should be "sqlite3"'
- end
-
db = SQLite3::Database.new(
config[:database],
:results_as_hash => true
@@ -195,7 +191,7 @@ module ActiveRecord
:decimal => { :name => "decimal" },
:datetime => { :name => "datetime" },
:timestamp => { :name => "datetime" },
- :time => { :name => "time" },
+ :time => { :name => "datetime" },
:date => { :name => "date" },
:binary => { :name => "blob" },
:boolean => { :name => "boolean" }
@@ -522,7 +518,11 @@ module ActiveRecord
end
def copy_table(from, to, options = {}) #:nodoc:
- options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
+ from_primary_key = primary_key(from)
+ options[:primary_key] = from_primary_key if from_primary_key != 'id'
+ unless options[:primary_key]
+ options[:id] = columns(from).detect{|c| c.name == 'id'}.present? && from_primary_key == 'id'
+ end
create_table(to, options) do |definition|
@definition = definition
columns(from).each do |column|
@@ -536,7 +536,7 @@ module ActiveRecord
:precision => column.precision, :scale => column.scale,
:null => column.null)
end
- @definition.primary_key(primary_key(from)) if primary_key(from)
+ @definition.primary_key(from_primary_key) if from_primary_key
yield @definition if block_given?
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index ed555e4bf6..b2ed606e5f 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -127,10 +127,16 @@ module ActiveRecord
object.is_a?(self)
end
+ # Returns an instance of <tt>Arel::Table</tt> loaded with the curent table name.
+ #
+ # class Post < ActiveRecord::Base
+ # scope :published_and_commented, published.and(self.arel_table[:comments_count].gt(0))
+ # end
def arel_table
@arel_table ||= Arel::Table.new(table_name, arel_engine)
end
+ # Returns the Arel engine.
def arel_engine
@arel_engine ||= connection_handler.retrieve_connection_pool(self) ? self : active_record_super.arel_engine
end
@@ -204,7 +210,7 @@ module ActiveRecord
self
end
-
+
##
# :method: clone
# Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
@@ -219,9 +225,9 @@ module ActiveRecord
#
# user.object_id == new_user.object_id # => false
# user.name.object_id == new_user.name.object_id # => true
- #
+ #
# user.name.object_id == user.dup.name.object_id # => false
-
+
##
# :method: dup
# Duped objects have no id assigned and are treated as new records. Note
@@ -230,7 +236,7 @@ module ActiveRecord
# specific and is therefore left to the application to implement according
# to its need.
# The dup method does not preserve the timestamps (created|updated)_(at|on).
-
+
##
def initialize_dup(other) # :nodoc:
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index c630af59f0..7e6512501c 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -83,7 +83,7 @@ module ActiveRecord
# end
#
# test "find_alt_method_2" do
- # assert_equal "Ruby on Rails", @rubyonrails.news
+ # assert_equal "Ruby on Rails", @rubyonrails.name
# end
#
# In order to use these methods to access fixtured data within your testcases, you must specify one of the
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 4a987c2343..a1bc39a32d 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -123,6 +123,7 @@ module ActiveRecord
# Deletes the record in the database and freezes this instance to reflect
# that no changes should be made (since they can't be persisted).
def destroy
+ raise ReadOnlyRecord if readonly?
destroy_associations
destroy_row if persisted?
@destroyed = true
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 3ce9995031..31d99f0192 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -108,34 +108,57 @@ module ActiveRecord
0
end
- # This method is designed to perform select by a single column as direct SQL query
- # Returns <tt>Array</tt> with values of the specified column name
- # The values has same data type as column.
+ # Use <tt>pluck</tt> as a shortcut to select a single attribute without
+ # loading a bunch of records just to grab one attribute you want.
+ #
+ # Person.pluck(:name)
+ #
+ # instead of
+ #
+ # Person.all.map(&:name)
+ #
+ # Pluck returns an <tt>Array</tt> of attribute values type-casted to match
+ # the plucked column name, if it can be deduced. Plucking a SQL fragment
+ # returns String values by default.
#
# Examples:
#
- # Person.pluck(:id) # SELECT people.id FROM people
- # Person.uniq.pluck(:role) # SELECT DISTINCT role FROM people
- # Person.where(:age => 21).limit(5).pluck(:id) # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
+ # Person.pluck(:id)
+ # # SELECT people.id FROM people
+ # # => [1, 2, 3]
+ #
+ # Person.uniq.pluck(:role)
+ # # SELECT DISTINCT role FROM people
+ # # => ['admin', 'member', 'guest']
+ #
+ # Person.where(:age => 21).limit(5).pluck(:id)
+ # # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
+ # # => [2, 3]
+ #
+ # Person.pluck('DATEDIFF(updated_at, created_at)')
+ # # SELECT DATEDIFF(updated_at, created_at) FROM people
+ # # => ['0', '27761', '173']
#
def pluck(column_name)
- key = column_name.to_s.split('.', 2).last
-
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
column_name = "#{table_name}.#{column_name}"
end
result = klass.connection.select_all(select(column_name).arel, nil, bind_values)
- types = result.column_types.merge klass.column_types
- column = types[key]
+
+ key = result.columns.first
+ column = klass.column_types.fetch(key) {
+ result.column_types.fetch(key) {
+ Class.new { def type_cast(v); v; end }.new
+ }
+ }
result.map do |attributes|
- value = klass.initialize_attributes(attributes)[key]
- if column
- column.type_cast value
- else
- value
- end
+ raise ArgumentError, "Pluck expects to select just one attribute: #{attributes.inspect}" unless attributes.one?
+
+ value = klass.initialize_attributes(attributes).values.first
+
+ column.type_cast(value)
end
end
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 3f880ce5e9..36f98c6480 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -43,7 +43,7 @@ module ActiveRecord
def normal_values
Relation::SINGLE_VALUE_METHODS +
Relation::MULTI_VALUE_METHODS -
- [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering]
+ [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from]
end
def merge
@@ -76,6 +76,7 @@ module ActiveRecord
end
def merge_single_values
+ relation.from_value = values[:from] unless relation.from_value
relation.lock_value = values[:lock] unless relation.lock_value
relation.reverse_order_value = values[:reverse_order]
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 29536b16c4..19fe8155d9 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -300,12 +300,25 @@ module ActiveRecord
self
end
- def from(value)
- spawn.from!(value)
+ # Specifies table from which the records will be fetched. For example:
+ #
+ # Topic.select('title').from('posts')
+ # #=> SELECT title FROM posts
+ #
+ # Can accept other relation objects. For example:
+ #
+ # Topic.select('title').from(Topics.approved)
+ # # => SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
+ #
+ # Topics.select('a.title').from(Topics.approved, :a)
+ # # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
+ #
+ def from(value, subquery_name = nil)
+ spawn.from!(value, subquery_name)
end
- def from!(value)
- self.from_value = value
+ def from!(value, subquery_name = nil)
+ self.from_value = [value, subquery_name]
self
end
@@ -415,7 +428,7 @@ module ActiveRecord
build_select(arel, select_values.uniq)
arel.distinct(uniq_value)
- arel.from(from_value) if from_value
+ arel.from(build_from) if from_value
arel.lock(lock_value) if lock_value
arel
@@ -464,6 +477,17 @@ module ActiveRecord
end
end
+ def build_from
+ opts, name = from_value
+ case opts
+ when Relation
+ name ||= 'subquery'
+ opts.arel.as(name.to_s)
+ else
+ opts
+ end
+ end
+
def build_joins(manager, joins)
buckets = joins.group_by do |join|
case join
diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb
index d815ab05ac..599e68379a 100644
--- a/activerecord/lib/active_record/schema.rb
+++ b/activerecord/lib/active_record/schema.rb
@@ -34,6 +34,15 @@ module ActiveRecord
ActiveRecord::Migrator.migrations_paths
end
+ def define(info, &block)
+ instance_eval(&block)
+
+ unless info[:version].blank?
+ initialize_schema_migrations_table
+ assume_migrated_upto_version(info[:version], migrations_paths)
+ end
+ end
+
# Eval the given block. All methods available to the current connection
# adapter are available within the block, so you can easily use the
# database definition DSL to build up your schema (+create_table+,
@@ -46,13 +55,7 @@ module ActiveRecord
# ...
# end
def self.define(info={}, &block)
- schema = new
- schema.instance_eval(&block)
-
- unless info[:version].blank?
- initialize_schema_migrations_table
- assume_migrated_upto_version(info[:version], schema.migrations_paths)
- end
+ new.define(info, &block)
end
end
end
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index ed47a26749..5a256b040b 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -201,10 +201,10 @@ module ActiveRecord
class << self
alias :data_column_name :data_column
-
+
# Use the ActiveRecord::Base.connection by default.
attr_writer :connection
-
+
# Use the ActiveRecord::Base.connection_pool by default.
attr_writer :connection_pool
@@ -218,12 +218,12 @@ module ActiveRecord
# Look up a session by id and unmarshal its data if found.
def find_by_session_id(session_id)
- if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id)}")
+ if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id.to_s)}")
new(:session_id => session_id, :marshaled_data => record['data'])
end
end
end
-
+
delegate :connection, :connection=, :connection_pool, :connection_pool=, :to => self
attr_reader :session_id, :new_record
@@ -241,6 +241,11 @@ module ActiveRecord
@new_record = @marshaled_data.nil?
end
+ # Returns true if the record is persisted, i.e. it's not a new record
+ def persisted?
+ !@new_record
+ end
+
# Lazy-unmarshal session state.
def data
unless @data
@@ -287,7 +292,7 @@ module ActiveRecord
connect = connection
connect.delete <<-end_sql, 'Destroy session'
DELETE FROM #{table_name}
- WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id)}
+ WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id.to_s)}
end_sql
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 64e5640791..30e1035300 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -290,7 +290,15 @@ module ActiveRecord
status = nil
self.class.transaction do
add_to_transaction
- status = yield
+ begin
+ status = yield
+ rescue ActiveRecord::Rollback
+ if defined?(@_start_transaction_state)
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ end
+ status = nil
+ end
+
raise ActiveRecord::Rollback unless status
end
status
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index ce08e4c6a7..34660577da 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -86,9 +86,9 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
end
def test_data_type_of_network_address_types
- assert_equal :string, @first_network_address.column_for_attribute(:cidr_address).type
- assert_equal :string, @first_network_address.column_for_attribute(:inet_address).type
- assert_equal :string, @first_network_address.column_for_attribute(:mac_address).type
+ assert_equal :cidr, @first_network_address.column_for_attribute(:cidr_address).type
+ assert_equal :inet, @first_network_address.column_for_attribute(:inet_address).type
+ assert_equal :macaddr, @first_network_address.column_for_attribute(:mac_address).type
end
def test_data_type_of_bit_string_types
@@ -134,9 +134,12 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
assert_equal '-1 years -2 days', @first_time.time_interval
end
- def test_network_address_values
- assert_equal '192.168.0.0/24', @first_network_address.cidr_address
- assert_equal '172.16.1.254', @first_network_address.inet_address
+ def test_network_address_values_ipaddr
+ cidr_address = IPAddr.new '192.168.0.0/24'
+ inet_address = IPAddr.new '172.16.1.254'
+
+ assert_equal cidr_address, @first_network_address.cidr_address
+ assert_equal inet_address, @first_network_address.inet_address
assert_equal '01:23:45:67:89:0a', @first_network_address.mac_address
end
@@ -200,8 +203,8 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
end
def test_update_network_address
- new_cidr_address = '10.1.2.3/32'
- new_inet_address = '10.0.0.0/8'
+ new_inet_address = '10.1.2.3/32'
+ new_cidr_address = '10.0.0.0/8'
new_mac_address = 'bc:de:f0:12:34:56'
assert @first_network_address.cidr_address = new_cidr_address
assert @first_network_address.inet_address = new_inet_address
diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
index 575b4806c1..7eef4ace81 100644
--- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
@@ -57,6 +57,14 @@ class CopyTableTest < ActiveRecord::TestCase
end
end
+ def test_copy_table_with_unconventional_primary_key
+ test_copy_table('owners', 'owners_unconventional') do |from, to, options|
+ original_pk = @connection.primary_key('owners')
+ copied_pk = @connection.primary_key('owners_unconventional')
+ assert_equal original_pk, copied_pk
+ end
+ end
+
protected
def copy_table(from, to, options = {})
@connection.copy_table(from, to, {:temporary => true}.merge(options))
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 17bde6cb62..8a7f44d0a3 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -35,6 +35,11 @@ module ActiveRecord
assert(!result.rows.first.include?("blob"), "should not store blobs")
end
+ def test_time_column
+ owner = Owner.create!(:eats_at => Time.utc(1995,1,1,6,0))
+ assert_match(/1995-01-01/, owner.reload.eats_at.to_s)
+ end
+
def test_exec_insert
column = @conn.columns('items').find { |col| col.name == 'number' }
vals = [[column, 10]]
@@ -58,18 +63,6 @@ module ActiveRecord
end
end
- def test_connection_no_adapter
- assert_raises(ArgumentError) do
- Base.sqlite3_connection :database => ':memory:'
- end
- end
-
- def test_connection_wrong_adapter
- assert_raises(ArgumentError) do
- Base.sqlite3_connection :database => ':memory:',:adapter => 'vuvuzela'
- end
- end
-
def test_bad_timeout
assert_raises(TypeError) do
Base.sqlite3_connection :database => ':memory:',
diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb
index 588adc38e3..b2eac0349b 100644
--- a/activerecord/test/cases/ar_schema_test.rb
+++ b/activerecord/test/cases/ar_schema_test.rb
@@ -37,6 +37,13 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
end
+
+ def test_schema_subclass
+ Class.new(ActiveRecord::Schema).define(:version => 9) do
+ create_table :fruits
+ end
+ assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
+ end
end
end
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 470f0c3fd3..a6daf54c01 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
@@ -333,6 +333,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 3, project.developers.size
end
+ def test_uniq_when_association_already_loaded
+ project = projects(:active_record)
+ project.developers << [ developers(:jamis), developers(:david), developers(:jamis), developers(:david) ]
+ assert_equal 3, Project.includes(:developers).find(project.id).developers.size
+ end
+
def test_deleting
david = Developer.find(1)
active_record = Project.find(1)
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 13d8c68b33..2e24f8ebe1 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1685,6 +1685,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [bulb2], car.reload.bulbs
end
+ def test_replace_returns_new_target
+ car = Car.create(:name => 'honda')
+ bulb1 = car.bulbs.create
+ bulb2 = car.bulbs.create
+ bulb3 = Bulb.create
+
+ assert_equal [bulb1, bulb2], car.bulbs
+ result = car.bulbs.replace([bulb1, bulb3])
+ assert_equal [bulb1, bulb3], car.bulbs
+ assert_equal [bulb1, bulb3], result
+ end
+
def test_building_has_many_association_with_restrict_dependency
option_before = ActiveRecord::Base.dependent_restrict_raises
ActiveRecord::Base.dependent_restrict_raises = true
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index c1b0cb8886..66a16d8b5f 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -522,7 +522,7 @@ class BasicsTest < ActiveRecord::TestCase
end
# Oracle, and Sybase do not have a TIME datatype.
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter)
def test_utc_as_time_zone
Topic.default_timezone = :utc
attributes = { "bonus_time" => "5:42:00AM" }
@@ -764,6 +764,9 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time_will_ignore_hour_if_missing
+ ActiveRecord::Base.time_zone_aware_attributes = false
+ ActiveRecord::Base.default_timezone = :local
+ Time.zone = nil
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12",
"written_on(5i)" => "12", "written_on(6i)" => "02"
@@ -870,7 +873,7 @@ class BasicsTest < ActiveRecord::TestCase
end
# Oracle, and Sybase do not have a TIME datatype.
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter)
def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
ActiveRecord::Base.time_zone_aware_attributes = true
ActiveRecord::Base.default_timezone = :utc
@@ -891,6 +894,9 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time_with_empty_seconds
+ ActiveRecord::Base.time_zone_aware_attributes = false
+ ActiveRecord::Base.default_timezone = :local
+ Time.zone = nil
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
@@ -946,7 +952,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_attributes_on_dummy_time
# Oracle, and Sybase do not have a TIME datatype.
- return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
+ return true if current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter)
attributes = {
"bonus_time" => "5:42:00AM"
@@ -1514,11 +1520,7 @@ class BasicsTest < ActiveRecord::TestCase
after_seq = Joke.sequence_name
assert_not_equal before_columns, after_columns
- unless before_seq.nil? && after_seq.nil?
- assert_not_equal before_seq, after_seq
- assert_equal "cold_jokes_id_seq", before_seq
- assert_equal "funny_jokes_id_seq", after_seq
- end
+ assert_not_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
end
def test_dont_clear_sequence_name_when_setting_explicitly
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index e096585f62..041f8ffb7c 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -466,6 +466,21 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [7], Company.joins(:contracts).pluck(:developer_id)
end
+ def test_pluck_with_selection_clause
+ assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT credit_limit').sort
+ assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT accounts.credit_limit').sort
+ assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT(credit_limit)').sort
+
+ # MySQL returns "SUM(DISTINCT(credit_limit))" as the column name unless
+ # an alias is provided. Without the alias, the column cannot be found
+ # and properly typecast.
+ assert_equal [50 + 53 + 55 + 60], Account.pluck('SUM(DISTINCT(credit_limit)) as credit_limit')
+ end
+
+ def test_pluck_expects_a_single_selection
+ assert_raise(ArgumentError) { Account.pluck 'id, credit_limit' }
+ end
+
def test_plucks_with_ids
assert_equal Company.all.map(&:id).sort, Company.ids.sort
end
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index f0b1f74bd3..ab61a4dcef 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -83,7 +83,6 @@ module ActiveRecord
t.column :one_int, :integer, :limit => 1
t.column :four_int, :integer, :limit => 4
t.column :eight_int, :integer, :limit => 8
- t.column :eleven_int, :integer, :limit => 11
end
columns = connection.columns(:testings)
@@ -94,20 +93,17 @@ module ActiveRecord
one = columns.detect { |c| c.name == "one_int" }
four = columns.detect { |c| c.name == "four_int" }
eight = columns.detect { |c| c.name == "eight_int" }
- eleven = columns.detect { |c| c.name == "eleven_int" }
if current_adapter?(:PostgreSQLAdapter)
assert_equal 'integer', default.sql_type
assert_equal 'smallint', one.sql_type
assert_equal 'integer', four.sql_type
assert_equal 'bigint', eight.sql_type
- assert_equal 'integer', eleven.sql_type
elsif current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
assert_match 'int(11)', default.sql_type
assert_match 'tinyint', one.sql_type
assert_match 'int', four.sql_type
assert_match 'bigint', eight.sql_type
- assert_match 'int(11)', eleven.sql_type
elsif current_adapter?(:OracleAdapter)
assert_equal 'NUMBER(38)', default.sql_type
assert_equal 'NUMBER(1)', one.sql_type
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index 409a558f5c..18f8d82bfe 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -183,6 +183,16 @@ module ActiveRecord
assert_instance_of TrueClass, bob.male?
assert_kind_of BigDecimal, bob.wealth
end
+
+ def test_out_of_range_limit_should_raise
+ skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
+
+ assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, :limit => 10 }
+
+ unless current_adapter?(:PostgreSQLAdapter)
+ assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, :limit => 0xfffffffff }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index f788690b0d..cad93936c9 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -375,6 +375,27 @@ class MigrationTest < ActiveRecord::TestCase
end
end
+ def test_out_of_range_limit_should_raise
+ skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
+
+ Person.connection.drop_table :test_limits rescue nil
+ assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do
+ Person.connection.create_table :test_integer_limits, :force => true do |t|
+ t.column :bigone, :integer, :limit => 10
+ end
+ end
+
+ unless current_adapter?(:PostgreSQLAdapter)
+ assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
+ Person.connection.create_table :test_text_limits, :force => true do |t|
+ t.column :bigtext, :text, :limit => 0xfffffffff
+ end
+ end
+ end
+
+ Person.connection.drop_table :test_limits rescue nil
+ end
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
@@ -883,8 +904,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase
def test_skipping_migrations
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
@existing_migrations = Dir[@migrations_path + "/*.rb"]
-
- sources = {}
+
+ sources = {}
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_name_collision"
diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index 39b66b3399..df0399f548 100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
@@ -23,6 +23,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
end
assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save }
assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save! }
+ assert_raise(ActiveRecord::ReadOnlyRecord) { dev.destroy }
end
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 8a7a2441d4..89f818a689 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -203,13 +203,18 @@ module ActiveRecord
assert_equal [], relation.extending_values
end
- (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with]).each do |method|
+ (Relation::SINGLE_VALUE_METHODS - [:from, :lock, :reordering, :reverse_order, :create_with]).each do |method|
test "##{method}!" do
assert relation.public_send("#{method}!", :foo).equal?(relation)
assert_equal :foo, relation.public_send("#{method}_value")
end
end
+ test '#from!' do
+ assert relation.from!('foo').equal?(relation)
+ assert_equal ['foo', nil], relation.from_value
+ end
+
test '#lock!' do
assert relation.lock!('foo').equal?(relation)
assert_equal 'foo', relation.lock_value
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 76b868c7b4..dee31f4772 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -133,6 +133,13 @@ class RelationTest < ActiveRecord::TestCase
assert topics.loaded?
end
+ def test_finiding_with_subquery
+ relation = Topic.where(:approved => true)
+ assert_equal relation.to_a, Topic.select('*').from(relation).to_a
+ assert_equal relation.to_a, Topic.select('subquery.*').from(relation).to_a
+ assert_equal relation.to_a, Topic.select('a.*').from(relation, :a).to_a
+ end
+
def test_finding_with_conditions
assert_equal ["David"], Author.where(:name => 'David').map(&:name)
assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 15ceaa1fcc..ab80dd1d6d 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -236,6 +236,27 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
end
+ def test_schema_dump_includes_inet_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_network_address"} =~ output
+ assert_match %r{t.inet "inet_address"}, output
+ end
+ end
+
+ def test_schema_dump_includes_cidr_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_network_address"} =~ output
+ assert_match %r{t.cidr "cidr_address"}, output
+ end
+ end
+
+ def test_schema_dump_includes_macaddr_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_network_address"} =~ output
+ assert_match %r{t.macaddr "macaddr_address"}, output
+ end
+ end
+
def test_schema_dump_includes_hstores_shorthand_definition
output = standard_dump
if %r{create_table "postgresql_hstores"} =~ output
diff --git a/activerecord/test/cases/session_store/sql_bypass.rb b/activerecord/test/cases/session_store/sql_bypass_test.rb
index 7402b2afd6..6749d4ce98 100644
--- a/activerecord/test/cases/session_store/sql_bypass.rb
+++ b/activerecord/test/cases/session_store/sql_bypass_test.rb
@@ -18,6 +18,11 @@ module ActiveRecord
assert !Session.table_exists?
end
+ def test_new_record?
+ s = SqlBypass.new :data => 'foo', :session_id => 10
+ assert s.new_record?, 'this is a new record!'
+ end
+
def test_persisted?
s = SqlBypass.new :data => 'foo', :session_id => 10
assert !s.persisted?, 'this is a new record!'
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index 9846f5b12d..961ba8d9ba 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -287,8 +287,45 @@ class TransactionObserverCallbacksTest < ActiveRecord::TestCase
raise ActiveRecord::Rollback
end
+ assert topic.id.nil?
+ assert !topic.persisted?
assert_equal %w{ after_rollback }, topic.history
end
+
+ class TopicWithManualRollbackObserverAttached < ActiveRecord::Base
+ self.table_name = :topics
+ def history
+ @history ||= []
+ end
+ end
+
+ class TopicWithManualRollbackObserverAttachedObserver < ActiveRecord::Observer
+ def after_save(record)
+ record.history.push "after_save"
+ raise ActiveRecord::Rollback
+ end
+ end
+
+ def test_after_save_called_with_manual_rollback
+ assert TopicWithManualRollbackObserverAttachedObserver.instance, 'should have observer'
+
+ topic = TopicWithManualRollbackObserverAttached.new
+
+ assert !topic.save
+ assert_equal nil, topic.id
+ assert !topic.persisted?
+ assert_equal %w{ after_save }, topic.history
+ end
+ def test_after_save_called_with_manual_rollback_bang
+ assert TopicWithManualRollbackObserverAttachedObserver.instance, 'should have observer'
+
+ topic = TopicWithManualRollbackObserverAttached.new
+
+ topic.save!
+ assert_equal nil, topic.id
+ assert !topic.persisted?
+ assert_equal %w{ after_save }, topic.history
+ end
end
class SaveFromAfterCommitBlockTest < ActiveRecord::TestCase
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 6422cf6415..3fc58c25b1 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -431,6 +431,7 @@ ActiveRecord::Schema.define do
t.string :name
t.column :updated_at, :datetime
t.column :happy_at, :datetime
+ t.column :eats_at, :time
t.string :essay_id
end
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index e97bb25b9f..7c3a41288b 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -8,8 +8,6 @@ module ActiveSupport
# instead of the file system root. The typical silencer use case is to exclude the output of a noisy library from the
# backtrace, so that you can focus on the rest.
#
- # ==== Example:
- #
# bc = BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root, '') }
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
@@ -42,8 +40,6 @@ module ActiveSupport
# Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
#
- # Example:
- #
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
def add_filter(&block)
@@ -53,8 +49,6 @@ module ActiveSupport
# Adds a silencer from the block provided. If the silencer returns true for a given line, it will be excluded from
# the clean backtrace.
#
- # Example:
- #
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
def add_silencer(&block)
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index c6c7e2821b..af683d37ed 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -23,8 +23,6 @@ module ActiveSupport
# methods, procs or lambdas, or callback objects that respond to certain predetermined
# methods. See +ClassMethods.set_callback+ for details.
#
- # ==== Example
- #
# class Record
# include ActiveSupport::Callbacks
# define_callbacks :save
@@ -312,13 +310,13 @@ module ActiveSupport
method << "value = nil"
method << "halted = false"
- callbacks = "value = yield if block_given? && !halted"
+ callbacks = "value = !halted && (!block_given? || yield)"
reverse_each do |callback|
callbacks = callback.apply(callbacks)
end
method << callbacks
- method << "halted ? false : (block_given? ? value : true)"
+ method << "value"
method.join("\n")
end
@@ -330,26 +328,17 @@ module ActiveSupport
# if it was not yet defined.
# This generated method plays caching role.
def __define_callbacks(kind, object) #:nodoc:
- name = __callback_runner_name(kind)
+ chain = object.send("_#{kind}_callbacks")
+ name = "_run_callbacks_#{chain.object_id}"
unless object.respond_to?(name, true)
- str = object.send("_#{kind}_callbacks").compile
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}() #{str} end
+ def #{name}() #{chain.compile} end
protected :#{name}
RUBY_EVAL
end
name
end
- def __reset_runner(symbol)
- name = __callback_runner_name(symbol)
- undef_method(name) if method_defined?(name)
- end
-
- def __callback_runner_name(kind)
- "_run__#{self.name.hash.abs}__#{kind}__callbacks"
- end
-
# This is used internally to append, prepend and skip callbacks to the
# CallbackChain.
#
@@ -361,7 +350,6 @@ module ActiveSupport
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
chain = target.send("_#{name}_callbacks")
yield target, chain.dup, type, filters, options
- target.__reset_runner(name)
end
end
@@ -449,12 +437,9 @@ module ActiveSupport
chain = target.send("_#{symbol}_callbacks").dup
callbacks.each { |c| chain.delete(c) }
target.send("_#{symbol}_callbacks=", chain)
- target.__reset_runner(symbol)
end
self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
-
- __reset_runner(symbol)
end
# Define sets of events in the object lifecycle that support callbacks.
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 323126fcfa..3e36c54eba 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -107,8 +107,6 @@ class Date
# Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
#
- # Examples:
- #
# Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1)
# Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12)
def change(options)
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 97e3c71992..81f969e786 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -26,7 +26,6 @@ class Date
#
# This method is aliased to <tt>to_s</tt>.
#
- # ==== Examples
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
#
# date.to_formatted_s(:db) # => "2007-11-10"
@@ -69,7 +68,6 @@ class Date
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
# The timezone can be either :local or :utc (default :local).
#
- # ==== Examples
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
#
# date.to_time # => Sat Nov 10 00:00:00 0800 2007
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index 020fa1a06d..fd78044b5d 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -104,8 +104,6 @@ class DateTime
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0
#
- # Example:
- #
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
def utc
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index 6338dc6397..19925198c0 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -42,7 +42,6 @@ class DateTime
alias_method :to_default_s, :to_s unless (instance_methods(false) & [:to_s, 'to_s']).empty?
alias_method :to_s, :to_formatted_s
- # Returns the +utc_offset+ as an +HH:MM formatted string. Examples:
#
# datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
# datetime.formatted_offset # => "-06:00"
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index b9c632e4f5..02d5a7080f 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -1,5 +1,5 @@
module Enumerable
- # Calculates a sum from the elements. Examples:
+ # Calculates a sum from the elements.
#
# payments.sum { |p| p.price * p.tax_rate }
# payments.sum(&:price)
@@ -26,7 +26,7 @@ module Enumerable
end
end
- # Convert an enumerable to a hash. Examples:
+ # Convert an enumerable to a hash.
#
# people.index_by(&:login)
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
index af771c86ff..023bf68a87 100644
--- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
@@ -1,11 +1,16 @@
class Hash
# Returns a new hash with +self+ and +other_hash+ merged recursively.
+ #
+ # h1 = {x: {y: [4,5,6]}, z: [7,8,9]}
+ # h2 = {x: {y: [7,8,9]}, z: "xyz"}
+ #
+ # h1.deep_merge(h2) #=> {:x => {:y => [7, 8, 9]}, :z => "xyz"}
+ # h2.deep_merge(h1) #=> {:x => {:y => [4, 5, 6]}, :z => [7, 8, 9]}
def deep_merge(other_hash)
dup.deep_merge!(other_hash)
end
- # Returns a new hash with +self+ and +other_hash+ merged recursively.
- # Modifies the receiver in place.
+ # Same as +deep_merge+, but modifies +self+.
def deep_merge!(other_hash)
other_hash.each_pair do |k,v|
tv = self[k]
diff --git a/activesupport/lib/active_support/core_ext/hash/diff.rb b/activesupport/lib/active_support/core_ext/hash/diff.rb
index 855dcb38bc..831dee8ecb 100644
--- a/activesupport/lib/active_support/core_ext/hash/diff.rb
+++ b/activesupport/lib/active_support/core_ext/hash/diff.rb
@@ -1,8 +1,6 @@
class Hash
# Returns a hash that represents the difference between two hashes.
#
- # Examples:
- #
# {1 => 2}.diff(1 => 2) # => {}
# {1 => 2}.diff(1 => 3) # => {1 => 2}
# {}.diff(1 => 2) # => {1 => 2}
diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb
index 230a84dabc..be4d611ce7 100644
--- a/activesupport/lib/active_support/core_ext/hash/keys.rb
+++ b/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -1,5 +1,8 @@
class Hash
# Return a new hash with all keys converted to strings.
+ #
+ # { :name => 'Rob', :years => '28' }.stringify_keys
+ # #=> { "name" => "Rob", "years" => "28" }
def stringify_keys
result = {}
keys.each do |key|
@@ -8,7 +11,8 @@ class Hash
result
end
- # Destructively convert all keys to strings.
+ # Destructively convert all keys to strings. Same as
+ # +stringify_keys+, but modifies +self+.
def stringify_keys!
keys.each do |key|
self[key.to_s] = delete(key)
@@ -18,6 +22,9 @@ class Hash
# Return a new hash with all keys converted to symbols, as long as
# they respond to +to_sym+.
+ #
+ # { 'name' => 'Rob', 'years' => '28' }.symbolize_keys
+ # #=> { :name => "Rob", :years => "28" }
def symbolize_keys
result = {}
keys.each do |key|
@@ -28,7 +35,7 @@ class Hash
alias_method :to_options, :symbolize_keys
# Destructively convert all keys to symbols, as long as they respond
- # to +to_sym+.
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
def symbolize_keys!
keys.each do |key|
self[(key.to_sym rescue key)] = delete(key)
@@ -41,7 +48,6 @@ class Hash
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
# as keys, this will fail.
#
- # ==== Examples
# { :name => 'Rob', :years => '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
# { :name => 'Rob', :age => '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
# { :name => 'Rob', :age => '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb
index 382156ecd8..580cb80413 100644
--- a/activesupport/lib/active_support/core_ext/module/aliasing.rb
+++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb
@@ -45,8 +45,6 @@ class Module
# Allows you to make aliases for attributes, which includes
# getter, setter, and query methods.
#
- # Example:
- #
# class Content < ActiveRecord::Base
# # has a title attribute
# end
diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb
index 2c4383ac94..883f5f556c 100644
--- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb
+++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb
@@ -1,5 +1,13 @@
class Object
- # Returns a deep copy of object if it's duplicable.
+ # Returns a deep copy of object if it's duplicable. If it's
+ # not duplicable, returns +self+.
+ #
+ # object = Object.new
+ # dup = object.deep_dup
+ # dup.instance_variable_set(:@a, 1)
+ #
+ # object.instance_variable_defined?(:@a) #=> false
+ # dup.instance_variable_defined?(:@a) #=> true
def deep_dup
duplicable? ? dup : self
end
@@ -7,6 +15,13 @@ end
class Array
# Returns a deep copy of array.
+ #
+ # array = [1, [2, 3]]
+ # dup = array.deep_dup
+ # dup[1][2] = 4
+ #
+ # array[1][2] #=> nil
+ # dup[1][2] #=> 4
def deep_dup
map { |it| it.deep_dup }
end
@@ -14,6 +29,13 @@ end
class Hash
# Returns a deep copy of hash.
+ #
+ # hash = { a: { b: 'b' } }
+ # dup = hash.deep_dup
+ # dup[:a][:c] = 'c'
+ #
+ # hash[:a][:c] #=> nil
+ # dup[:a][:c] #=> "c"
def deep_dup
each_with_object(dup) do |(key, value), hash|
hash[key.deep_dup] = value.deep_dup
diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb
index 9d1630bb7c..f1b755c2c4 100644
--- a/activesupport/lib/active_support/core_ext/object/duplicable.rb
+++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb
@@ -19,7 +19,7 @@
class Object
# Can you safely dup this object?
#
- # False for +nil+, +false+, +true+, symbols, numbers, class and module objects;
+ # False for +nil+, +false+, +true+, symbol, and number objects;
# true otherwise.
def duplicable?
true
@@ -81,30 +81,6 @@ class Numeric
end
end
-class Class
- # Classes are not duplicable:
- #
- # c = Class.new # => #<Class:0x10328fd80>
- # c.dup # => #<Class:0x10328fd80>
- #
- # Note +dup+ returned the same class object.
- def duplicable?
- false
- end
-end
-
-class Module
- # Modules are not duplicable:
- #
- # m = Module.new # => #<Module:0x10328b6e0>
- # m.dup # => #<Module:0x10328b6e0>
- #
- # Note +dup+ returned the same module object.
- def duplicable?
- false
- end
-end
-
require 'bigdecimal'
class BigDecimal
begin
diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
index 91fdf93eb2..40821fd619 100644
--- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb
+++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -1,6 +1,6 @@
class Object
- # Returns a hash that maps instance variable names without "@" to their
- # corresponding values. Keys are strings both in Ruby 1.8 and 1.9.
+ # Returns a hash with string keys that maps instance variable names without "@" to their
+ # corresponding values.
#
# class C
# def initialize(x, y)
@@ -9,12 +9,11 @@ class Object
# end
#
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
- def instance_values #:nodoc:
+ def instance_values
Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
end
- # Returns an array of instance variable names including "@". They are strings
- # both in Ruby 1.8 and 1.9.
+ # Returns an array of instance variable names including "@".
#
# class C
# def initialize(x, y)
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index 40a8101ca3..48eb546a7d 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -1,6 +1,6 @@
class Object
# Invokes the public method identified by the symbol +method+, passing it any arguments
- # and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
+ # and/or the block specified, just like the regular Ruby <tt>Object#public_send</tt> does.
#
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
@@ -24,7 +24,7 @@ class Object
# Without a method argument try will yield to the block unless the receiver is nil.
# @person.try { |p| "#{p.first_name} #{p.last_name}" }
#--
- # +try+ behaves like +Object#send+, unless called on +NilClass+.
+ # +try+ behaves like +Object#public_send+, unless called on +NilClass+.
def try(*a, &b)
if a.empty? && block_given?
yield self
diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb
index 43134b4314..b1a12781f3 100644
--- a/activesupport/lib/active_support/core_ext/range/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -5,8 +5,6 @@ class Range
# Gives a human readable format of the range.
#
- # ==== Example
- #
# (1..100).to_formatted_s # => "1..100"
def to_formatted_s(format = :default)
if formatter = RANGE_FORMATS[format]
diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb
index ab49af55bf..fb36262528 100644
--- a/activesupport/lib/active_support/core_ext/string.rb
+++ b/activesupport/lib/active_support/core_ext/string.rb
@@ -6,7 +6,6 @@ require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/string/access'
require 'active_support/core_ext/string/xchar'
require 'active_support/core_ext/string/behavior'
-require 'active_support/core_ext/string/interpolation'
require 'active_support/core_ext/string/output_safety'
require 'active_support/core_ext/string/exclude'
require 'active_support/core_ext/string/strip'
diff --git a/activesupport/lib/active_support/core_ext/string/inquiry.rb b/activesupport/lib/active_support/core_ext/string/inquiry.rb
index 2562a7cef6..1dcd949536 100644
--- a/activesupport/lib/active_support/core_ext/string/inquiry.rb
+++ b/activesupport/lib/active_support/core_ext/string/inquiry.rb
@@ -2,7 +2,7 @@ require 'active_support/string_inquirer'
class String
# Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
- # which gives you a prettier way to test for equality. Example:
+ # which gives you a prettier way to test for equality.
#
# env = 'production'.inquiry
# env.production? # => true
diff --git a/activesupport/lib/active_support/core_ext/string/interpolation.rb b/activesupport/lib/active_support/core_ext/string/interpolation.rb
deleted file mode 100644
index 7f764e9de1..0000000000
--- a/activesupport/lib/active_support/core_ext/string/interpolation.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'active_support/i18n'
-require 'i18n/core_ext/string/interpolate'
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 6bda970e40..f98d5b3777 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -150,6 +150,20 @@ module ActiveSupport #:nodoc:
dup.concat(other)
end
+ def %(args)
+ args = Array(args)
+
+ args.map! do |arg|
+ if !html_safe? || arg.html_safe?
+ arg
+ else
+ ERB::Util.h(arg)
+ end
+ end
+
+ self.class.new(super(args))
+ end
+
def html_safe?
defined?(@html_safe) && @html_safe
end
diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb
index 9102537810..fc962dcb57 100644
--- a/activesupport/lib/active_support/deprecation/behaviors.rb
+++ b/activesupport/lib/active_support/deprecation/behaviors.rb
@@ -16,9 +16,9 @@ module ActiveSupport
#
# Available behaviors:
#
- # [+stderr+] Log all deprecation warnings to +$stderr+.
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
# [+log+] Log all deprecation warnings to +Rails.logger+.
- # [+notify] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
+ # [+notify+] Use <tt>ActiveSupport::Notifications</tt> to notify +deprecation.rails+.
# [+silence+] Do nothing.
#
# Setting behaviors only affects deprecations that happen after boot time.
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 00c67a470d..2cdc991120 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -5,7 +5,6 @@ require 'active_support/core_ext/object/acts_like'
module ActiveSupport
# Provides accurate date and time measurements using Date#advance and
# Time#advance, respectively. It mainly supports the methods on Numeric.
- # Example:
#
# 1.month.ago # equivalent to Time.now.advance(:months => -1)
class Duration < BasicObject
diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb
index 7eb61cd1a0..c04c2ed15b 100644
--- a/activesupport/lib/active_support/inflections.rb
+++ b/activesupport/lib/active_support/inflections.rb
@@ -26,7 +26,7 @@ module ActiveSupport
inflect.singular(/(ss)$/i, '\1')
inflect.singular(/(n)ews$/i, '\1ews')
inflect.singular(/([ti])a$/i, '\1um')
- inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1\2sis')
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
inflect.singular(/([^f])ves$/i, '\1fe')
inflect.singular(/(hive)s$/i, '\1')
diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb
index 13b23d627a..600e353812 100644
--- a/activesupport/lib/active_support/inflector/inflections.rb
+++ b/activesupport/lib/active_support/inflector/inflections.rb
@@ -3,7 +3,7 @@ require 'active_support/core_ext/array/prepend_and_append'
module ActiveSupport
module Inflector
# A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
- # inflection rules. Examples:
+ # inflection rules.
#
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1\2en'
@@ -40,7 +40,6 @@ module ActiveSupport
# A camelized string that contains the acronym will maintain the acronym when titleized or humanized, and will
# convert the acronym into a non-delimited single lowercase word when passed to +underscore+.
#
- # Examples:
# acronym 'HTML'
# titleize 'html' #=> 'HTML'
# camelize 'html' #=> 'HTML'
@@ -70,7 +69,6 @@ module ActiveSupport
# `acronym` may be used to specify any word that contains an acronym or otherwise needs to maintain a non-standard
# capitalization. The only restriction is that the word must begin with a capital letter.
#
- # Examples:
# acronym 'RESTful'
# underscore 'RESTful' #=> 'restful'
# underscore 'RESTfulController' #=> 'restful_controller'
@@ -105,7 +103,6 @@ module ActiveSupport
# Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
# for strings, not regular expressions. You simply pass the irregular in singular and plural form.
#
- # Examples:
# irregular 'octopus', 'octopi'
# irregular 'person', 'people'
def irregular(singular, plural)
@@ -127,7 +124,6 @@ module ActiveSupport
# Add uncountable words that shouldn't be attempted inflected.
#
- # Examples:
# uncountable "money"
# uncountable "money", "information"
# uncountable %w( money information rice )
@@ -139,7 +135,6 @@ module ActiveSupport
# When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
# When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
#
- # Examples:
# human /_cnt$/i, '\1_count'
# human "legacy_col_person_name", "Name"
def human(rule, replacement)
@@ -150,7 +145,6 @@ module ActiveSupport
# Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
# <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
#
- # Examples:
# clear :all
# clear :plurals
def clear(scope = :all)
@@ -166,7 +160,6 @@ module ActiveSupport
# Yields a singleton instance of Inflector::Inflections so you can specify additional
# inflector rules.
#
- # Example:
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.uncountable "rails"
# end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 4fcd32edf2..48296841aa 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -16,7 +16,6 @@ module ActiveSupport
# Returns the plural form of the word in the string.
#
- # Examples:
# "post".pluralize # => "posts"
# "octopus".pluralize # => "octopi"
# "sheep".pluralize # => "sheep"
@@ -28,7 +27,6 @@ module ActiveSupport
# The reverse of +pluralize+, returns the singular form of a word in a string.
#
- # Examples:
# "posts".singularize # => "post"
# "octopi".singularize # => "octopus"
# "sheep".singularize # => "sheep"
@@ -43,7 +41,6 @@ module ActiveSupport
#
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
#
- # Examples:
# "active_model".camelize # => "ActiveModel"
# "active_model".camelize(:lower) # => "activeModel"
# "active_model/errors".camelize # => "ActiveModel::Errors"
@@ -67,7 +64,6 @@ module ActiveSupport
#
# Changes '::' to '/' to convert namespaces to paths.
#
- # Examples:
# "ActiveModel".underscore # => "active_model"
# "ActiveModel::Errors".underscore # => "active_model/errors"
#
@@ -89,7 +85,6 @@ module ActiveSupport
# Capitalizes the first word and turns underscores into spaces and strips a
# trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
#
- # Examples:
# "employee_salary" # => "Employee salary"
# "author_id" # => "Author"
def humanize(lower_case_and_underscored_word)
@@ -108,7 +103,6 @@ module ActiveSupport
#
# +titleize+ is also aliased as +titlecase+.
#
- # Examples:
# "man from the boondocks".titleize # => "Man From The Boondocks"
# "x-men: the last stand".titleize # => "X Men: The Last Stand"
# "TheManWithoutAPast".titleize # => "The Man Without A Past"
@@ -120,7 +114,6 @@ module ActiveSupport
# Create the name of a table like Rails does for models to table names. This method
# uses the +pluralize+ method on the last word in the string.
#
- # Examples
# "RawScaledScorer".tableize # => "raw_scaled_scorers"
# "egg_and_ham".tableize # => "egg_and_hams"
# "fancyCategory".tableize # => "fancy_categories"
@@ -132,7 +125,6 @@ module ActiveSupport
# Note that this returns a string and not a Class. (To convert to an actual class
# follow +classify+ with +constantize+.)
#
- # Examples:
# "egg_and_hams".classify # => "EggAndHam"
# "posts".classify # => "Post"
#
@@ -145,7 +137,6 @@ module ActiveSupport
# Replaces underscores with dashes in the string.
#
- # Example:
# "puni_puni".dasherize # => "puni-puni"
def dasherize(underscored_word)
underscored_word.tr('_', '-')
@@ -183,7 +174,6 @@ module ActiveSupport
# +separate_class_name_and_id_with_underscore+ sets whether
# the method should put '_' between the name and 'id'.
#
- # Examples:
# "Message".foreign_key # => "message_id"
# "Message".foreign_key(false) # => "messageid"
# "Admin::Post".foreign_key # => "post_id"
@@ -253,7 +243,6 @@ module ActiveSupport
# Returns the suffix that should be added to a number to denote the position
# in an ordered sequence such as 1st, 2nd, 3rd, 4th.
#
- # Examples:
# ordinal(1) # => "st"
# ordinal(2) # => "nd"
# ordinal(1002) # => "nd"
@@ -276,7 +265,6 @@ module ActiveSupport
# Turns a number into an ordinal string used to denote the position in an
# ordered sequence such as 1st, 2nd, 3rd, 4th.
#
- # Examples:
# ordinalize(1) # => "1st"
# ordinalize(2) # => "2nd"
# ordinalize(1002) # => "1002nd"
@@ -302,7 +290,6 @@ module ActiveSupport
# Applies inflection rules for +singularize+ and +pluralize+.
#
- # Examples:
# apply_inflections("post", inflections.plurals) # => "posts"
# apply_inflections("posts", inflections.singulars) # => "post"
def apply_inflections(word, rules)
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index 40e7a0e389..a372b6d1f7 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -66,8 +66,6 @@ module ActiveSupport
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
#
- # ==== Examples
- #
# class Person
# def to_param
# "#{id}-#{name.parameterize}"
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index ab12f3f454..a6e4e7ced2 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -136,7 +136,7 @@ module ActiveSupport
end
self.use_standard_json_time_format = true
- self.escape_html_entities_in_json = false
+ self.escape_html_entities_in_json = true
self.encode_big_decimal_as_string = true
end
end
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 7b7fc81e6c..b65ea6208c 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -61,8 +61,12 @@ module ActiveSupport
@logged = Hash.new { |h,k| h[k] = [] }
end
- def method_missing(level, message)
- @logged[level] << message
+ def method_missing(level, message = nil)
+ if block_given?
+ @logged[level] << yield
+ else
+ @logged[level] << message
+ end
end
def logged(level)
diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb
index 5efe13c537..977fe95dbe 100644
--- a/activesupport/lib/active_support/multibyte.rb
+++ b/activesupport/lib/active_support/multibyte.rb
@@ -7,7 +7,6 @@ module ActiveSupport #:nodoc:
# class so you can support other encodings. See the ActiveSupport::Multibyte::Chars implementation for
# an example how to do this.
#
- # Example:
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
def self.proxy_class=(klass)
@proxy_class = klass
@@ -18,4 +17,4 @@ module ActiveSupport #:nodoc:
@proxy_class ||= ActiveSupport::Multibyte::Chars
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index b20c980f36..4fe925f7f4 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -74,7 +74,6 @@ module ActiveSupport #:nodoc:
# Works just like <tt>String#split</tt>, with the exception that the items in the resulting list are Chars
# instances instead of String. This makes chaining methods easier.
#
- # Example:
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
def split(*args)
@wrapped_string.split(*args).map { |i| i.mb_chars }
@@ -88,7 +87,6 @@ module ActiveSupport #:nodoc:
# Reverses all characters in the string.
#
- # Example:
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
def reverse
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*'))
@@ -97,7 +95,6 @@ module ActiveSupport #:nodoc:
# Limits the byte size of the string to a number of bytes without breaking characters. Usable
# when the storage for a string is limited for some reason.
#
- # Example:
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
def limit(limit)
slice(0...translate_offset(limit))
@@ -105,7 +102,6 @@ module ActiveSupport #:nodoc:
# Converts characters in the string to uppercase.
#
- # Example:
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
def upcase
chars Unicode.upcase(@wrapped_string)
@@ -113,7 +109,6 @@ module ActiveSupport #:nodoc:
# Converts characters in the string to lowercase.
#
- # Example:
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
def downcase
chars Unicode.downcase(@wrapped_string)
@@ -121,7 +116,6 @@ module ActiveSupport #:nodoc:
# Converts characters in the string to the opposite case.
#
- # Example:
# 'El Cañón".mb_chars.swapcase.to_s # => "eL cAÑÓN"
def swapcase
chars Unicode.swapcase(@wrapped_string)
@@ -129,7 +123,6 @@ module ActiveSupport #:nodoc:
# Converts the first character to uppercase and the remainder to lowercase.
#
- # Example:
# 'über'.mb_chars.capitalize.to_s # => "Über"
def capitalize
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
@@ -137,7 +130,6 @@ module ActiveSupport #:nodoc:
# Capitalizes the first letter of every word, when possible.
#
- # Example:
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
# "日本語".mb_chars.titleize # => "日本語"
def titleize
@@ -157,7 +149,6 @@ module ActiveSupport #:nodoc:
# Performs canonical decomposition on all the characters.
#
- # Example:
# 'é'.length # => 2
# 'é'.mb_chars.decompose.to_s.length # => 3
def decompose
@@ -166,7 +157,6 @@ module ActiveSupport #:nodoc:
# Performs composition on all the characters.
#
- # Example:
# 'é'.length # => 3
# 'é'.mb_chars.compose.to_s.length # => 2
def compose
@@ -175,7 +165,6 @@ module ActiveSupport #:nodoc:
# Returns the number of grapheme clusters in the string.
#
- # Example:
# 'क्षि'.mb_chars.length # => 4
# 'क्षि'.mb_chars.grapheme_length # => 3
def grapheme_length
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index cb89d45c92..678f551193 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -15,7 +15,6 @@ module ActiveSupport
# The default normalization used for operations that require normalization. It can be set to any of the
# normalizations in NORMALIZATION_FORMS.
#
- # Example:
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
attr_accessor :default_normalization_form
@default_normalization_form = :kc
@@ -72,7 +71,6 @@ module ActiveSupport
# Unpack the string at grapheme boundaries. Returns a list of character lists.
#
- # Example:
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
def unpack_graphemes(string)
@@ -107,7 +105,6 @@ module ActiveSupport
# Reverse operation of unpack_graphemes.
#
- # Example:
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
def pack_graphemes(unpacked)
unpacked.flatten.pack('U*')
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 8edd3960c7..1a3693f766 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -5,16 +5,20 @@ YAML.add_builtin_type("omap") do |type, val|
end
module ActiveSupport
- # The order of iteration over hashes in Ruby 1.8 is undefined. For example, you do not know the
- # order in which +keys+ will return keys, or +each+ yield pairs. <tt>ActiveSupport::OrderedHash</tt>
- # implements a hash that preserves insertion order, as in Ruby 1.9:
+ # <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
+ # insertion order.
#
# oh = ActiveSupport::OrderedHash.new
# oh[:a] = 1
# oh[:b] = 2
# oh.keys # => [:a, :b], this order is guaranteed
#
- # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with other implementations.
+ # Also, maps the +omap+ feature for YAML files
+ # (See http://yaml.org/type/omap.html) to support ordered items
+ # when loading from yaml.
+ #
+ # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
+ # with other implementations.
class OrderedHash < ::Hash
def to_yaml_type
"!tag:yaml.org,2002:omap"
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
index 538a36f6d9..5e080df518 100644
--- a/activesupport/lib/active_support/tagged_logging.rb
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -3,7 +3,7 @@ require 'logger'
require 'active_support/logger'
module ActiveSupport
- # Wraps any standard Logger object to provide tagging capabilities. Examples:
+ # Wraps any standard Logger object to provide tagging capabilities.
#
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
# logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff"
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index cd07c24257..67ac1b6ccd 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -8,7 +8,6 @@ module ActiveSupport
#
# You shouldn't ever need to create a TimeWithZone instance directly via <tt>new</tt> . Instead use methods
# +local+, +parse+, +at+ and +now+ on TimeZone instances, and +in_time_zone+ on Time and DateTime instances.
- # Examples:
#
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
# Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
@@ -20,7 +19,6 @@ module ActiveSupport
# See Time and TimeZone for further documentation of these methods.
#
# TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangeable.
- # Examples:
#
# t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
# t.hour # => 13
@@ -122,8 +120,6 @@ module ActiveSupport
# %Y/%m/%d %H:%M:%S +offset style by setting <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
# to false.
#
- # ==== Examples
- #
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
# # => "2005-02-01T15:15:10Z"
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 9543e50395..28bc06f103 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -176,7 +176,7 @@ module ActiveSupport
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
# Assumes self represents an offset from UTC in seconds (as returned from Time#utc_offset)
- # and turns this into an +HH:MM formatted string. Example:
+ # and turns this into an +HH:MM formatted string.
#
# TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00"
def self.seconds_to_utc_offset(seconds, colon = true)
@@ -239,7 +239,7 @@ module ActiveSupport
"(GMT#{formatted_offset}) #{name}"
end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example:
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values.
#
# Time.zone = "Hawaii" # => "Hawaii"
# Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
@@ -248,7 +248,7 @@ module ActiveSupport
ActiveSupport::TimeWithZone.new(nil, self, time)
end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch. Example:
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch.
#
# Time.zone = "Hawaii" # => "Hawaii"
# Time.utc(2000).to_f # => 946684800.0
@@ -258,7 +258,7 @@ module ActiveSupport
utc.in_time_zone(self)
end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example:
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string.
#
# Time.zone = "Hawaii" # => "Hawaii"
# Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
@@ -271,7 +271,12 @@ module ActiveSupport
date_parts = Date._parse(str)
return if date_parts.empty?
time = Time.parse(str, now) rescue DateTime.parse(str)
+
if date_parts[:offset].nil?
+ if date_parts[:hour] && time.hour != date_parts[:hour]
+ time = DateTime.parse(str)
+ end
+
ActiveSupport::TimeWithZone.new(nil, self, time)
else
time.in_time_zone(self)
@@ -279,7 +284,7 @@ module ActiveSupport
end
# Returns an ActiveSupport::TimeWithZone instance representing the current time
- # in the time zone represented by +self+. Example:
+ # in the time zone represented by +self+.
#
# Time.zone = 'Hawaii' # => "Hawaii"
# Time.zone.now # => Wed, 23 Jan 2008 20:24:27 HST -10:00
diff --git a/activesupport/test/core_ext/duplicable_test.rb b/activesupport/test/core_ext/duplicable_test.rb
index 1105353e45..e0566e012c 100644
--- a/activesupport/test/core_ext/duplicable_test.rb
+++ b/activesupport/test/core_ext/duplicable_test.rb
@@ -5,8 +5,8 @@ require 'active_support/core_ext/numeric/time'
class DuplicableTest < ActiveSupport::TestCase
RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, 5.seconds]
- YES = ['1', Object.new, /foo/, [], {}, Time.now]
- NO = [Class.new, Module.new]
+ YES = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new]
+ NO = []
begin
bd = BigDecimal.new('4.56')
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 9010a4a716..eee2caa60e 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -439,6 +439,30 @@ class OutputSafetyTest < ActiveSupport::TestCase
assert @other_string.html_safe?
end
+ test "Concatting safe onto unsafe with % yields unsafe" do
+ @other_string = "other%s"
+ string = @string.html_safe
+
+ @other_string = @other_string % string
+ assert !@other_string.html_safe?
+ end
+
+ test "Concatting unsafe onto safe with % yields escaped safe" do
+ @other_string = "other%s".html_safe
+ string = @other_string % "<foo>"
+
+ assert_equal "other&lt;foo&gt;", string
+ assert string.html_safe?
+ end
+
+ test "Concatting safe onto safe with % yields safe" do
+ @other_string = "other%s".html_safe
+ string = @string.html_safe
+
+ @other_string = @other_string % string
+ assert @other_string.html_safe?
+ end
+
test "Concatting a fixnum to safe always yields safe" do
string = @string.html_safe
string = string.concat(13)
diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb
index 4d10cfca25..9fa1f417e4 100644
--- a/activesupport/test/inflector_test_cases.rb
+++ b/activesupport/test/inflector_test_cases.rb
@@ -47,6 +47,7 @@ module InflectorTestCases
"medium" => "media",
"stadium" => "stadia",
"analysis" => "analyses",
+ "my_analysis" => "my_analyses",
"node_child" => "node_children",
"child" => "children",
diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb
index 8e160714b1..2a0e8d20ed 100644
--- a/activesupport/test/log_subscriber_test.rb
+++ b/activesupport/test/log_subscriber_test.rb
@@ -11,7 +11,7 @@ class MyLogSubscriber < ActiveSupport::LogSubscriber
def foo(event)
debug "debug"
- info "info"
+ info { "info" }
warn "warn"
end
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index d14d01dc30..b9434489bb 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -203,6 +203,24 @@ class TimeZoneTest < ActiveSupport::TestCase
assert_equal Time.utc(1999,12,31,19), twz.time
end
+ def test_parse_should_not_black_out_system_timezone_dst_jump
+ zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)']
+ zone.stubs(:now).returns(zone.now)
+ Time.stubs(:parse).with('2012-03-25 03:29', zone.now).
+ returns(Time.local(0,29,4,25,3,2012,nil,nil,true,"+03:00"))
+ twz = zone.parse('2012-03-25 03:29')
+ assert_equal [0, 29, 3, 25, 3, 2012], twz.to_a[0,6]
+ end
+
+ def test_parse_should_black_out_app_timezone_dst_jump
+ zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)']
+ zone.stubs(:now).returns(zone.now)
+ Time.stubs(:parse).with('2012-03-11 02:29', zone.now).
+ returns(Time.local(0,29,2,11,3,2012,nil,nil,false,"+02:00"))
+ twz = zone.parse('2012-03-11 02:29')
+ assert_equal [0, 29, 3, 11, 3, 2012], twz.to_a[0,6]
+ end
+
def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize
tzinfo = TZInfo::Timezone.get('America/New_York')
zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo)
diff --git a/guides/source/active_model_basics.textile b/guides/source/active_model_basics.textile
index f140a8d2ac..d373f4ac85 100644
--- a/guides/source/active_model_basics.textile
+++ b/guides/source/active_model_basics.textile
@@ -20,7 +20,7 @@ class Person
attribute_method_prefix 'reset_'
attribute_method_suffix '_highest?'
- define_attribute_methods ['age']
+ define_attribute_methods 'age'
attr_accessor :age
@@ -99,7 +99,7 @@ require 'active_model'
class Person
include ActiveModel::Dirty
- define_attribute_methods [:first_name, :last_name]
+ define_attribute_methods :first_name, :last_name
def first_name
@first_name
diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile
index a9cb424eaa..294ef25b33 100644
--- a/guides/source/active_record_querying.textile
+++ b/guides/source/active_record_querying.textile
@@ -1260,6 +1260,24 @@ with
Client.pluck(:id)
</ruby>
+h3. +ids+
+
++ids+ can be used to pluck all the IDs for the relation using the table's primary key.
+
+<ruby>
+Person.ids
+# SELECT id FROM people
+</ruby>
+
+<ruby>
+class Person < ActiveRecord::Base
+ self.primary_key = "person_id"
+end
+
+Person.ids
+# SELECT person_id FROM people
+</ruby>
+
h3. Existence of Objects
If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+.
diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile
index 8045316e98..6443255f5d 100644
--- a/guides/source/active_support_core_extensions.textile
+++ b/guides/source/active_support_core_extensions.textile
@@ -1277,20 +1277,6 @@ The <tt>inquiry</tt> method converts a string into a +StringInquirer+ object mak
"active".inquiry.inactive? # => false
</ruby>
-h4. Key-based Interpolation
-
-In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted:
-
-<ruby>
-"Total is %<total>.02f" % {:total => 43.1} # => Total is 43.10
-"I say %{foo}" % {:foo => "wadus"} # => "I say wadus"
-"I say %{woo}" % {:foo => "wadus"} # => KeyError
-</ruby>
-
-Active Support adds that functionality to <tt>%</tt> in previous versions of Ruby.
-
-NOTE: Defined in +active_support/core_ext/string/interpolation.rb+.
-
h4. +starts_with?+ and +ends_with?+
Active Support defines 3rd person aliases of +String#start_with?+ and +String#end_with?+:
@@ -1337,7 +1323,7 @@ Returns the character of the string at position +position+:
"hello".at(0) # => "h"
"hello".at(4) # => "o"
"hello".at(-1) # => "o"
-"hello".at(10) # => ERROR if < 1.9, nil in 1.9
+"hello".at(10) # => nil
</ruby>
NOTE: Defined in +active_support/core_ext/string/access.rb+.
@@ -1819,7 +1805,7 @@ NOTE: Defined in +active_support/core_ext/numeric/bytes.rb+.
h4. Time
-Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
+Enables the use of time calculations and declarations, like @45.minutes <plus> 2.hours <plus> 4.years@.
These methods use Time#advance for precise date calculations when using from_now, ago, etc.
as well as adding or subtracting their results from a Time object. For example:
@@ -2767,18 +2753,6 @@ As the example depicts, the +:db+ format generates a +BETWEEN+ SQL clause. That
NOTE: Defined in +active_support/core_ext/range/conversions.rb+.
-h4. +step+
-
-Active Support extends the method +Range#step+ so that it can be invoked without a block:
-
-<ruby>
-(1..10).step(2) # => [1, 3, 5, 7, 9]
-</ruby>
-
-As the example shows, in that case the method returns an array with the corresponding elements.
-
-NOTE: Defined in +active_support/core_ext/range/blockless_step.rb+.
-
h4. +include?+
The methods +Range#include?+ and +Range#===+ say whether some value falls between the ends of a given instance:
diff --git a/guides/source/ajax_on_rails.textile b/guides/source/ajax_on_rails.textile
index cda9c64460..bfd007490a 100644
--- a/guides/source/ajax_on_rails.textile
+++ b/guides/source/ajax_on_rails.textile
@@ -78,7 +78,7 @@ will produce
<ruby>
button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
- :method => "delete", :remote => true, :disable_with => 'loading...')
+ :method => "delete", :remote => true, 'data-disable-with' => 'loading...')
</ruby>
will produce
@@ -87,7 +87,7 @@ will produce
<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
<div>
<input name='_method' value='delete' type='hidden' />
- <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
+ <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
</div>
</form>
</html>
diff --git a/guides/source/asset_pipeline.textile b/guides/source/asset_pipeline.textile
index 010154f1d1..105efe229e 100644
--- a/guides/source/asset_pipeline.textile
+++ b/guides/source/asset_pipeline.textile
@@ -396,7 +396,7 @@ Rails comes bundled with a rake task to compile the asset manifests and other fi
Compiled assets are written to the location specified in +config.assets.prefix+. By default, this is the +public/assets+ directory.
-You can call this task on the server during deployment to create compiled versions of your assets directly on the server. If you do not have write access to your production file system, you can call this task locally and then deploy the compiled assets.
+You can call this task on the server during deployment to create compiled versions of your assets directly on the server. See the next section for information on compiling locally.
The rake task is:
@@ -516,6 +516,41 @@ If you're compiling nginx with Phusion Passenger you'll need to pass that option
A robust configuration for Apache is possible but tricky; please Google around. (Or help update this Guide if you have a good example configuration for Apache.)
+h4. Local Precompilation
+
+There are several reasons why you might want to precompile your assets locally. Among them are:
+
+* You may not have write access to your production file system.
+* You may be deploying to more than one server, and want to avoid the duplication of work.
+* You may be doing frequent deploys that do not include asset changes.
+
+Local compilation allows you to commit the compiled files into source control, and deploy as normal.
+
+There are two caveats:
+
+* You must not run the Capistrano deployment task that precompiles assets.
+* You must change the following two application configuration settings.
+
+In <tt>config/environments/development.rb</tt>, place the following line:
+
+<erb>
+config.assets.prefix = "/dev-assets"
+</erb>
+
+You will also need this in application.rb:
+
+<erb>
+config.assets.initialize_on_precompile = false
+</erb>
+
+The +prefix+ change makes Rails use a different URL for serving assets in development mode, and pass all requests to Sprockets. The prefix is still set to +/assets+ in the production environment. Without this change, the application would serve the precompiled assets from +public/assets+ in development, and you would not see any local changes until you compile assets again.
+
+The +initialize_on_precompile+ change tells the precompile task to run without invoking Rails. This is because the precompile task runs in production mode by default, and will attempt to connect to your specified production database. Please note that you cannot have code in pipeline files that relies on Rails resources (such as the database) when compiling locally with this option.
+
+You will also need to ensure that any compressors or minifiers are available on your development system.
+
+In practice, this will allow you to precompile locally, have those files in your working tree, and commit those files to source control when needed. Development mode will work as expected.
+
h4. Live Compilation
In some circumstances you may wish to use live compilation. In this mode all requests for assets in the pipeline are handled by Sprockets directly.
diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile
index b2c9300034..f114075cae 100644
--- a/guides/source/configuring.textile
+++ b/guides/source/configuring.textile
@@ -597,7 +597,7 @@ Rails has 5 initialization events which can be hooked into (listed in the order
* +to_prepare+: Run after the initializers are run for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in +development+, but only once (during boot-up) in +production+ and +test+.
-* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment.
+* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the +production+ environment and not for the +development+ environment.
* +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run.
diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile
index 1e9bd1f144..19bd106ff0 100644
--- a/guides/source/getting_started.textile
+++ b/guides/source/getting_started.textile
@@ -183,9 +183,9 @@ Rails will create several files for you. Most important of these are of course t
Open the +app/views/welcome/index.html.erb+ file in your text editor and edit it to contain a single line of code:
-<code class="html">
+<html>
<h1>Hello, Rails!</h1>
-</code>
+</html>
h4. Setting the Application Home Page
@@ -193,7 +193,7 @@ Now that we have made the controller and view, we need to tell Rails when we wan
To fix this, delete the +index.html+ file located inside the +public+ directory of the application.
-You need to do this because Rails will serve any static file in the +public+ directory that matches a route in preference to any dynamic content you generate from the controllers.
+You need to do this because Rails will serve any static file in the +public+ directory that matches a route in preference to any dynamic content you generate from the controllers. The +index.html+ file is special: it will be served if a request comes in at the root route, e.g. http://localhost:3000. If another request such as http://localhost:3000/welcome happened, a static file at <tt>public/welcome.html</tt> would be served first, but only if it existed.
Next, you have to tell Rails where your actual home page is located.
@@ -210,7 +210,7 @@ Blog::Application.routes.draw do
The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+).
-If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see +Hello, Rails!+.
+If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see the +Hello, Rails!+ message you put into +app/views/welcome/index.html.erb+, indicating that this new route is indeed going to +WelcomeController+'s +index+ action and is rendering the view correctly.
NOTE. For more information about routing, refer to "Rails Routing from the Outside In":routing.html.
@@ -220,7 +220,7 @@ Now that you've seen how to create a controller, an action and a view, let's cre
In the Blog application, you will now create a new _resource_. A resource is the term used for a collection of similar objects, such as posts, people or animals. You can create, read, update and destroy items for a resource and these operations are referred to as _CRUD_ operations.
-In the next section, you will add the ability to create new posts in your application and be able to view them. This is the "CR" from CRUD. The form for doing this will look like this:
+In the next section, you will add the ability to create new posts in your application and be able to view them. This is the "C" and the "R" from CRUD: creation and reading. The form for doing this will look like this:
!images/getting_started/new_post.png(The new post form)!
@@ -232,7 +232,7 @@ The first thing that you are going to need to create a new post within the appli
!images/getting_started/routing_error_no_route_matches.png(A routing error, no route matches /posts/new)!
-This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, and so you must define your routes as you need them.
+This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, besides the root route you defined earlier, and so you must define your routes as you need them.
To do this, you're going to need to create a route inside +config/routes.rb+ file, on a new line between the +do+ and the +end+ for the +draw+ method:
@@ -282,9 +282,9 @@ You're getting this error now because Rails expects plain actions like this one
In the above image, the bottom line has been truncated. Let's see what the full thing looks like:
-<text>
+<blockquote>
Missing template posts/new, application/new with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "/path/to/blog/app/views"
-</text>
+</blockquote>
That's quite a lot of text! Let's quickly go through and understand what each part of it does.
@@ -330,11 +330,17 @@ method called +form_for+. To use this method, add this code into +app/views/post
If you refresh the page now, you'll see the exact same form as in the example. Building forms in Rails is really just that easy!
-When you call +form_for+, you pass it an identifying object for this form. In this case, it's the symbol +:post+. This tells the +form_for+ helper what this form is for. Inside the block for this method, the FormBuilder object -- represented by +f+ -- is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to +submit+ on the +f+ object will create a submit button for the form.
+When you call +form_for+, you pass it an identifying object for this
+form. In this case, it's the symbol +:post+. This tells the +form_for+
+helper what this form is for. Inside the block for this method, the
++FormBuilder+ object -- represented by +f+ -- is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to +submit+ on the +f+ object will create a submit button for the form.
There's one problem with this form though. If you inspect the HTML that is generated, by viewing the source of the page, you will see that the +action+ attribute for the form is pointing at +/posts/new+. This is a problem because this route goes to the very page that you're on right at the moment, and that route should only be used to display the form for a new post.
-So the form needs to use a different URL in order to go somewhere else. This can be done quite simply with the +:url+ option of +form_for+. Typically in Rails, the action that is used for new form submissions like this is called "create", and so the form should be pointed to this action.
+The form needs to use a different URL in order to go somewhere else.
+This can be done quite simply with the +:url+ option of +form_for+.
+Typically in Rails, the action that is used for new form submissions
+like this is called "create", and so the form should be pointed to that action.
Edit the +form_for+ line inside +app/views/posts/new.html.erb+ to look like this:
@@ -350,11 +356,11 @@ post "posts/create"
By using the +post+ method rather than the +get+ method, Rails will define a route that will only respond to POST methods. The POST method is the typical method used by forms all over the web.
-With the form and the route for it defined now, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error:
+With the form and its associated route defined, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error:
!images/getting_started/unknown_action_create_for_posts.png(Unknown action create for PostsController)!
-You will now need to create the +create+ action within the +PostsController+ for this to work.
+You now need to create the +create+ action within the +PostsController+ for this to work.
h4. Creating posts
@@ -381,7 +387,7 @@ def create
end
</ruby>
-The +render+ method here is taking a very simple hash with the key of +text+ and the value of +params[:post].inspect+. The +params+ method here is the object which represents the parameters (or fields) coming in from the form. The +params+ method returns a +HashWithIndifferentAccess+ object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form.
+The +render+ method here is taking a very simple hash with a key of +text+ and value of +params[:post].inspect+. The +params+ method is the object which represents the parameters (or fields) coming in from the form. The +params+ method returns a +HashWithIndifferentAccess+ object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form.
If you re-submit the form one more time you'll now no longer get the missing template error. Instead, you'll see something that looks like the following:
@@ -402,16 +408,22 @@ To create the new model, run this command in your terminal:
$ rails generate model Post title:string text:text
</shell>
-With that command we told Rails that we want a +Post+ model, which in
-turn should have a title attribute of type string, and a text attribute
+With that command we told Rails that we want a +Post+ model, together
+with a _title_ attribute of type string, and a _text_ attribute
of type text. Those attributes are automatically added to the +posts+
table in the database and mapped to the +Post+ model.
-Rails in turn responded by creating a bunch of files. For
+Rails responded by creating a bunch of files. For
now, we're only interested in +app/models/post.rb+ and
-+db/migrate/20120419084633_create_posts.rb+. The latter is responsible
++db/migrate/20120419084633_create_posts.rb+ (your name could be a bit
+different). The latter is responsible
for creating the database structure, which is what we'll look at next.
+TIP: Active Record is smart enough to automatically map column names to
+model attributes, which means you don't have to declare attributes
+inside Rails models, as that will be done automatically by Active
+Record.
+
h4. Running a Migration
As we've just seen, +rails generate model+ created a _database
@@ -472,8 +484,8 @@ invoking the command: +rake db:migrate RAILS_ENV=production+.
h4. Saving data in the controller
Back in +posts_controller+, we need to change the +create+ action
-to use the new +Post+ model to save data in the database. Open that file
-and change the +create+ action to look like the following:
+to use the new +Post+ model to save the data in the database. Open that file
+and change the +create+ action to look like this:
<ruby>
def create
@@ -485,22 +497,21 @@ end
</ruby>
Here's what's going on: every Rails model can be initialized with its
-respective attributes, which are automatically mapped to its
+respective attributes, which are automatically mapped to the respective
database columns. In the first line we do just that (remember that
+params[:post]+ contains the attributes we're interested in). Then,
+@post.save+ is responsible for saving the model in the database.
-Finally, on the last line we redirect the user to the +show+ action,
-wich we have not defined yet.
+Finally, we redirect the user to the +show+ action,
+wich we'll define later.
TIP: As we'll see later, +@post.save+ returns a boolean indicating
-wherever the model was saved or not, and you can (and usually do) take
-different actions depending on the result of calling +@post.save+.
+wherever the model was saved or not.
-h4. Showing posts
+h4. Showing Posts
-Before trying to create a new post, let's add the +show+ action, which
-will be responsible for showing our posts. Open +config/routes.rb+
-and add the following route:
+If you submit the form again now, Rails will complain about not finding
+the +show+ action. That's not very useful though, so let's add the
++show+ action before proceeding. Open +config/routes.rb+ and add the following route:
<ruby>
get "posts/:id" => "posts#show"
@@ -549,19 +560,21 @@ be able to create a post. Try it!
h4. Listing all posts
We still need a way to list all our posts, so let's do that. As usual,
-we'll need a route, a controller action, and a view:
+we'll need a route placed into +config/routes.rb+:
<ruby>
-# Add to config/routes.rb
get "posts" => "posts#index"
+</ruby>
+
+And an action for that route inside the +PostsController+ in the +app/controllers/posts_controller.rb+ file:
-# Add to app/controllers/posts_controller.rb
+<ruby>
def index
@posts = Post.all
end
</ruby>
-+app/view/posts/index.html.erb+:
+And then finally a view for this action, located at +app/views/posts/index.html.erb+:
<erb>
<h1>Listing posts</h1>
@@ -572,15 +585,17 @@ end
<th>Text</th>
</tr>
-<% @posts.each do |post| %>
- <tr>
- <td><%= post.title %></td>
- <td><%= post.text %></td>
- </tr>
-<% end %>
+ <% @posts.each do |post| %>
+ <tr>
+ <td><%= post.title %></td>
+ <td><%= post.text %></td>
+ </tr>
+ <% end %>
</table>
</erb>
+Now if you go to +http://localhost:3000/posts+ you will see a list of all the posts that you have created.
+
h4. Adding links
You can now create, show, and list posts. Now let's add some links to
@@ -597,41 +612,25 @@ The +link_to+ method is one of Rails' built-in view helpers. It creates a
hyperlink based on text to display and where to go - in this case, to the path
for posts.
-Let's add links to the other views as well.
+Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +<table>+ tag:
<erb>
-# app/views/posts/index.html.erb
-
-<h1>Listing posts</h1>
-
<%= link_to 'New post', :action => :new %>
+</erb>
-<table>
- <tr>
- <th>Title</th>
- <th>Text</th>
- <th></th>
- </tr>
-
-<% @posts.each do |post| %>
- <tr>
- <td><%= post.title %></td>
- <td><%= post.text %></td>
- <td><%= link_to 'Show', :action => :show, :id => post.id %></td>
- </tr>
-<% end %>
-</table>
-
-# app/views/posts/new.html.erb
+This link will allow you to bring up the form that lets you create a new post. You should also add a link to this template -- +app/views/posts/new.html.erb+ -- to go back to the +index+ action. Do this by adding this underneath the form in this template:
+<erb>
<%= form_for :post do |f| %>
...
<% end %>
<%= link_to 'Back', :action => :index %>
+</erb>
-# app/views/posts/show.html.erb
+Finally, add another link to the +app/views/posts/show.html.erb+ template to go back to the +index+ action as well, so that people who are viewing a single post can go back and view the whole list again:
+<erb>
<p>
<strong>Title:</strong>
<%= @post.title %>
@@ -653,7 +652,7 @@ TIP: In development mode (which is what you're working in by default), Rails
reloads your application with every browser request, so there's no need to stop
and restart the web server when a change is made.
-h4. Adding Some Validation
+h4. Allowing the update of fields
The model file, +app/models/post.rb+ is about as simple as it can get:
@@ -668,11 +667,28 @@ your Rails models for free, including basic database CRUD (Create, Read, Update,
Destroy) operations, data validation, as well as sophisticated search support
and the ability to relate multiple models to one another.
+Rails includes methods to help you secure some of your model fields.
+Open the +app/models/post.rb+ file and edit it:
+
+<ruby>
+class Post < ActiveRecord::Base
+ attr_accessible :text, :title
+end
+</ruby>
+
+This change will ensure that all changes made through HTML forms can edit the content of the text and title fields.
+It will not be possible to define any other field value through forms. You can still define them by calling the `field=` method of course.
+Accessible attributes and the mass assignment probem is covered in details in the "Security guide":security.html#mass-assignment
+
+h4. Adding Some Validation
+
Rails includes methods to help you validate the data that you send to models.
Open the +app/models/post.rb+ file and edit it:
<ruby>
class Post < ActiveRecord::Base
+ attr_accessible :text, :title
+
validates :title, :presence => true,
:length => { :minimum => 5 }
end
@@ -684,9 +700,12 @@ format, and the existence of associated objects. Validations are covered in deta
in "Active Record Validations and
Callbacks":active_record_validations_callbacks.html#validations-overview
-If you open +posts_controller+ again, you'll notice that we don't check
-the result of calling +@post.save+. We need to change its behavior to
-show the form back to the user if any error occur:
+With the validation now in place, when you call +@post.save+ on an invalid
+post, it will return +false+. If you open +app/controllers/posts_controller.rb+
+again, you'll notice that we don't check the result of calling +@post.save+
+inside the +create+ action. If +@post.save+ fails in this situation, we need to
+show the form back to the user. To do this, change the +new+ and +create+
+actions inside +app/controllers/posts_controller.rb+ to these:
<ruby>
def new
@@ -704,13 +723,11 @@ def create
end
</ruby>
-Notice that I've also added +@post = Post.new+ to the +new+ action. I'll
-explain why I did that in the next section, for now add that to your
-controller as well.
+The +new+ action is now creating a new instance variable called +@post+, and
+you'll see why that is in just a few moments.
-Also notice that we use +render+ instead of +redirect_to+ when +save+
-returns false. We can use +render+ so that the +@post+ object is passed
-back to the view.
+Notice that inside the +create+ action we use +render+ instead of +redirect_to+ when +save+
+returns +false+. The +render+ method is used so that the +@post+ object is passed back to the +new+ template when it is rendered. This rendering is done within the same request as the form submission, whereas the +redirect_to+ will tell the browser to issue another request.
If you reload
"http://localhost:3000/posts/new":http://localhost:3000/posts/new and
@@ -754,9 +771,8 @@ A few things are going on. We check if there are any errors with
+@post.errors.any?+, and in that case we show a list of all
errors with +@post.errors.full_messages+.
-+pluralize+ is a rails helper
-that takes a number and a string as its arguments. If the number is
-greater than one, the string will be automatically pluralized.
++pluralize+ is a rails helper that takes a number and a string as its
+arguments. If the number is greater than one, the string will be automatically pluralized.
The reason why we added +@post = Post.new+ in +posts_controller+ is that
otherwise +@post+ would be +nil+ in our view, and calling
@@ -766,7 +782,8 @@ TIP: Rails automatically wraps fields that contain an error with a div
with class +field_with_errors+. You can define a css rule to make them
standout.
-Now you'll get a nice error message when saving a post without title:
+Now you'll get a nice error message when saving a post without title when you
+attempt to do just that on the "new post form(http://localhost:3000/posts/new)":http://localhost:3000/posts/new.
!images/getting_started/form_with_errors.png(Form With Errors)!
@@ -830,21 +847,23 @@ it look as follows:
<%= link_to 'Back', :action => :index %>
</erb>
-This time we point the form to the +update+ action (not defined yet).
+This time we point the form to the +update+ action, which is not defined yet
+but will be very soon.
+
The +:method => :put+ option tells Rails that we want this form to be
-submitted via +put+, which is the http method you're expected to use to
+submitted via the +PUT+, HTTP method which is the HTTP method you're expected to use to
*update* resources according to the REST protocol.
TIP: By default forms built with the +form_for_ helper are sent via +POST+.
-Moving on, we need to add the +update+ action. The file
+Next, we need to add the +update+ action. The file
+config/routes.rb+ will need just one more line:
<ruby>
put "posts/:id" => "posts#update"
</ruby>
-And the +update+ action in +posts_controller+ itself should not look too complicated by now:
+And then create the +update+ action in +app/controllers/posts_controller.rb+:
<ruby>
def update
@@ -858,7 +877,7 @@ def update
end
</ruby>
-The new method +update_attributes+ is used when you want to update a record
+The new method, +update_attributes+, is used when you want to update a record
that already exists, and it accepts an hash containing the attributes
that you want to update. As before, if there was an error updating the
post we want to show the form back to the user.
@@ -868,11 +887,11 @@ example, if you'd call +@post.update_attributes(:title => 'A new title')+
Rails would only update the +title+ attribute, leaving all other
attributes untouched.
-Finally, we want to show a link to the +edit+ action in the +index+ and
-+show+ views:
+Finally, we want to show a link to the +edit+ action in the list of all the
+posts, so let's add that now to +app/views/posts/index.html.erb+ to make it
+appear next to the "Show" link:
<erb>
-# app/view/posts/index.html.erb
<table>
<tr>
@@ -891,11 +910,16 @@ Finally, we want to show a link to the +edit+ action in the +index+ and
</tr>
<% end %>
</table>
+</erb>
-# app/view/posts/show.html.erb
+And we'll also add one to the +app/views/posts/show.html.erb+ template as well,
+so that there's also an "Edit" link on a post's page. Add this at the bottom of
+the template:
+<erb>
...
+
<%= link_to 'Back', :action => :index %>
| <%= link_to 'Edit', :action => :edit, :id => @post.id %>
</erb>
@@ -924,8 +948,8 @@ simple example:
<%= @user.about_me %>
</erb>
-The +show+ view will automatically include the content of the
-+_user_details+ view. Note that partials are prefixed by an underscore,
+The +users/show+ template will automatically include the content of the
++users/_user_details+ template. Note that partials are prefixed by an underscore,
as to not be confused with regular views. However, you don't include the
underscore when including them with the +helper+ method.
@@ -934,7 +958,7 @@ Rails":layouts_and_rendering.html guide.
Our +edit+ action looks very similar to the +new+ action, in fact they
both share the same code for displaying the form. Lets clean them up by
-using a +_form+ partial.
+using a partial.
Create a new file +app/views/posts/_form.html.erb+ with the following
content:
@@ -944,7 +968,7 @@ content:
<% if @post.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited
- this post from being saved:</h2>
+ this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
@@ -968,23 +992,23 @@ content:
<% end %>
</erb>
-Everything except for the +form_for+ declaration remained the same. I'll
-explain later how +form_for+ can figure out the right +action+ and
-+method+ attributes when building the form, for now let's update the
-+new+ and +edit+ views:
+Everything except for the +form_for+ declaration remained the same.
+How +form_for+ can figure out the right +action+ and +method+ attributes
+when building the form will be explained in just a moment. For now, let's update the
++app/views/posts/new.html.erb+ view to use this new partial, rewriting it
+completely:
<erb>
-# app/views/posts/new.html.erb
-
<h1>New post</h1>
<%= render 'form' %>
<%= link_to 'Back', :action => :index %>
+</erb>
+Then do the same for the +app/views/posts/edit.html.erb+ view:
-# app/views/posts/edit.html.erb
-
+<erb>
<h1>Edit post</h1>
<%= render 'form' %>
@@ -992,8 +1016,7 @@ explain later how +form_for+ can figure out the right +action+ and
<%= link_to 'Back', :action => :index %>
</erb>
-Point your browser to
-"http://localhost:3000/posts/new":http://localhost:3000/posts/new and
+Point your browser to "http://localhost:3000/posts/new":http://localhost:3000/posts/new and
try creating a new post. Everything still works. Now try editing the
post and you'll receive the following error:
@@ -1011,7 +1034,8 @@ knows that it should create new objects via POST and update them via
PUT.
If you run +rake routes+ from the console you'll see that we already
-have a +posts_path+ route, which was created automatically by Rails.
+have a +posts_path+ route, which was created automatically by Rails when we
+defined the route for the index action.
However, we don't have a +post_path+ yet, which is the reason why we
received an error before.
@@ -1034,26 +1058,37 @@ line like this:
get "posts/:id" => "posts#show", :as => :post
</ruby>
-Now you'll be able to update posts again.
+The +:as+ option tells the +get+ method that we want to make routing helpers
+called +post_url+ and +post_path+ available to our application. These are
+precisely the methods that the +form_for+ needs when editing a post, and so now
+you'll be able to update posts again.
+
+NOTE: The +:as+ option is available on the +post+, +put+, +delete+ and +match+
+routing methods also.
h4. Deleting Posts
We're now ready to cover the "D" part of CRUD, deleting posts from the
database. Following the REST convention, we're going to add a route for
-deleting posts:
+deleting posts to +config/routes.rb+:
<ruby>
-# config/routes.rb
-
delete "posts/:id" => "posts#destroy"
</ruby>
-We use the +delete+ method for destroying resources, which is mapped to
-the +destroy+ action, which is provided below:
+The +delete+ routing method should be used for routes that destroy
+resources. If this was left as a typical +get+ route, it could be possible for
+people to craft malicious URLs like this:
-<ruby>
-# app/controllers/posts_controller.rb
+<html>
+<a href='http://yoursite.com/posts/1/destroy'>look at this cat!</a>
+</html>
+We use the +delete+ method for destroying resources, and this route is mapped to
+the +destroy+ action inside +app/controllers/posts_controller.rb+, which doesn't exist yet, but is
+provided below:
+
+<ruby>
def destroy
@post = Post.find(params[:id])
@post.destroy
@@ -1063,13 +1098,15 @@ end
</ruby>
You can call +destroy+ on Active Record objects when you want to delete
-them from the dabase. Note that we don't need to add a view for this
+them from the database. Note that we don't need to add a view for this
action since we're redirecting to the +index+ action.
-Finally, add a 'destroy' link to your +index+ action to wrap everything
+Finally, add a 'destroy' link to your +index+ action template
+(+app/views/posts/index.html.erb) to wrap everything
together.
<erb>
+<h1>Listing Posts</h1>
<table>
<tr>
<th>Title</th>
@@ -1092,11 +1129,14 @@ together.
</erb>
Here we're using +link_to+ in a different way. We wrap the
-+:action+ and +:id+ attributes in a hash so that we can pass other
-arguments to +link_to+. The +:method+ and +:confirm+
++:action+ and +:id+ attributes in a hash so that we can pass those two keys in
+first as one argument, and then the final two keys as another argument. The +:method+ and +:confirm+
options are used as html5 attributes so that when the click is linked,
Rails will first show a confirm dialog to the user, and then submit the
-link with method +delete+. This is done via javascript automatically.
+link with method +delete+. This is done via the JavaScript file +jquery_ujs+
+which is automatically included into your application's layout
+(+app/views/layouts/application.html.erb+) when you generated the application.
+Without this file, the confirmation dialog box wouldn't appear.
!images/getting_started/confirm_dialog.png(Confirm Dialog)!
@@ -1136,7 +1176,7 @@ end
</ruby>
If you run +rake routes+, you'll see that all the routes that we
-declared before are still available, and the app still works as before.
+declared before are still available:
<shell>
# rake routes
@@ -1150,18 +1190,22 @@ edit_post GET /posts/:id/edit(.:format) posts#edit
root / welcome#index
</shell>
+Also, if you go through the motions of creating, updating and deleting
+posts the app still works as before.
+
TIP: In general, Rails encourages the use of resources objects in place
-of declaring routes manually. For more information about routing, see
+of declaring routes manually. It was only done in this guide as a learning
+exercise. For more information about routing, see
"Rails Routing from the Outside In":routing.html.
h3. Adding a Second Model
It's time to add a second model to the application. The second model will handle comments on
-blog posts.
+posts.
h4. Generating a Model
-We're going to se the same generator that we used before when creating
+We're going to see the same generator that we used before when creating
the +Post+ model. This time we'll create a +Comment+ model to hold
reference of post comments. Run this command in your terminal:
@@ -1321,7 +1365,7 @@ So first, we'll wire up the Post show template
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Add a comment:</h2>
@@ -1344,7 +1388,10 @@ So first, we'll wire up the Post show template
</erb>
This adds a form on the +Post+ show page that creates a new comment by
-calling the +CommentsController+ +create+ action. Let's wire that up:
+calling the +CommentsController+ +create+ action. The +form_for+ call here uses
+an array, which will build a nested route, such as +/posts/1/comments+.
+
+Let's wire up the +create+:
<ruby>
class CommentsController < ApplicationController
@@ -1380,7 +1427,7 @@ template. This is where we want the comment to show, so let's add that to the
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Comments</h2>
@@ -1428,7 +1475,7 @@ use partials to clean it up.
h4. Rendering Partial Collections
-First we will make a comment partial to extract showing all the comments for the
+First, we will make a comment partial to extract showing all the comments for the
post. Create the file +app/views/comments/_comment.html.erb+ and put the
following into it:
@@ -1455,7 +1502,7 @@ following:
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Comments</h2>
@@ -1517,7 +1564,7 @@ Then you make the +app/views/posts/show.html.erb+ look like the following:
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Add a comment:</h2>
diff --git a/guides/source/i18n.textile b/guides/source/i18n.textile
index 6179694c40..ee7176a6c8 100644
--- a/guides/source/i18n.textile
+++ b/guides/source/i18n.textile
@@ -127,7 +127,7 @@ If you want to translate your Rails application to a *single language other than
However, you would probably like to *provide support for more locales* in your application. In such case, you need to set and pass the locale between requests.
-WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>. *Do not do so*. The locale should be transparent and a part of the URL. This way you don't break people's basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you're being "<em>RESTful</em>":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. There may be some exceptions to this rule, which are discussed below.
+WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>, however *do not do this*. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being "<em>RESTful</em>":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. Sometimes there are exceptions to this rule and those are discussed below.
The _setting part_ is easy. You can set the locale in a +before_filter+ in the +ApplicationController+ like this:
@@ -220,7 +220,7 @@ Every helper method dependent on +url_for+ (e.g. helpers for named routes like +
You may be satisfied with this. It does impact the readability of URLs, though, when the locale "hangs" at the end of every URL in your application. Moreover, from the architectural standpoint, locale is usually hierarchically above the other parts of the application domain: and URLs should reflect this.
-You probably want URLs to look like this: +www.example.com/en/books+ (which loads the English locale) and +www.example.com/nl/books+ (which loads the Netherlands locale). This is achievable with the "over-riding +default_url_options+" strategy from above: you just have to set up your routes with "+path_prefix+":http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354 option in this way:
+You probably want URLs to look like this: +www.example.com/en/books+ (which loads the English locale) and +www.example.com/nl/books+ (which loads the Dutch locale). This is achievable with the "over-riding +default_url_options+" strategy from above: you just have to set up your routes with "+path_prefix+":http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354 option in this way:
<ruby>
# config/routes.rb
@@ -229,7 +229,7 @@ scope "/:locale" do
end
</ruby>
-Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Netherlands locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed).
+Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Dutch locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed).
If you don't want to force the use of a locale in your routes you can use an optional path scope (denoted by the parentheses) like so:
diff --git a/guides/source/layouts_and_rendering.textile b/guides/source/layouts_and_rendering.textile
index e4a1fd6951..b0a87a5981 100644
--- a/guides/source/layouts_and_rendering.textile
+++ b/guides/source/layouts_and_rendering.textile
@@ -860,12 +860,6 @@ You can supply a hash of additional HTML options:
<%= image_tag "icons/delete.gif", {:height => 45} %>
</erb>
-You can also supply an alternate image to show on mouseover:
-
-<erb>
-<%= image_tag "home.gif", :onmouseover => "menu/home_highlight.gif" %>
-</erb>
-
You can supply alternate text for the image which will be used if the user has images turned off in their browser. If you do not specify an alt text explicitly, it defaults to the file name of the file, capitalized and with no extension. For example, these two image tags would return the same code:
<erb>
diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile
index f855072fd8..52dba76e68 100644
--- a/guides/source/migrations.textile
+++ b/guides/source/migrations.textile
@@ -737,9 +737,7 @@ column.
class AddFlagToProduct < ActiveRecord::Migration
def change
add_column :products, :flag, :boolean
- Product.all.each do |product|
- product.update_attributes!(:flag => false)
- end
+ Product.update_all :flag => false
end
end
</ruby>
@@ -762,9 +760,7 @@ column.
class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
- Product.all.each do |product|
- product.update_attributes! :fuzz => 'fuzzy'
- end
+ Product.update_all :fuzz => 'fuzzy'
end
end
</ruby>
@@ -816,9 +812,7 @@ class AddFlagToProduct < ActiveRecord::Migration
def change
add_column :products, :flag, :boolean
Product.reset_column_information
- Product.all.each do |product|
- product.update_attributes!(:flag => false)
- end
+ Product.update_all :flag => false
end
end
</ruby>
@@ -833,9 +827,7 @@ class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
Product.reset_column_information
- Product.all.each do |product|
- product.update_attributes!(:fuzz => 'fuzzy')
- end
+ Product.update_all :fuzz => 'fuzzy'
end
end
</ruby>
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 01df2c5b64..1f88843ee9 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki*
+
* The application generator generates `public/humans.txt` with some basic data. *Paul Campbell*
* Add `config.queue_consumer` to allow the default consumer to be configurable. *Carlos Antonio da Silva*
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 59c3c56e59..670477f91a 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -107,14 +107,11 @@ module Rails
# * The environment variable RAILS_GROUPS;
# * The optional envs given as argument and the hash with group dependencies;
#
- # == Examples
- #
# groups :assets => [:development, :test]
#
# # Returns
# # => [:default, :development, :assets] for Rails.env == "development"
# # => [:default, :production] for Rails.env == "production"
- #
def groups(*groups)
hash = groups.extract_options!
env = Rails.env
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 9bf9cbe022..47856c87c6 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -39,8 +39,6 @@ module Rails
# and <tt>autoload_once_paths</tt>, which, differently from a <tt>Railtie</tt>, are scoped to
# the current engine.
#
- # Example:
- #
# class MyEngine < Rails::Engine
# # Add a load path for this specific Engine
# config.autoload_paths << File.expand_path("../lib/some/path", __FILE__)
@@ -336,11 +334,8 @@ module Rails
# It will affect the priority of loading views, helpers, assets and all the other files
# related to engine or application.
#
- # Example:
- #
# # load Blog::Engine with highest priority, followed by application and other railties
# config.railties_order = [Blog::Engine, :main_app, :all]
- #
class Engine < Railtie
autoload :Configuration, "rails/engine/configuration"
autoload :Railties, "rails/engine/railties"
@@ -572,8 +567,9 @@ module Rails
end
initializer :load_environment_config, :before => :load_environment_hook, :group => :all do
- environment = paths["config/environments"].existent.first
- require environment if environment
+ paths["config/environments"].existent.each do |environment|
+ require environment
+ end
end
initializer :append_assets_path, :group => :all do |app|
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 55642f8140..4fa990171d 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -95,7 +95,6 @@ module Rails
# some of them are not available by adding a fallback:
#
# Rails::Generators.fallbacks[:shoulda] = :test_unit
- #
def self.fallbacks
@fallbacks ||= {}
end
@@ -115,8 +114,6 @@ module Rails
# Generators names must end with "_generator.rb". This is required because Rails
# looks in load paths and loads the generator just before it's going to be used.
#
- # ==== Examples
- #
# find_by_namespace :webrat, :rails, :integration
#
# Will search for the following generators:
@@ -125,7 +122,6 @@ module Rails
#
# Notice that "rails:generators:webrat" could be loaded as well, what
# Rails looks for is the first and last parts of the namespace.
- #
def self.find_by_namespace(name, base=nil, context=nil) #:nodoc:
lookups = []
lookups << "#{base}:#{name}" if base
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 9b0649e456..6cd2ea2bbd 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -8,12 +8,9 @@ module Rails
# Adds an entry into Gemfile for the supplied gem. If env
# is specified, add the gem to the given environment.
#
- # ==== Example
- #
# gem "rspec", :group => :test
# gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/"
# gem "rails", "3.0", :git => "git://github.com/rails/rails"
- #
def gem(*args)
options = args.extract_options!
name, version = args
@@ -43,12 +40,9 @@ module Rails
# Wraps gem entries inside a group.
#
- # ==== Example
- #
# gem_group :development, :test do
# gem "rspec-rails"
# end
- #
def gem_group(*names, &block)
name = names.map(&:inspect).join(", ")
log :gemfile, "group #{name}"
@@ -66,10 +60,7 @@ module Rails
# Add the given source to Gemfile
#
- # ==== Example
- #
# add_source "http://gems.github.com/"
- #
def add_source(source, options={})
log :source, source
@@ -83,8 +74,6 @@ module Rails
# If options :env is specified, the line is appended to the corresponding
# file in config/environments.
#
- # ==== Examples
- #
# environment do
# "config.autoload_paths += %W(#{config.root}/extras)"
# end
@@ -92,7 +81,6 @@ module Rails
# environment(nil, :env => "development") do
# "config.active_record.observers = :cacher"
# end
- #
def environment(data=nil, options={}, &block)
sentinel = /class [a-z_:]+ < Rails::Application/i
env_file_sentinel = /::Application\.configure do/
@@ -112,12 +100,9 @@ module Rails
# Run a command in git.
#
- # ==== Examples
- #
# git :init
# git :add => "this.file that.rb"
# git :add => "onefile.rb", :rm => "badfile.cxx"
- #
def git(commands={})
if commands.is_a?(Symbol)
run "git #{commands}"
@@ -131,15 +116,12 @@ module Rails
# Create a new file in the vendor/ directory. Code can be specified
# in a block or a data string can be given.
#
- # ==== Examples
- #
# vendor("sekrit.rb") do
# sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--"
# "salt = '#{sekrit_salt}'"
# end
#
# vendor("foreign.rb", "# Foreign code is fun")
- #
def vendor(filename, data=nil, &block)
log :vendor, filename
create_file("vendor/#{filename}", data, :verbose => false, &block)
@@ -148,14 +130,11 @@ module Rails
# Create a new file in the lib/ directory. Code can be specified
# in a block or a data string can be given.
#
- # ==== Examples
- #
# lib("crypto.rb") do
# "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'"
# end
#
# lib("foreign.rb", "# Foreign code is fun")
- #
def lib(filename, data=nil, &block)
log :lib, filename
create_file("lib/#{filename}", data, :verbose => false, &block)
@@ -163,8 +142,6 @@ module Rails
# Create a new Rakefile with the provided code (either in a block or a string).
#
- # ==== Examples
- #
# rakefile("bootstrap.rake") do
# project = ask("What is the UNIX name of your project?")
#
@@ -178,7 +155,6 @@ module Rails
# end
#
# rakefile('seed.rake', 'puts "Planting seeds"')
- #
def rakefile(filename, data=nil, &block)
log :rakefile, filename
create_file("lib/tasks/#{filename}", data, :verbose => false, &block)
@@ -186,8 +162,6 @@ module Rails
# Create a new initializer with the provided code (either in a block or a string).
#
- # ==== Examples
- #
# initializer("globals.rb") do
# data = ""
#
@@ -199,7 +173,6 @@ module Rails
# end
#
# initializer("api.rb", "API_KEY = '123456'")
- #
def initializer(filename, data=nil, &block)
log :initializer, filename
create_file("config/initializers/#{filename}", data, :verbose => false, &block)
@@ -209,10 +182,7 @@ module Rails
# The second parameter is the argument string that is passed to
# the generator or an Array that is joined.
#
- # ==== Example
- #
# generate(:authenticated, "user session")
- #
def generate(what, *args)
log :generate, what
argument = args.map {|arg| arg.to_s }.flatten.join(" ")
@@ -222,12 +192,9 @@ module Rails
# Runs the supplied rake task
#
- # ==== Example
- #
# rake("db:migrate")
# rake("db:migrate", :env => "production")
# rake("gems:install", :sudo => true)
- #
def rake(command, options={})
log :rake, command
env = options[:env] || ENV["RAILS_ENV"] || 'development'
@@ -237,10 +204,7 @@ module Rails
# Just run the capify command in root
#
- # ==== Example
- #
# capify!
- #
def capify!
log :capify, ""
in_root { run("#{extify(:capify)} .", :verbose => false) }
@@ -248,10 +212,7 @@ module Rails
# Make an entry in Rails routing file config/routes.rb
#
- # === Example
- #
# route "root :to => 'welcome#index'"
- #
def route(routing_code)
log :route, routing_code
sentinel = /\.routes\.draw do\s*$/
@@ -263,10 +224,7 @@ module Rails
# Reads the given file at the source root and prints it in the console.
#
- # === Example
- #
# readme "README"
- #
def readme(path)
log File.read(find_in_source_paths(path))
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 2c1742c6be..10ad475d55 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -246,8 +246,17 @@ module Rails
# is easier to silence stdout in the existing test suite this way. The
# end-user gets the bundler commands called anyway, so no big deal.
#
+ # We unset temporary bundler variables to load proper bundler and Gemfile.
+ #
# Thanks to James Tucker for the Gem tricks involved in this call.
- print `"#{Gem.ruby}" "#{Gem.bin_path('bundler', 'bundle')}" #{command}`
+ _bundle_command = Gem.bin_path('bundler', 'bundle')
+
+ bundle_bin_path, bundle_gemfile, rubyopt = ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT']
+ ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = "", "", ""
+
+ print `"#{Gem.ruby}" "#{_bundle_command}" #{command}`
+
+ ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = bundle_bin_path, bundle_gemfile, rubyopt
end
def run_bundle
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 1648b9674a..28d7680669 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -187,10 +187,7 @@ module Rails
# Remove a previously added hook.
#
- # ==== Examples
- #
# remove_hook_for :orm
- #
def self.remove_hook_for(*names)
remove_invocation(*names)
diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb
index 0c5c4f6e09..5bf98bb6e0 100644
--- a/railties/lib/rails/generators/migration.rb
+++ b/railties/lib/rails/generators/migration.rb
@@ -3,7 +3,6 @@ module Rails
# Holds common methods for migrations. It assumes that migrations has the
# [0-9]*_name format and can be used by another frameworks (like Sequel)
# just by implementing the next migration version method.
- #
module Migration
attr_reader :migration_number, :migration_file_name, :migration_class_name
@@ -38,10 +37,7 @@ module Rails
# The migration version, migration file name, migration class name are
# available as instance variables in the template to be rendered.
#
- # ==== Examples
- #
# migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb"
- #
def migration_template(source, destination=nil, config={})
destination = File.expand_path(destination || source, self.destination_root)
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
index 3b5cc6648e..3192ec897b 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
@@ -10,4 +10,4 @@
*
*= require_self
*= require_tree .
-*/
+ */
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 5fa96397f0..d816f973e6 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -44,9 +44,6 @@ module <%= app_const_base %>
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
- # Enable escaping HTML in JSON. The default is false.
- # config.active_support.escape_html_entities_in_json = true
-
# Use SQL instead of Active Record's schema dumper when creating the database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types.
diff --git a/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt b/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt
index 1c49e5c70a..f081e08b6c 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt
+++ b/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt
@@ -1,9 +1,7 @@
# See more about this file at: http://humanstxt.org/
# For format suggestions, see: http://humanstxt.org/Standard.html
/* TEAM */
- <%= ENV['USER'].titlecase %>
/* APP */
Name: <%= app_const_base %>
- Date Created: <%= Date.today.strftime("%B %d, %Y") %>
Software: Ruby on Rails
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 59212d4f58..26e912fd9e 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -89,7 +89,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
output = Dir.chdir(app_root) do
`rails new --help`
end
- assert_match /rails new APP_PATH \[options\]/, output
+ assert_match(/rails new APP_PATH \[options\]/, output)
assert_equal true, $?.success?
end
@@ -378,9 +378,8 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_humans_txt_file
- date = Date.today.strftime("%B %d, %Y")
run_generator [File.join(destination_root, 'things-43')]
- assert_file "things-43/public/humans.txt", /Name: Things43/, /Software: Ruby on Rails/, /Date Created: #{date}/
+ assert_file "things-43/public/humans.txt", /Name: Things43/, /Software: Ruby on Rails/
end
protected
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index 51374e5f3f..b0e1865b26 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -99,7 +99,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
end
def test_generation_runs_bundle_install_with_full_and_mountable
- result = run_generator [destination_root, "--mountable", "--full"]
+ result = run_generator [destination_root, "--mountable", "--full", "--dev"]
+ assert_file "#{destination_root}/Gemfile.lock" do |contents|
+ assert_match(/bukkits/, contents)
+ end
+ assert_match(/run bundle install/, result)
+ assert_match(/Using bukkits \(0\.0\.1\)/, result)
+ assert_match(/Your bundle is complete/, result)
assert_equal 1, result.scan("Your bundle is complete").size
end
@@ -348,4 +354,3 @@ protected
silence(:stdout){ generator.send(*args, &block) }
end
end
-
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 9a6b2b66ca..55f72f532f 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -537,10 +537,11 @@ YAML
assert_equal "foo", last_response.body
end
- test "it loads its environment file" do
+ test "it loads its environments file" do
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
+ config.paths["config/environments"].push "config/environments/additional.rb"
end
end
RUBY
@@ -551,9 +552,16 @@ YAML
end
RUBY
+ @plugin.write "config/environments/additional.rb", <<-RUBY
+ Bukkits::Engine.configure do
+ config.additional_environment_loaded = true
+ end
+ RUBY
+
boot_rails
assert Bukkits::Engine.config.environment_loaded
+ assert Bukkits::Engine.config.additional_environment_loaded
end
test "it passes router in env" do