aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/lib/action_mailer/test_helper.rb12
-rw-r--r--actionpack/CHANGELOG.md16
-rw-r--r--actionpack/README.rdoc2
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/caching.rb18
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb8
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb2
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb8
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb44
-rw-r--r--actionpack/lib/action_controller/railtie.rb17
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb22
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb2
-rw-r--r--actionpack/lib/action_view/base.rb2
-rw-r--r--actionpack/lib/action_view/digestor.rb21
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb16
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionpack/test/controller/caching_test.rb18
-rw-r--r--actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb33
-rw-r--r--actionpack/test/controller/webservice_test.rb50
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb15
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request/xml_params_parsing_test.rb17
-rw-r--r--actionpack/test/fixtures/test/_partial_name_local_variable.erb1
-rw-r--r--actionpack/test/template/digestor_test.rb18
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb4
-rw-r--r--actionpack/test/template/render_test.rb7
-rw-r--r--activemodel/README.rdoc18
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb2
-rw-r--r--activerecord/CHANGELOG.md6
-rw-r--r--activerecord/lib/active_record/aggregations.rb2
-rw-r--r--activerecord/lib/active_record/associations.rb16
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_association.rb7
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb4
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb2
-rw-r--r--activerecord/lib/active_record/base.rb50
-rw-r--r--activerecord/lib/active_record/locking/pessimistic.rb2
-rw-r--r--activerecord/lib/active_record/log_subscriber.rb12
-rw-r--r--activerecord/test/cases/deprecated_dynamic_methods_test.rb2
-rw-r--r--activerecord/test/cases/log_subscriber_test.rb42
-rw-r--r--activerecord/test/cases/relation/where_test.rb4
-rw-r--r--activesupport/CHANGELOG.md7
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb27
-rw-r--r--activesupport/lib/active_support/core_ext/object/acts_like.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/object/instance_variables.rb2
-rw-r--r--activesupport/lib/active_support/json/encoding.rb2
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb14
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb28
-rw-r--r--guides/source/4_0_release_notes.md2
-rw-r--r--guides/source/action_controller_overview.md8
-rw-r--r--guides/source/active_record_basics.md4
-rw-r--r--guides/source/active_record_callbacks.md3
-rw-r--r--guides/source/active_record_querying.md4
-rw-r--r--guides/source/active_support_core_extensions.md23
-rw-r--r--guides/source/caching_with_rails.md96
-rw-r--r--guides/source/command_line.md44
-rw-r--r--guides/source/configuring.md4
-rw-r--r--guides/source/credits.html.erb2
-rw-r--r--guides/source/debugging_rails_applications.md2
-rw-r--r--guides/source/engines.md30
-rw-r--r--guides/source/form_helpers.md6
-rw-r--r--guides/source/generators.md18
-rw-r--r--guides/source/getting_started.md16
-rw-r--r--guides/source/i18n.md4
-rw-r--r--guides/source/layouts_and_rendering.md2
-rw-r--r--guides/source/nested_model_forms.md2
-rw-r--r--guides/source/performance_testing.md16
-rw-r--r--guides/source/rails_application_templates.md7
-rw-r--r--guides/source/security.md2
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/README.rdoc (renamed from railties/lib/rails/generators/rails/app/templates/README)6
-rw-r--r--railties/lib/rails/templates/rails/welcome/index.html.erb6
-rw-r--r--railties/test/application/configuration_test.rb48
82 files changed, 439 insertions, 578 deletions
diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb
index 3ab37d8142..6452bf616c 100644
--- a/actionmailer/lib/action_mailer/test_helper.rb
+++ b/actionmailer/lib/action_mailer/test_helper.rb
@@ -4,9 +4,9 @@ module ActionMailer
#
# def test_emails
# assert_emails 0
- # ContactMailer.deliver_contact
+ # ContactMailer.welcome.deliver
# assert_emails 1
- # ContactMailer.deliver_contact
+ # ContactMailer.welcome.deliver
# assert_emails 2
# end
#
@@ -15,12 +15,12 @@ module ActionMailer
#
# def test_emails_again
# assert_emails 1 do
- # ContactMailer.deliver_contact
+ # ContactMailer.welcome.deliver
# end
#
# assert_emails 2 do
- # ContactMailer.deliver_contact
- # ContactMailer.deliver_contact
+ # ContactMailer.welcome.deliver
+ # ContactMailer.welcome.deliver
# end
# end
def assert_emails(number)
@@ -38,7 +38,7 @@ module ActionMailer
#
# def test_emails
# assert_no_emails
- # ContactMailer.deliver_contact
+ # ContactMailer.welcome.deliver
# assert_emails 1
# end
#
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 334cf9e1fc..1a8f187979 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,21 @@
## Rails 4.0.0 (unreleased) ##
+* Added view_cache_dependency API for declaring dependencies that affect
+ cache digest computation.
+
+ *Jamis Buck*
+
+* `image_submit_tag` will set `alt` attribute from image source if not
+ specified.
+
+ *Nihad Abbasov*
+
+* Do not generate local variables for partials without object or collection.
+ Previously rendering a partial without giving `:object` or `:collection`
+ would generate a local variable with the partial name by default.
+
+ *Carlos Antonio da Silva*
+
* Return the last valid, non-private IP address from the X-Forwarded-For,
Client-IP and Remote-Addr headers, in that order. Document the rationale
for that decision, and describe the options that can be passed to the
diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc
index ccd0193515..29a7fcf0f0 100644
--- a/actionpack/README.rdoc
+++ b/actionpack/README.rdoc
@@ -10,7 +10,7 @@ It consists of several modules:
* Action Dispatch, which parses information about the web request, handles
routing as defined by the user, and does advanced processing related to HTTP
- such as MIME-type negotiation, decoding parameters in POST/PUT bodies,
+ such as MIME-type negotiation, decoding parameters in POST, PATCH, or PUT bodies,
handling HTTP caching logic, cookies and sessions.
* Action Controller, which provides a base controller class that can be
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index c65870cac6..f00fc46b2e 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
s.add_dependency 'activesupport', version
s.add_dependency 'builder', '~> 3.1.0'
- s.add_dependency 'rack', '~> 1.4.1'
+ s.add_dependency 'rack', '~> 1.4.3'
s.add_dependency 'rack-test', '~> 0.6.1'
s.add_dependency 'erubis', '~> 2.7.0'
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index 2892e093af..0f4cced32a 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -70,12 +70,30 @@ module ActionController
config_accessor :perform_caching
self.perform_caching = true if perform_caching.nil?
+
+ class_attribute :_view_cache_dependencies
+ self._view_cache_dependencies = []
+ helper_method :view_cache_dependencies if respond_to?(:helper_method)
+ end
+
+ module ClassMethods
+ def view_cache_dependency(&dependency)
+ self._view_cache_dependencies += [dependency]
+ end
+
+ def view_cache_dependencies
+ _view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
+ end
end
def caching_allowed?
request.get? && response.status == 200
end
+ def view_cache_dependencies
+ self.class.view_cache_dependencies
+ end
+
protected
# Convenience accessor.
def cache(key, options = {}, &block)
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index e59213806f..d04fbae150 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -82,7 +82,7 @@ module ActionController #:nodoc:
# (by name) if it does not already exist, without web-services, it might look like this:
#
# def create
- # @company = Company.find_or_create_by_name(params[:company][:name])
+ # @company = Company.find_or_create_by(name: params[:company][:name])
# @person = @company.people.create(params[:person])
#
# redirect_to(person_list_url)
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
#
# def create
# company = params[:person].delete(:company)
- # @company = Company.find_or_create_by_name(company[:name])
+ # @company = Company.find_or_create_by(name: company[:name])
# @person = @company.people.create(params[:person])
#
# respond_to do |format|
@@ -120,7 +120,7 @@ module ActionController #:nodoc:
# Note, however, the extra bit at the top of that action:
#
# company = params[:person].delete(:company)
- # @company = Company.find_or_create_by_name(company[:name])
+ # @company = Company.find_or_create_by(name: company[:name])
#
# This is because the incoming XML document (if a web-service request is in process) can only contain a
# single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
@@ -227,7 +227,7 @@ module ActionController #:nodoc:
# i.e. its +show+ action.
# 2. If there are validation errors, the response
# renders a default action, which is <tt>:new</tt> for a
- # +post+ request or <tt>:edit</tt> for +put+.
+ # +post+ request or <tt>:edit</tt> for +patch+ or +put+.
# Thus an example like this -
#
# respond_to :html, :xml
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 091facfd8d..13ec55fe92 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -32,7 +32,7 @@ module ActionController
# redirect_to :back
# redirect_to proc { edit_post_url(@post) }
#
- # The redirection happens as a "302 Moved" header unless otherwise specified.
+ # The redirection happens as a "302 Found" header unless otherwise specified.
#
# redirect_to post_url(@post), status: :found
# redirect_to action: 'atom', status: :moved_permanently
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 0b3c438ec2..73e9b5660d 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -26,7 +26,7 @@ module ActionController #:nodoc:
#
# class PostsController
# def index
- # @posts = Post.scoped
+ # @posts = Post.all
# render stream: true
# end
# end
@@ -51,9 +51,9 @@ module ActionController #:nodoc:
#
# def dashboard
# # Allow lazy execution of the queries
- # @posts = Post.scoped
- # @pages = Page.scoped
- # @articles = Article.scoped
+ # @posts = Post.all
+ # @pages = Page.all
+ # @articles = Article.all
# render stream: true
# end
#
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 5ea1b2cc1a..941b6e210f 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -19,20 +19,6 @@ module ActionController
end
end
- # Raised when a supplied parameter is not permitted.
- #
- # params = ActionController::Parameters.new(a: "123", b: "456")
- # params.permit(:c)
- # # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
- class UnpermittedParameters < IndexError
- attr_reader :params # :nodoc:
-
- def initialize(params) # :nodoc:
- @params = params
- super("found unpermitted keys: #{params.join(", ")}")
- end
- end
-
# == Action Controller \Parameters
#
# Allows to choose which attributes should be whitelisted for mass updating
@@ -57,14 +43,10 @@ module ActionController
# Person.first.update!(permitted)
# # => #<Person id: 1, name: "Francesco", age: 22, role: "user">
#
- # It provides two options that controls the top-level behavior of new instances:
- #
- # * +permit_all_parameters+ - If it's +true+, all the parameters will be
- # permitted by default. The default is +false+.
- # * +raise_on_unpermitted_parameters+ - If it's +true+, it will raise an
- # ActionController::UnpermittedParameters exception if parameters that are not
- # explicitly permitted are found. The default value is +true+ in test and
- # development environments, +false+ otherwise.
+ # It provides a +permit_all_parameters+ option that controls the top-level
+ # behavior of new instances. If it's +true+, all the parameters will be
+ # permitted by default. The default value for +permit_all_parameters+
+ # option is +false+.
#
# params = ActionController::Parameters.new
# params.permitted? # => false
@@ -74,16 +56,6 @@ module ActionController
# params = ActionController::Parameters.new
# params.permitted? # => true
#
- # params = ActionController::Parameters.new(a: "123", b: "456")
- # params.permit(:c)
- # # => {}
- #
- # ActionController::Parameters.raise_on_unpermitted_parameters = true
- #
- # params = ActionController::Parameters.new(a: "123", b: "456")
- # params.permit(:c)
- # # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
- #
# <tt>ActionController::Parameters</tt> is inherited from
# <tt>ActiveSupport::HashWithIndifferentAccess</tt>, this means
# that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>.
@@ -93,7 +65,6 @@ module ActionController
# params["key"] # => "value"
class Parameters < ActiveSupport::HashWithIndifferentAccess
cattr_accessor :permit_all_parameters, instance_accessor: false
- cattr_accessor :raise_on_unpermitted_parameters, instance_accessor: false
# Returns a new instance of <tt>ActionController::Parameters</tt>.
# Also, sets the +permitted+ attribute to the default value of
@@ -251,13 +222,6 @@ module ActionController
end
end
- if Parameters.raise_on_unpermitted_parameters
- unpermitted_keys = self.keys - params.keys
- if unpermitted_keys.any?
- raise ActionController::UnpermittedParameters.new(unpermitted_keys)
- end
- end
-
params.permit!
end
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index 731d66b0cf..3e44155f73 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -20,25 +20,22 @@ module ActionController
end
initializer "action_controller.parameters_config" do |app|
- options = app.config.action_controller
-
- ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false }
- ActionController::Parameters.raise_on_unpermitted_parameters = options.delete(:raise_on_unpermitted_parameters) { Rails.env.test? || Rails.env.development? }
+ ActionController::Parameters.permit_all_parameters = app.config.action_controller.delete(:permit_all_parameters) { false }
end
initializer "action_controller.set_configs" do |app|
paths = app.config.paths
options = app.config.action_controller
- options.logger ||= Rails.logger
- options.cache_store ||= Rails.cache
+ options.logger ||= Rails.logger
+ options.cache_store ||= Rails.cache
- options.javascripts_dir ||= paths["public/javascripts"].first
- options.stylesheets_dir ||= paths["public/stylesheets"].first
+ options.javascripts_dir ||= paths["public/javascripts"].first
+ options.stylesheets_dir ||= paths["public/stylesheets"].first
# Ensure readers methods get compiled
- options.asset_host ||= app.config.asset_host
- options.relative_url_root ||= app.config.relative_url_root
+ options.asset_host ||= app.config.asset_host
+ options.relative_url_root ||= app.config.relative_url_root
ActiveSupport.on_load(:action_controller) do
include app.routes.mounted_helpers
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 452809a689..31b36eedb0 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -276,15 +276,14 @@ module ActionDispatch
LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip
end
- protected
-
# Remove nils from the params hash
def deep_munge(hash)
- hash.each_value do |v|
+ hash.each do |k, v|
case v
when Array
v.grep(Hash) { |x| deep_munge(x) }
v.compact!
+ hash[k] = nil if v.empty?
when Hash
deep_munge(v)
end
@@ -293,6 +292,8 @@ module ActionDispatch
hash
end
+ protected
+
def parse_query(qs)
deep_munge(super)
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 121a11c8e1..6ecbb03784 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -15,7 +15,7 @@ module ActionDispatch
# being written will be sent out with the response. Reading a cookie does not get
# the cookie object itself back, just the value it holds.
#
- # Examples for writing:
+ # Examples of writing:
#
# # Sets a simple session cookie.
# # This cookie will be deleted when the user's browser is closed.
@@ -38,7 +38,7 @@ module ActionDispatch
# # You can also chain these methods:
# cookies.permanent.signed[:login] = "XJ-122"
#
- # Examples for reading:
+ # Examples of reading:
#
# cookies[:user_name] # => "david"
# cookies.size # => 2
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index f24e9b8e18..7e56feb90a 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -59,12 +59,12 @@ module ActionDispatch
@flash[k]
end
- # Convenience accessor for flash.now[:alert]=
+ # Convenience accessor for <tt>flash.now[:alert]=</tt>.
def alert=(message)
self[:alert] = message
end
- # Convenience accessor for flash.now[:notice]=
+ # Convenience accessor for <tt>flash.now[:notice]=</tt>.
def notice=(message)
self[:notice] = message
end
@@ -82,7 +82,7 @@ module ActionDispatch
else
new
end
-
+
flash.tap(&:sweep)
end
@@ -169,6 +169,14 @@ module ActionDispatch
# vanish when the current action is done.
#
# Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>.
+ #
+ # Also, brings two convenience accessors:
+ #
+ # flash.now.alert = "Beware now!"
+ # # Equivalent to flash.now[:alert] = "Beware now!"
+ #
+ # flash.now.notice = "Good luck now!"
+ # # Equivalent to flash.now[:notice] = "Good luck now!"
def now
@now ||= FlashNow.new(self)
end
@@ -199,22 +207,22 @@ module ActionDispatch
@discard.replace @flashes.keys
end
- # Convenience accessor for flash[:alert]
+ # Convenience accessor for <tt>flash[:alert]</tt>.
def alert
self[:alert]
end
- # Convenience accessor for flash[:alert]=
+ # Convenience accessor for <tt>flash[:alert]=</tt>.
def alert=(message)
self[:alert] = message
end
- # Convenience accessor for flash[:notice]
+ # Convenience accessor for <tt>flash[:notice]</tt>.
def notice
self[:notice]
end
- # Convenience accessor for flash[:notice]=
+ # Convenience accessor for <tt>flash[:notice]=</tt>.
def notice=(message)
self[:notice] = message
end
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 2c98ca03a8..a3291bb7ad 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -47,12 +47,10 @@ module ActionDispatch
when Proc
strategy.call(request.raw_post)
when :xml_simple, :xml_node
- data = Hash.from_xml(request.raw_post) || {}
+ data = request.deep_munge(Hash.from_xml(request.body.read) || {})
data.with_indifferent_access
- when :yaml
- YAML.load(request.raw_post)
when :json
- data = ActiveSupport::JSON.decode(request.raw_post)
+ data = request.deep_munge ActiveSupport::JSON.decode(request.body)
data = {:_json => data} unless data.is_a?(Hash)
data.with_indifferent_access
else
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index e3b15b43b9..1c9512ad01 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -6,7 +6,7 @@ module ActionDispatch
def initialize(root, cache_control)
@root = root.chomp('/')
@compiled_root = /^#{Regexp.escape(root)}/
- @file_server = ::Rack::File.new(@root, cache_control)
+ @file_server = ::Rack::File.new(@root, 'Cache-Control' => cache_control)
end
def match?(path)
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 668515df59..08253de3f4 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -6,7 +6,7 @@ require 'action_view/log_subscriber'
module ActionView #:nodoc:
# = Action View Base
#
- # Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERb
+ # Action View templates can be written in several ways. If the template file has a <tt>.erb</tt> extension then it uses a mixture of ERB
# (included in Ruby) and HTML. If the template file has a <tt>.builder</tt> extension then Jim Weirich's Builder::XmlMarkup library is used.
#
# == ERB
diff --git a/actionpack/lib/action_view/digestor.rb b/actionpack/lib/action_view/digestor.rb
index f3f6b425a8..4507861dcc 100644
--- a/actionpack/lib/action_view/digestor.rb
+++ b/actionpack/lib/action_view/digestor.rb
@@ -24,16 +24,17 @@ module ActionView
@@cache = ThreadSafe::Cache.new
def self.digest(name, format, finder, options = {})
- @@cache["#{name}.#{format}"] ||= begin
+ cache_key = [name, format] + Array.wrap(options[:dependencies])
+ @@cache[cache_key.join('.')] ||= begin
klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
- klass.new(name, format, finder).digest
+ klass.new(name, format, finder, options).digest
end
end
- attr_reader :name, :format, :finder
+ attr_reader :name, :format, :finder, :options
- def initialize(name, format, finder)
- @name, @format, @finder = name, format, finder
+ def initialize(name, format, finder, options={})
+ @name, @format, @finder, @options = name, format, finder, options
end
def digest
@@ -81,9 +82,11 @@ module ActionView
end
def dependency_digest
- dependencies.collect do |template_name|
+ template_digests = dependencies.collect do |template_name|
Digestor.digest(template_name, format, finder, partial: true)
- end.join("-")
+ end
+
+ (template_digests + injected_dependencies).join("-")
end
def render_dependencies
@@ -105,6 +108,10 @@ module ActionView
def explicit_dependencies
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
end
+
+ def injected_dependencies
+ Array.wrap(options[:dependencies])
+ end
end
class PartialDigestor < Digestor # :nodoc:
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index 995aa10afb..8fc78ea7fb 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -167,7 +167,7 @@ module ActionView
if @virtual_path
[
*Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name),
- Digestor.digest(@virtual_path, formats.last.to_sym, lookup_context)
+ Digestor.digest(@virtual_path, formats.last.to_sym, lookup_context, dependencies: view_cache_dependencies)
]
else
name
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 8a1e886b7f..50f1eff4ec 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -84,7 +84,7 @@ module ActionView
#
# <form action="/people/256" class="edit_person" id="edit_person_256" method="post">
# <div style="margin:0;padding:0;display:inline">
- # <input name="_method" type="hidden" value="put" />
+ # <input name="_method" type="hidden" value="patch" />
# <input name="authenticity_token" type="hidden" value="NrOp5bsjoLRuK8IW5+dQEYjKGUJDe7TQoZVvq95Wteg=" />
# </div>
# <label for="person_first_name">First name</label>:
@@ -242,7 +242,7 @@ module ActionView
#
# is then equivalent to something like:
#
- # <%= form_for @post, as: :post, url: post_path(@post), method: :put, html: { class: "edit_post", id: "edit_post_45" } do |f| %>
+ # <%= form_for @post, as: :post, url: post_path(@post), method: :patch, html: { class: "edit_post", id: "edit_post_45" } do |f| %>
# ...
# <% end %>
#
@@ -318,7 +318,7 @@ module ActionView
#
# <form action='http://www.example.com' method='post' data-remote='true'>
# <div style='margin:0;padding:0;display:inline'>
- # <input name='_method' type='hidden' value='put' />
+ # <input name='_method' type='hidden' value='patch' />
# </div>
# ...
# </form>
@@ -336,7 +336,7 @@ module ActionView
#
# <form action='http://www.example.com' method='post' data-behavior='autosave' name='go'>
# <div style='margin:0;padding:0;display:inline'>
- # <input name='_method' type='hidden' value='put' />
+ # <input name='_method' type='hidden' value='patch' />
# </div>
# ...
# </form>
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 479739bebd..86d9f94067 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -26,7 +26,7 @@ module ActionView
# ==== Options
# * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
# * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post".
- # If "put", "delete", or another verb is used, a hidden input with name <tt>_method</tt>
+ # If "patch", "put", "delete", or another verb is used, a hidden input with name <tt>_method</tt>
# is added to simulate the verb over post.
# * <tt>:authenticity_token</tt> - Authenticity token to use in the form. Use only if you need to
# pass custom authenticity token string, or to not add authenticity_token field at all
@@ -526,19 +526,19 @@ module ActionView
#
# ==== Examples
# image_submit_tag("login.png")
- # # => <input src="/images/login.png" type="image" />
+ # # => <input alt="Login" src="/images/login.png" type="image" />
#
# image_submit_tag("purchase.png", disabled: true)
- # # => <input disabled="disabled" src="/images/purchase.png" type="image" />
+ # # => <input alt="Purchase" disabled="disabled" src="/images/purchase.png" type="image" />
#
- # image_submit_tag("search.png", class: 'search_button')
- # # => <input class="search_button" src="/images/search.png" type="image" />
+ # image_submit_tag("search.png", class: 'search_button', alt: 'Find')
+ # # => <input alt="Find" class="search_button" src="/images/search.png" type="image" />
#
# image_submit_tag("agree.png", disabled: true, class: "agree_disagree_button")
- # # => <input class="agree_disagree_button" disabled="disabled" src="/images/agree.png" type="image" />
+ # # => <input alt="Agree" class="agree_disagree_button" disabled="disabled" src="/images/agree.png" type="image" />
#
# image_submit_tag("save.png", data: { confirm: "Are you sure?" })
- # # => <input src="/images/save.png" data-confirm="Are you sure?" type="image" />
+ # # => <input alt="Save" src="/images/save.png" data-confirm="Are you sure?" type="image" />
def image_submit_tag(source, options = {})
options = options.stringify_keys
@@ -550,7 +550,7 @@ module ActionView
options["data-confirm"] = confirm
end
- tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options)
+ tag :input, { "alt" => image_alt(source), "type" => "image", "src" => path_to_image(source) }.update(options)
end
# Creates a field set for grouping HTML form elements.
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 37f93a13fc..43a88b0623 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -452,7 +452,7 @@ module ActionView
def retrieve_template_keys
keys = @locals.keys
- keys << @variable
+ keys << @variable if @object || @collection
keys << @variable_counter if @collection
keys
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 2428cd7433..eb5eeb0423 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -296,6 +296,24 @@ class CacheHelperOutputBufferTest < ActionController::TestCase
end
end
+class ViewCacheDependencyTest < ActionController::TestCase
+ class NoDependenciesController < ActionController::Base
+ end
+
+ class HasDependenciesController < ActionController::Base
+ view_cache_dependency { "trombone" }
+ view_cache_dependency { "flute" }
+ end
+
+ def test_view_cache_dependencies_are_empty_by_default
+ assert NoDependenciesController.view_cache_dependencies.empty?
+ end
+
+ def test_view_cache_dependencies_are_listed_in_declaration_order
+ assert_equal %w(trombone flute), HasDependenciesController.view_cache_dependencies
+ end
+end
+
class DeprecatedPageCacheExtensionTest < ActiveSupport::TestCase
def test_page_cache_extension_binds_default_static_extension
deprecation_behavior = ActiveSupport::Deprecation.behavior
diff --git a/actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb b/actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb
deleted file mode 100644
index 747b8123ea..0000000000
--- a/actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'abstract_unit'
-require 'action_controller/metal/strong_parameters'
-
-class RaiseOnUnpermittedParametersTest < ActiveSupport::TestCase
- def setup
- ActionController::Parameters.raise_on_unpermitted_parameters = true
- end
-
- def teardown
- ActionController::Parameters.raise_on_unpermitted_parameters = false
- end
-
- test "raises on unexpected params" do
- params = ActionController::Parameters.new({
- book: { pages: 65 },
- fishing: "Turnips"
- })
-
- assert_raises(ActionController::UnpermittedParameters) do
- params.permit(book: [:pages])
- end
- end
-
- test "raises on unexpected nested params" do
- params = ActionController::Parameters.new({
- book: { pages: 65, title: "Green Cats and where to find then." }
- })
-
- assert_raises(ActionController::UnpermittedParameters) do
- params.permit(book: [:pages])
- end
- end
-end
diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb
index c0b9833603..0480295056 100644
--- a/actionpack/test/controller/webservice_test.rb
+++ b/actionpack/test/controller/webservice_test.rb
@@ -116,22 +116,22 @@ class WebServiceTest < ActionDispatch::IntegrationTest
end
end
- def test_register_and_use_yaml
+ def test_post_xml_using_a_disallowed_type_attribute
+ $stderr = StringIO.new
with_test_route_set do
- with_params_parsers Mime::YAML => Proc.new { |d| YAML.load(d) } do
- post "/", {"entry" => "loaded from yaml"}.to_yaml,
- {'CONTENT_TYPE' => 'application/x-yaml'}
+ post '/', '<foo type="symbol">value</foo>', 'CONTENT_TYPE' => 'application/xml'
+ assert_response 500
- assert_equal 'entry', @controller.response.body
- assert @controller.params.has_key?(:entry)
- assert_equal 'loaded from yaml', @controller.params["entry"]
- end
+ post '/', '<foo type="yaml">value</foo>', 'CONTENT_TYPE' => 'application/xml'
+ assert_response 500
end
+ ensure
+ $stderr = STDERR
end
- def test_register_and_use_yaml_as_symbol
+ def test_register_and_use_yaml
with_test_route_set do
- with_params_parsers Mime::YAML => :yaml do
+ with_params_parsers Mime::YAML => Proc.new { |d| YAML.load(d) } do
post "/", {"entry" => "loaded from yaml"}.to_yaml,
{'CONTENT_TYPE' => 'application/x-yaml'}
@@ -211,36 +211,6 @@ class WebServiceTest < ActionDispatch::IntegrationTest
end
end
- def test_typecast_as_yaml
- with_test_route_set do
- with_params_parsers Mime::YAML => :yaml do
- yaml = (<<-YAML).strip
- ---
- data:
- a: 15
- b: false
- c: true
- d: 2005-03-17
- e: 2005-03-17T21:41:07Z
- f: unparsed
- g:
- - 1
- - hello
- - 1974-07-25
- YAML
- post "/", yaml, {'CONTENT_TYPE' => 'application/x-yaml'}
- params = @controller.params
- assert_equal 15, params[:data][:a]
- assert_equal false, params[:data][:b]
- assert_equal true, params[:data][:c]
- assert_equal Date.new(2005,3,17), params[:data][:d]
- assert_equal Time.utc(2005,3,17,21,41,7), params[:data][:e]
- assert_equal "unparsed", params[:data][:f]
- assert_equal [1, "hello", Date.new(1974,7,25)], params[:data][:g]
- end
- end
- end
-
private
def with_params_parsers(parsers = {})
old_session = @integration_session
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index c0c3147e37..2c4a6c2147 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -30,6 +30,21 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
)
end
+ test "nils are stripped from collections" do
+ assert_parses(
+ {"person" => nil},
+ "{\"person\":[null]}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ assert_parses(
+ {"person" => ['foo']},
+ "{\"person\":[\"foo\",null]}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ assert_parses(
+ {"person" => nil},
+ "{\"person\":[null, null]}", { 'CONTENT_TYPE' => 'application/json' }
+ )
+ end
+
test "logs error if parsing unsuccessful" do
with_test_routing do
output = StringIO.new
diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index 3cb430d83d..f072a9f717 100644
--- a/actionpack/test/dispatch/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -84,8 +84,8 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
assert_parses({"action" => nil}, "action")
assert_parses({"action" => {"foo" => nil}}, "action[foo]")
assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar]")
- assert_parses({"action" => {"foo" => { "bar" => [] }}}, "action[foo][bar][]")
- assert_parses({"action" => {"foo" => []}}, "action[foo][]")
+ assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar][]")
+ assert_parses({"action" => {"foo" => nil }}, "action[foo][]")
assert_parses({"action"=>{"foo"=>[{"bar"=>nil}]}}, "action[foo][][bar]")
end
diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb
index cb68667002..f13b64a3c7 100644
--- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb
@@ -30,6 +30,23 @@ class XmlParamsParsingTest < ActionDispatch::IntegrationTest
assert_equal "<ok>bar</ok>", resp.body
end
+ def assert_parses(expected, xml)
+ with_test_routing do
+ post "/parse", xml, default_headers
+ assert_response :ok
+ assert_equal(expected, TestController.last_request_parameters)
+ end
+ end
+
+ test "nils are stripped from collections" do
+ assert_parses(
+ {"hash" => { "person" => nil} },
+ "<hash><person type=\"array\"><person nil=\"true\"/></person></hash>")
+ assert_parses(
+ {"hash" => { "person" => ['foo']} },
+ "<hash><person type=\"array\"><person>foo</person><person nil=\"true\"/></person>\n</hash>")
+ end
+
test "parses hash params" do
with_test_routing do
xml = "<person><name>David</name></person>"
diff --git a/actionpack/test/fixtures/test/_partial_name_local_variable.erb b/actionpack/test/fixtures/test/_partial_name_local_variable.erb
new file mode 100644
index 0000000000..cc3a91c89f
--- /dev/null
+++ b/actionpack/test/fixtures/test/_partial_name_local_variable.erb
@@ -0,0 +1 @@
+<%= partial_name_local_variable %>
diff --git a/actionpack/test/template/digestor_test.rb b/actionpack/test/template/digestor_test.rb
index 02b1fd87a8..849e2981a6 100644
--- a/actionpack/test/template/digestor_test.rb
+++ b/actionpack/test/template/digestor_test.rb
@@ -138,6 +138,20 @@ class TemplateDigestorTest < ActionView::TestCase
end
end
+ def test_dependencies_via_options_results_in_different_digest
+ digest_plain = digest("comments/_comment")
+ digest_fridge = digest("comments/_comment", dependencies: ["fridge"])
+ digest_phone = digest("comments/_comment", dependencies: ["phone"])
+ digest_fridge_phone = digest("comments/_comment", dependencies: ["fridge", "phone"])
+
+ assert_not_equal digest_plain, digest_fridge
+ assert_not_equal digest_plain, digest_phone
+ assert_not_equal digest_plain, digest_fridge_phone
+ assert_not_equal digest_fridge, digest_phone
+ assert_not_equal digest_fridge, digest_fridge_phone
+ assert_not_equal digest_phone, digest_fridge_phone
+ end
+
private
def assert_logged(message)
old_logger = ActionView::Base.logger
@@ -164,8 +178,8 @@ class TemplateDigestorTest < ActionView::TestCase
ActionView::Digestor.cache.clear
end
- def digest(template_name)
- ActionView::Digestor.digest(template_name, :html, FixtureFinder.new)
+ def digest(template_name, options={})
+ ActionView::Digestor.digest(template_name, :html, FixtureFinder.new, options)
end
def change_template(template_name)
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 0a94fa079b..6c6a142397 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -488,7 +488,7 @@ class FormTagHelperTest < ActionView::TestCase
def test_image_submit_tag_with_confirmation
assert_dom_equal(
- %(<input type="image" src="/images/save.gif" data-confirm="Are you sure?" />),
+ %(<input alt="Save" type="image" src="/images/save.gif" data-confirm="Are you sure?" />),
image_submit_tag("save.gif", :data => { :confirm => "Are you sure?" })
)
end
@@ -496,7 +496,7 @@ class FormTagHelperTest < ActionView::TestCase
def test_image_submit_tag_with_deprecated_confirmation
assert_deprecated ":confirm option is deprecated and will be removed from Rails 4.1. Use 'data: { confirm: \'Text\' }' instead" do
assert_dom_equal(
- %(<input type="image" src="/images/save.gif" data-confirm="Are you sure?" />),
+ %(<input alt="Save" type="image" src="/images/save.gif" data-confirm="Are you sure?" />),
image_submit_tag("save.gif", :confirm => "Are you sure?")
)
end
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 9fb26e32b1..8111e58527 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -318,6 +318,13 @@ module RenderTestCases
@controller_view.render(customers, :greeting => "Hello")
end
+ def test_render_partial_without_object_or_collection_does_not_generate_partial_name_local_variable
+ exception = assert_raises ActionView::Template::Error do
+ @controller_view.render("partial_name_local_variable")
+ end
+ assert_match "undefined local variable or method `partial_name_local_variable'", exception.message
+ end
+
# TODO: The reason for this test is unclear, improve documentation
def test_render_partial_and_fallback_to_layout
assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" })
diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc
index 3262bf61ac..3cc2d9ad8e 100644
--- a/activemodel/README.rdoc
+++ b/activemodel/README.rdoc
@@ -133,24 +133,6 @@ behavior out of the box:
{Learn more}[link:classes/ActiveModel/Naming.html]
-* Observer support
-
- ActiveModel::Observers allows your object to implement the Observer
- pattern in a Rails App and take advantage of all the standard observer
- functions.
-
- class PersonObserver < ActiveModel::Observer
- def after_create(person)
- person.logger.info("New person added!")
- end
-
- def after_destroy(person)
- person.logger.warn("Person with an id of #{person.id} was destroyed!")
- end
- end
-
- {Learn more}[link:classes/ActiveModel/Observer.html]
-
* Making objects serializable
ActiveModel::Serialization provides a standard interface for your object
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index db5759ada9..6d11c0fbdc 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -436,7 +436,7 @@ module ActiveModel
# attribute_missing is like method_missing, but for attributes. When method_missing is
# called we check to see if there is a matching attribute method. If so, we call
# attribute_missing to dispatch the attribute. This method can be overloaded to
- # customise the behaviour.
+ # customize the behavior.
def attribute_missing(match, *args, &block)
__send__(match.target, match.attr_name, *args, &block)
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index f098c49136..5a0c391154 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,10 +1,14 @@
## Rails 4.0.0 (unreleased) ##
+* Remove support for parsing YAML parameters from request.
+
+ *Aaron Patterson*
+
* Support for PostgreSQL's `ltree` data type.
*Rob Worley*
-* Fix undefined method `to_i` when calling `new` on a scope that uses an
+* Fix undefined method `to_i` when calling `new` on a scope that uses an
Array; Fix FloatDomainError when setting integer column to NaN.
Fixes #8718, #8734, #8757.
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index 6acfec02c4..9d1c12ec62 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -165,7 +165,7 @@ module ActiveRecord
# by specifying an instance of the value object in the conditions hash. The following example
# finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
#
- # Customer.where(balance: Money.new(20, "USD")).all
+ # Customer.where(balance: Money.new(20, "USD"))
#
module ClassMethods
# Adds reader and writer methods for manipulating a value object:
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index e09f2089fb..16a46a59d1 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -192,7 +192,7 @@ module ActiveRecord
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
# <tt>Project#milestones.delete(milestone), Project#milestones.destroy(mileston), Project#milestones.find(milestone_id),</tt>
- # <tt>Project#milestones.all(options), Project#milestones.build, Project#milestones.create</tt>
+ # <tt>Project#milestones.build, Project#milestones.create</tt>
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
# <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
#
@@ -457,7 +457,7 @@ module ActiveRecord
# has_many :people do
# def find_or_create_by_name(name)
# first_name, last_name = name.split(" ", 2)
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
+ # find_or_create_by(first_name: first_name, last_name: last_name)
# end
# end
# end
@@ -472,7 +472,7 @@ module ActiveRecord
# module FindOrCreateByNameExtension
# def find_or_create_by_name(name)
# first_name, last_name = name.split(" ", 2)
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
+ # find_or_create_by(first_name: first_name, last_name: last_name)
# end
# end
#
@@ -741,7 +741,7 @@ module ActiveRecord
# other than the main one. If this is the case Active Record falls back to the previously
# used LEFT OUTER JOIN based strategy. For example
#
- # Post.includes([:author, :comments]).where(['comments.approved = ?', true]).all
+ # Post.includes([:author, :comments]).where(['comments.approved = ?', true])
#
# This will result in a single SQL query with joins along the lines of:
# <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
@@ -949,7 +949,7 @@ module ActiveRecord
#
# The <tt>:dependent</tt> option can have different values which specify how the deletion
# is done. For more information, see the documentation for this option on the different
- # specific association types. When no option is given, the behaviour is to do nothing
+ # specific association types. When no option is given, the behavior is to do nothing
# with the associated records when destroying a record.
#
# Note that <tt>:dependent</tt> is implemented using Rails' callback
@@ -1079,7 +1079,7 @@ module ActiveRecord
# === Example
#
# Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
- # * <tt>Firm#clients</tt> (similar to <tt>Clients.all conditions: ["firm_id = ?", id]</tt>)
+ # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
# * <tt>Firm#clients<<</tt>
# * <tt>Firm#clients.delete</tt>
# * <tt>Firm#clients.destroy</tt>
@@ -1089,7 +1089,7 @@ module ActiveRecord
# * <tt>Firm#clients.clear</tt>
# * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
- # * <tt>Firm#clients.find</tt> (similar to <tt>Client.find(id, conditions: "firm_id = #{id}")</tt>)
+ # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
# * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
@@ -1211,7 +1211,7 @@ module ActiveRecord
# === Example
#
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
- # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.first(conditions: "account_id = #{id}")</tt>)
+ # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index 75f72c1a46..532af3e83e 100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
@@ -50,8 +50,11 @@ module ActiveRecord
# Checks whether record is different to the current target, without loading it
def different_target?(record)
- record.nil? && owner[reflection.foreign_key] ||
- record && record.id != owner[reflection.foreign_key]
+ if record.nil?
+ owner[reflection.foreign_key]
+ else
+ record.id != owner[reflection.foreign_key]
+ end
end
def replace_keys(record)
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 7c43e37cf2..33dce58982 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -758,7 +758,7 @@ module ActiveRecord
# person.pets.count # => 0
# person.pets.any? # => true
#
- # You can also pass a block to define criteria. The behaviour
+ # You can also pass a block to define criteria. The behavior
# is the same, it returns true if the collection based on the
# criteria is not empty.
#
@@ -793,7 +793,7 @@ module ActiveRecord
# person.pets.many? #=> true
#
# You can also pass a block to define criteria. The
- # behaviour is the same, it returns true if the collection
+ # behavior is the same, it returns true if the collection
# based on the criteria has more than one record.
#
# person.pets
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index c3266f2bb4..d1458f30ba 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -114,11 +114,7 @@ module ActiveRecord
end
def target_reflection_has_associated_record?
- if through_reflection.macro == :belongs_to && owner[through_reflection.foreign_key].blank?
- false
- else
- true
- end
+ !(through_reflection.macro == :belongs_to && owner[through_reflection.foreign_key].blank?)
end
def update_through_counter?(method)
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 0857b02c8e..310f1b6e75 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -76,7 +76,7 @@ module ActiveRecord
end
def get_primary_key(base_name) #:nodoc:
- return 'id' unless base_name && !base_name.blank?
+ return 'id' if base_name.blank?
case primary_key_prefix_type
when :table_name
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index aab832c2f7..bf5793d454 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -162,12 +162,9 @@ module ActiveRecord #:nodoc:
#
# Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects
# by simple queries without turning to SQL. They work by appending the name of an attribute
- # to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt> and thus produces finders
- # like <tt>Person.find_by_user_name</tt>, <tt>Person.find_all_by_last_name</tt>, and
- # <tt>Payment.find_by_transaction_id</tt>. Instead of writing
- # <tt>Person.where(user_name: user_name).first</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
- # And instead of writing <tt>Person.where(last_name: last_name).all</tt>, you just do
- # <tt>Person.find_all_by_last_name(last_name)</tt>.
+ # to <tt>find_by_</tt> # like <tt>Person.find_by_user_name</tt>.
+ # Instead of writing # <tt>Person.where(user_name: user_name).first</tt>, you just do
+ # <tt>Person.find_by_user_name(user_name)</tt>.
#
# It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an
# <tt>ActiveRecord::RecordNotFound</tt> error if they do not return any records,
@@ -180,46 +177,7 @@ module ActiveRecord #:nodoc:
#
# It's even possible to call these dynamic finder methods on relations and named scopes.
#
- # Payment.order("created_on").find_all_by_amount(50)
- # Payment.pending.find_last_by_amount(100)
- #
- # The same dynamic finder style can be used to create the object if it doesn't already exist.
- # This dynamic finder is called with <tt>find_or_create_by_</tt> and will return the object if
- # it already exists and otherwise creates it, then returns it. Protected attributes won't be set
- # unless they are given in a block.
- #
- # # No 'Summer' tag exists
- # Tag.find_or_create_by_name("Summer") # equal to Tag.create(name: "Summer")
- #
- # # Now the 'Summer' tag does exist
- # Tag.find_or_create_by_name("Summer") # equal to Tag.find_by_name("Summer")
- #
- # # Now 'Bob' exist and is an 'admin'
- # User.find_or_create_by_name('Bob', age: 40) { |u| u.admin = true }
- #
- # Adding an exclamation point (!) on to the end of <tt>find_or_create_by_</tt> will
- # raise an <tt>ActiveRecord::RecordInvalid</tt> error if the new record is invalid.
- #
- # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without
- # saving it first. Protected attributes won't be set unless they are given in a block.
- #
- # # No 'Winter' tag exists
- # winter = Tag.find_or_initialize_by_name("Winter")
- # winter.persisted? # false
- #
- # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
- # a list of parameters.
- #
- # Tag.find_or_create_by_name(name: "rails", creator: current_user)
- #
- # That will either find an existing tag named "rails", or create a new one while setting the
- # user that created it.
- #
- # Just like <tt>find_by_*</tt>, you can also use <tt>scoped_by_*</tt> to retrieve data. The good thing about
- # using this feature is that the very first time result is returned using <tt>method_missing</tt> technique
- # but after that the method is declared on the class. Henceforth <tt>method_missing</tt> will not be hit.
- #
- # User.scoped_by_user_name('David')
+ # Payment.order("created_on").find_by_amount(50)
#
# == Saving arrays, hashes, and other non-mappable objects in text columns
#
diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb
index b4bb95a392..8e4ddcac82 100644
--- a/activerecord/lib/active_record/locking/pessimistic.rb
+++ b/activerecord/lib/active_record/locking/pessimistic.rb
@@ -26,7 +26,7 @@ module ActiveRecord
#
# Account.transaction do
# # select * from accounts where ...
- # accounts = Account.where(...).all
+ # accounts = Account.where(...)
# account1 = accounts.detect { |account| ... }
# account2 = accounts.detect { |account| ... }
# # select * from accounts where id=? for update
diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb
index 2366a91bb5..c1ba524c84 100644
--- a/activerecord/lib/active_record/log_subscriber.rb
+++ b/activerecord/lib/active_record/log_subscriber.rb
@@ -21,13 +21,15 @@ module ActiveRecord
end
def render_bind(column, value)
- if column.type == :binary
- rendered_value = "<#{value.bytesize} bytes of binary data>"
+ if column
+ if column.binary?
+ value = "<#{value.bytesize} bytes of binary data>"
+ end
+
+ [column.name, value]
else
- rendered_value = value
+ [nil, value]
end
-
- [column.name, rendered_value]
end
def sql(event)
diff --git a/activerecord/test/cases/deprecated_dynamic_methods_test.rb b/activerecord/test/cases/deprecated_dynamic_methods_test.rb
index 32eb87d522..8e842d8758 100644
--- a/activerecord/test/cases/deprecated_dynamic_methods_test.rb
+++ b/activerecord/test/cases/deprecated_dynamic_methods_test.rb
@@ -1,7 +1,7 @@
# This file should be deleted when activerecord-deprecated_finders is removed as
# a dependency.
#
-# It is kept for now as there is some fairly nuanced behaviour in the dynamic
+# It is kept for now as there is some fairly nuanced behavior in the dynamic
# finders so it is useful to keep this around to guard against regressions if
# we need to change the code.
diff --git a/activerecord/test/cases/log_subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb
index 345e83a102..57eac0c175 100644
--- a/activerecord/test/cases/log_subscriber_test.rb
+++ b/activerecord/test/cases/log_subscriber_test.rb
@@ -8,6 +8,19 @@ class LogSubscriberTest < ActiveRecord::TestCase
include ActiveSupport::LogSubscriber::TestHelper
include ActiveSupport::Logger::Severity
+ class TestDebugLogSubscriber < ActiveRecord::LogSubscriber
+ attr_reader :debugs
+
+ def initialize
+ @debugs = []
+ super
+ end
+
+ def debug message
+ @debugs << message
+ end
+ end
+
fixtures :posts
def setup
@@ -30,30 +43,27 @@ class LogSubscriberTest < ActiveRecord::TestCase
def test_schema_statements_are_ignored
event = Struct.new(:duration, :payload)
- logger = Class.new(ActiveRecord::LogSubscriber) {
- attr_accessor :debugs
-
- def initialize
- @debugs = []
- super
- end
-
- def debug message
- @debugs << message
- end
- }.new
+ logger = TestDebugLogSubscriber.new
assert_equal 0, logger.debugs.length
- logger.sql(event.new(0, { :sql => 'hi mom!' }))
+ logger.sql(event.new(0, sql: 'hi mom!'))
assert_equal 1, logger.debugs.length
- logger.sql(event.new(0, { :sql => 'hi mom!', :name => 'foo' }))
+ logger.sql(event.new(0, sql: 'hi mom!', name: 'foo'))
assert_equal 2, logger.debugs.length
- logger.sql(event.new(0, { :sql => 'hi mom!', :name => 'SCHEMA' }))
+ logger.sql(event.new(0, sql: 'hi mom!', name: 'SCHEMA'))
assert_equal 2, logger.debugs.length
end
+ def test_ignore_binds_payload_with_nil_column
+ event = Struct.new(:duration, :payload)
+
+ logger = TestDebugLogSubscriber.new
+ logger.sql(event.new(0, sql: 'hi mom!', binds: [[nil, 1]]))
+ assert_equal 1, logger.debugs.length
+ end
+
def test_basic_query_logging
Developer.all.load
wait
@@ -105,7 +115,7 @@ class LogSubscriberTest < ActiveRecord::TestCase
def test_binary_data_is_not_logged
skip if current_adapter?(:Mysql2Adapter)
- Binary.create(:data => 'some binary data')
+ Binary.create(data: 'some binary data')
wait
assert_match(/<16 bytes of binary data>/, @logger.logged(:debug).join)
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index 297e865308..f69a248491 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -82,6 +82,10 @@ module ActiveRecord
assert_equal 0, Post.where(:posts => {}).count
end
+ def test_where_with_table_name_and_empty_array
+ assert_equal 0, Post.where(:id => []).count
+ end
+
def test_where_with_empty_hash_and_no_foreign_key
assert_equal 0, Edge.where(:sink => {}).count
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 08bec2f4ae..5848f9712f 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,12 @@
## Rails 4.0.0 (unreleased) ##
+* Hash.from_xml raises when it encounters type="symbol" or type="yaml".
+ Use Hash.from_trusted_xml to parse this XML.
+
+ CVE-2013-0156
+
+ *Jeremy Kemper*
+
* Deprecate `assert_present` and `assert_blank` in favor of
`assert object.blank?` and `assert object.present?`
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index f1aff8a8e3..4b41e6247d 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -72,6 +72,9 @@ module ActiveSupport
@silencers = []
end
+ # Removes all filters, but leaves in silencers. Useful if you suddenly
+ # need to see entire filepaths in the backtrace that you had already
+ # filtered out.
def remove_filters!
@filters = []
end
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 64e9945ef5..430a35fbaf 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -8,7 +8,7 @@ class Array
# Converts the array to a comma-separated sentence where the last element is
# joined by the connector word.
#
- # You can pass the following options to change the default behaviour. If you
+ # You can pass the following options to change the default behavior. If you
# pass an option key that doesn't exist in the list below, it will raise an
# <tt>ArgumentError</tt>.
#
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 6cb7434e5f..8930376ac8 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -101,17 +101,33 @@ class Hash
#
# hash = Hash.from_xml(xml)
# # => {"hash"=>{"foo"=>1, "bar"=>2}}
- def from_xml(xml)
- ActiveSupport::XMLConverter.new(xml).to_h
+ #
+ # DisallowedType is raise if the XML contains attributes with <tt>type="yaml"</tt> or
+ # <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to parse this XML.
+ def from_xml(xml, disallowed_types = nil)
+ ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
end
+ # Builds a Hash from XML just like <tt>Hash.from_xml</tt>, but also allows Symbol and YAML.
+ def from_trusted_xml(xml)
+ from_xml xml, []
+ end
end
end
module ActiveSupport
class XMLConverter # :nodoc:
- def initialize(xml)
+ class DisallowedType < StandardError
+ def initialize(type)
+ super "Disallowed type attribute: #{type.inspect}"
+ end
+ end
+
+ DISALLOWED_TYPES = %w(symbol yaml)
+
+ def initialize(xml, disallowed_types = nil)
@xml = normalize_keys(XmlMini.parse(xml))
+ @disallowed_types = disallowed_types || DISALLOWED_TYPES
end
def to_h
@@ -119,7 +135,6 @@ module ActiveSupport
end
private
-
def normalize_keys(params)
case params
when Hash
@@ -145,6 +160,10 @@ module ActiveSupport
end
def process_hash(value)
+ if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type'])
+ raise DisallowedType, value['type']
+ end
+
if become_array?(value)
_, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
if entries.nil? || value['__content__'].try(:empty?)
diff --git a/activesupport/lib/active_support/core_ext/object/acts_like.rb b/activesupport/lib/active_support/core_ext/object/acts_like.rb
index fcc8e50f06..3912cc5ace 100644
--- a/activesupport/lib/active_support/core_ext/object/acts_like.rb
+++ b/activesupport/lib/active_support/core_ext/object/acts_like.rb
@@ -1,9 +1,9 @@
class Object
# A duck-type assistant method. For example, Active Support extends Date
- # to define an acts_like_date? method, and extends Time to define
- # acts_like_time?. As a result, we can do "x.acts_like?(:time)" and
- # "x.acts_like?(:date)" to do duck-type-safe comparisons, since classes that
- # we want to act like Time simply need to define an acts_like_time? method.
+ # to define an <tt>acts_like_date?</tt> method, and extends Time to define
+ # <tt>acts_like_time?</tt>. As a result, we can do <tt>x.acts_like?(:time)</tt> and
+ # <tt>x.acts_like?(:date)</tt> to do duck-type-safe comparisons, since classes that
+ # we want to act like Time simply need to define an <tt>acts_like_time?</tt> method.
def acts_like?(duck)
respond_to? :"acts_like_#{duck}?"
end
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 40821fd619..755e1c6b16 100644
--- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb
+++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -13,7 +13,7 @@ class Object
Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
end
- # Returns an array of instance variable names including "@".
+ # Returns an array of instance variable names as strings including "@".
#
# class C
# def initialize(x, y)
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 832d1ce6d5..9bf1ea35b3 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -235,7 +235,7 @@ class BigDecimal
# real value.
#
# Use <tt>ActiveSupport.use_standard_json_big_decimal_format = true</tt> to
- # override this behaviour.
+ # override this behavior.
def as_json(options = nil) #:nodoc:
if finite?
ActiveSupport.encode_big_decimal_as_string ? to_s : self
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 63dad7e01a..f9a98686d3 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -15,7 +15,7 @@ module ActiveSupport
# end
#
# def test_basic_query_logging
- # Developer.all
+ # Developer.all.to_a
# wait
# assert_equal 1, @logger.logged(:debug).size
# assert_match(/Developer Load/, @logger.logged(:debug).last)
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index fdaaacf2fe..d3741845d2 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -109,6 +109,14 @@ module ActiveSupport
alias_method :gmt_offset, :utc_offset
alias_method :gmtoff, :utc_offset
+ # Returns a formatted string of the offset from UTC, or an alternative
+ # string if the time zone is already UTC.
+ #
+ # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
+ # Time.zone.now.formatted_offset(true) # => "-05:00"
+ # Time.zone.now.formatted_offset(false) # => "-0500"
+ # Time.zone = 'UTC' # => "UTC"
+ # Time.zone.now.formatted_offset(true, "0") # => "0"
def formatted_offset(colon = true, alternate_utc_string = nil)
utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon)
end
@@ -206,18 +214,24 @@ module ActiveSupport
utc <=> other
end
+ # Returns true if the current object's time is within the specified
+ # +min+ and +max+ time.
def between?(min, max)
utc.between?(min, max)
end
+ # Returns true if the current object's time is in the past.
def past?
utc.past?
end
+ # Returns true if the current object's time falls within
+ # the current day.
def today?
time.today?
end
+ # Returns true if the current object's time is in the future.
def future?
utc.future?
end
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 84dd9bc983..30d95b75bc 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -1015,12 +1015,10 @@ class HashToXmlTest < ActiveSupport::TestCase
<replies-close-in type="integer">2592000000</replies-close-in>
<written-on type="date">2003-07-16</written-on>
<viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
- <content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
<author-email-address>david@loudthinking.com</author-email-address>
<parent-id></parent-id>
<ad-revenue type="decimal">1.5</ad-revenue>
<optimum-viewing-angle type="float">135</optimum-viewing-angle>
- <resident type="symbol">yes</resident>
</topic>
EOT
@@ -1033,12 +1031,10 @@ class HashToXmlTest < ActiveSupport::TestCase
:replies_close_in => 2592000000,
:written_on => Date.new(2003, 7, 16),
:viewed_at => Time.utc(2003, 7, 16, 9, 28),
- :content => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
:author_email_address => "david@loudthinking.com",
:parent_id => nil,
:ad_revenue => BigDecimal("1.50"),
:optimum_viewing_angle => 135.0,
- :resident => :yes
}.stringify_keys
assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"]
@@ -1052,7 +1048,6 @@ class HashToXmlTest < ActiveSupport::TestCase
<approved type="boolean"></approved>
<written-on type="date"></written-on>
<viewed-at type="datetime"></viewed-at>
- <content type="yaml"></content>
<parent-id></parent-id>
</topic>
EOT
@@ -1063,7 +1058,6 @@ class HashToXmlTest < ActiveSupport::TestCase
:approved => nil,
:written_on => nil,
:viewed_at => nil,
- :content => nil,
:parent_id => nil
}.stringify_keys
@@ -1290,6 +1284,28 @@ class HashToXmlTest < ActiveSupport::TestCase
assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"]
end
+ def test_from_xml_raises_on_disallowed_type_attributes
+ assert_raise ActiveSupport::XMLConverter::DisallowedType do
+ Hash.from_xml '<product><name type="foo">value</name></product>', %w(foo)
+ end
+ end
+
+ def test_from_xml_disallows_symbol_and_yaml_types_by_default
+ assert_raise ActiveSupport::XMLConverter::DisallowedType do
+ Hash.from_xml '<product><name type="symbol">value</name></product>'
+ end
+
+ assert_raise ActiveSupport::XMLConverter::DisallowedType do
+ Hash.from_xml '<product><name type="yaml">value</name></product>'
+ end
+ end
+
+ def test_from_trusted_xml_allows_symbol_and_yaml_types
+ expected = { 'product' => { 'name' => :value }}
+ assert_equal expected, Hash.from_trusted_xml('<product><name type="symbol">value</name></product>')
+ assert_equal expected, Hash.from_trusted_xml('<product><name type="yaml">:value</name></product>')
+ end
+
def test_should_use_default_value_for_unknown_key
hash_wia = HashWithIndifferentAccess.new(3)
assert_equal 3, hash_wia[:new_key]
diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md
index 002e1da5af..2242b2699f 100644
--- a/guides/source/4_0_release_notes.md
+++ b/guides/source/4_0_release_notes.md
@@ -85,7 +85,7 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/railt
* New test locations `test/models`, `test/helpers`, `test/controllers`, and `test/mailers`. Corresponding rake tasks added as well. ([Pull Request](https://github.com/rails/rails/pull/7878))
-* Your app's executables now live in the `bin/` dir. Run `rake update:bin` to get `bin/bundle`, `bin/rails`, and `bin/rake`.
+* Your app's executables now live in the `bin/` dir. Run `rake rails:update:bin` to get `bin/bundle`, `bin/rails`, and `bin/rake`.
* Threadsafe on by default
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index e0408cadda..cc80334af3 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -174,10 +174,10 @@ Session
Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and the view and can use one of a number of different storage mechanisms:
-* ActionDispatch::Session::CookieStore - Stores everything on the client.
-* ActionDispatch::Session::CacheStore - Stores the data in the Rails cache.
-* @ActionDispatch::Session::ActiveRecordStore@ - Stores the data in a database using Active Record. (require `activerecord-session_store` gem).
-* @ActionDispatch::Session::MemCacheStore@ - Stores the data in a memcached cluster (this is a legacy implementation; consider using CacheStore instead).
+* `ActionDispatch::Session::CookieStore` - Stores everything on the client.
+* `ActionDispatch::Session::CacheStore` - Stores the data in the Rails cache.
+* `ActionDispatch::Session::ActiveRecordStore` - Stores the data in a database using Active Record. (require `activerecord-session_store` gem).
+* `ActionDispatch::Session::MemCacheStore` - Stores the data in a memcached cluster (this is a legacy implementation; consider using CacheStore instead).
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md
index c90f42c492..062bcd49f4 100644
--- a/guides/source/active_record_basics.md
+++ b/guides/source/active_record_basics.md
@@ -239,12 +239,12 @@ Active Record provides a rich API for accessing data within a database. Below
are a few examples of different data access methods provided by Active Record.
```ruby
-# return array with all records
+# return a collection with all users
users = User.all
```
```ruby
-# return the first record
+# return the first user
user = User.first
```
diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md
index 20959a1a35..3747b00b82 100644
--- a/guides/source/active_record_callbacks.md
+++ b/guides/source/active_record_callbacks.md
@@ -168,7 +168,6 @@ Additionally, the `after_find` callback is triggered by the following finder met
* `all`
* `first`
* `find`
-* `find_all_by_*`
* `find_by_*`
* `find_by_*!`
* `find_by_sql`
@@ -176,7 +175,7 @@ Additionally, the `after_find` callback is triggered by the following finder met
The `after_initialize` callback is triggered every time a new object of the class is initialized.
-NOTE: The `find_all_by_*`, `find_by_*` and `find_by_*!` methods are dynamic finders generated automatically for every attribute. Learn more about them at the [Dynamic finders section](active_record_querying.html#dynamic-finders)
+NOTE: The `find_by_*` and `find_by_*!` methods are dynamic finders generated automatically for every attribute. Learn more about them at the [Dynamic finders section](active_record_querying.html#dynamic-finders)
Skipping Callbacks
------------------
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index 24f98f68ca..62d6294ae5 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1228,9 +1228,7 @@ Client.unscoped {
Dynamic Finders
---------------
-For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` and `find_all_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` and `find_all_by_locked` methods.
-
-You can also use `find_last_by_*` methods which will find the last record matching your argument.
+For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called `first_name` on your `Client` model for example, you get `find_by_first_name` for free from Active Record. If you have a `locked` field on the `Client` model, you also get `find_by_locked` and methods.
You can specify an exclamation point (`!`) on the end of the dynamic finders to get them to raise an `ActiveRecord::RecordNotFound` error if they do not return any records, like `Client.find_by_name!("Ryan")`
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index 7f03363b23..3c1bb0f132 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -422,24 +422,6 @@ NOTE: Defined in `active_support/core_ext/object/with_options.rb`.
Active Support provides several methods to ease access to instance variables.
-#### `instance_variable_names`
-
-Ruby 1.8 and 1.9 have a method called `instance_variables` that returns the names of the defined instance variables. But they behave differently, in 1.8 it returns strings whereas in 1.9 it returns symbols. Active Support defines `instance_variable_names` as a portable way to obtain them as strings:
-
-```ruby
-class C
- def initialize(x, y)
- @x, @y = x, y
- end
-end
-
-C.new(0, 1).instance_variable_names # => ["@y", "@x"]
-```
-
-WARNING: The order in which the names are returned is unspecified, and it indeed depends on the version of the interpreter.
-
-NOTE: Defined in `active_support/core_ext/object/instance_variables.rb`.
-
#### `instance_values`
The method `instance_values` returns a hash that maps instance variable names without "@" to their
@@ -1449,11 +1431,10 @@ As the previous example shows, Active Support knows some irregular plurals and u
Active Record uses this method to compute the default table name that corresponds to a model:
```ruby
-# active_record/base.rb
+# active_record/model_schema.rb
def undecorated_table_name(class_name = base_class.name)
table_name = class_name.to_s.demodulize.underscore
- table_name = table_name.pluralize if pluralize_table_names
- table_name
+ pluralize_table_names ? table_name.pluralize : table_name
end
```
diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md
index 773102400a..0228d463cf 100644
--- a/guides/source/caching_with_rails.md
+++ b/guides/source/caching_with_rails.md
@@ -30,101 +30,13 @@ config.action_controller.perform_caching = true
Page caching is a Rails mechanism which allows the request for a generated page to be fulfilled by the webserver (i.e. Apache or nginx), without ever having to go through the Rails stack at all. Obviously, this is super-fast. Unfortunately, it can't be applied to every situation (such as pages that need authentication) and since the webserver is literally just serving a file from the filesystem, cache expiration is an issue that needs to be dealt with.
-To enable page caching, you need to use the `caches_page` method.
-
-```ruby
-class ProductsController < ActionController
-
- caches_page :index
-
- def index
- @products = Product.all
- end
-end
-```
-
-Let's say you have a controller called `ProductsController` and an `index` action that lists all the products. The first time anyone requests `/products`, Rails will generate a file called `products.html` and the webserver will then look for that file before it passes the next request for `/products` to your Rails application.
-
-By default, the page cache directory is set to `Rails.public_path` (which is usually set to the `public` folder) and this can be configured by changing the configuration setting `config.action_controller.page_cache_directory`. Changing the default from `public` helps avoid naming conflicts, since you may want to put other static html in `public`, but changing this will require web server reconfiguration to let the web server know where to serve the cached files from.
-
-The Page Caching mechanism will automatically add a `.html` extension to requests for pages that do not have an extension to make it easy for the webserver to find those pages and this can be configured by changing the configuration setting `config.action_controller.default_static_extension`.
-
-In order to expire this page when a new product is added we could extend our example controller like this:
-
-```ruby
-class ProductsController < ActionController
-
- caches_page :index
-
- def index
- @products = Product.all
- end
-
- def create
- expire_page action: :index
- end
-
-end
-```
-
-By default, page caching automatically gzips files (for example, to `products.html.gz` if user requests `/products`) to reduce the size of data transmitted (web servers are typically configured to use a moderate compression ratio as a compromise, but since precompilation happens once, compression ratio is maximum).
-
-Nginx is able to serve compressed content directly from disk by enabling `gzip_static`:
-
-```nginx
-location / {
- gzip_static on; # to serve pre-gzipped version
-}
-```
-
-You can disable gzipping by setting `:gzip` option to false (for example, if action returns image):
-
-```ruby
-caches_page :image, gzip: false
-```
-
-Or, you can set custom gzip compression level (level names are taken from `Zlib` constants):
-
-```ruby
-caches_page :image, gzip: :best_speed
-```
-
-NOTE: Page caching ignores all parameters. For example `/products?page=1` will be written out to the filesystem as `products.html` with no reference to the `page` parameter. Thus, if someone requests `/products?page=2` later, they will get the cached first page. A workaround for this limitation is to include the parameters in the page's path, e.g. `/products/page/1`.
-
-INFO: Page caching runs in an after filter. Thus, invalid requests won't generate spurious cache entries as long as you halt them. Typically, a redirection in some before filter that checks request preconditions does the job.
+INFO: Page Caching has been removed from Rails 4. See the [actionpack-page_caching gem](https://github.com/rails/actionpack-page_caching)
### Action Caching
Page Caching cannot be used for actions that have before filters - for example, pages that require authentication. This is where Action Caching comes in. Action Caching works like Page Caching except the incoming web request hits the Rails stack so that before filters can be run on it before the cache is served. This allows authentication and other restrictions to be run while still serving the result of the output from a cached copy.
-Clearing the cache works in a similar way to Page Caching, except you use `expire_action` instead of `expire_page`.
-
-Let's say you only wanted authenticated users to call actions on `ProductsController`.
-
-```ruby
-class ProductsController < ActionController
-
- before_action :authenticate
- caches_action :index
-
- def index
- @products = Product.all
- end
-
- def create
- expire_action action: :index
- end
-
-end
-```
-
-You can also use `:if` (or `:unless`) to pass a Proc that specifies when the action should be cached. Also, you can use `layout: false` to cache without layout so that dynamic information in the layout such as logged in user info or the number of items in the cart can be left uncached. This feature is available as of Rails 2.2.
-
-You can modify the default action cache path by passing a `:cache_path` option. This will be passed directly to `ActionCachePath.path_for`. This is handy for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance.
-
-Finally, if you are using memcached or Ehcache, you can also pass `:expires_in`. In fact, all parameters not used by `caches_action` are sent to the underlying cache store.
-
-INFO: Action caching runs in an after filter. Thus, invalid requests won't generate spurious cache entries as long as you halt them. Typically, a redirection in some before filter that checks request preconditions does the job.
+INFO: Action Caching has been removed from Rails 4. See the [actionpack-action_caching gem](https://github.com/rails/actionpack-action_caching)
### Fragment Caching
@@ -196,10 +108,6 @@ class ProductsController < ActionController
end
```
-The second time the same query is run against the database, it's not actually going to hit the database. The first time the result is returned from the query it is stored in the query cache (in memory) and the second time it's pulled from memory.
-
-However, it's important to note that query caches are created at the start of an action and destroyed at the end of that action and thus persist only for the duration of the action. If you'd like to store query results in a more persistent fashion, you can in Rails by using low level caching.
-
Cache Stores
------------
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index fb15790d90..12d39ea1cc 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -225,7 +225,8 @@ $ rails generate scaffold HighScore game:string score:integer
invoke test_unit
create test/models/high_score_test.rb
create test/fixtures/high_scores.yml
- route resources :high_scores
+ invoke resource_route
+ route resources :high_scores
invoke scaffold_controller
create app/controllers/high_scores_controller.rb
invoke erb
@@ -563,14 +564,20 @@ We had to create the **gitapp** directory and initialize an empty git repository
$ cat config/database.yml
# PostgreSQL. Versions 8.2 and up are supported.
#
-# Install the ruby-postgres driver:
-# gem install ruby-postgres
-# On Mac OS X:
-# gem install ruby-postgres -- --include=/usr/local/pgsql
+# Install the pg driver:
+# gem install pg
+# On OS X with Homebrew:
+# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
+# On OS X with MacPorts:
+# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
-# gem install ruby-postgres
+# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
+#
+# Configure Using Gemfile
+# gem 'pg'
+#
development:
adapter: postgresql
encoding: unicode
@@ -585,28 +592,3 @@ development:
It also generated some lines in our database.yml configuration corresponding to our choice of PostgreSQL for database.
NOTE. The only catch with using the SCM options is that you have to make your application's directory first, then initialize your SCM, then you can run the `rails new` command to generate the basis of your app.
-
-### `server` with Different Backends
-
-Many people have created a large number of different web servers in Ruby, and many of them can be used to run Rails. Since version 2.3, Rails uses Rack to serve its webpages, which means that any webserver that implements a Rack handler can be used. This includes WEBrick, Mongrel, Thin, and Phusion Passenger (to name a few!).
-
-NOTE: For more details on the Rack integration, see [Rails on Rack](rails_on_rack.html).
-
-To use a different server, just install its gem, then use its name for the first parameter to `rails server`:
-
-```bash
-$ sudo gem install mongrel
-Building native extensions. This could take a while...
-Building native extensions. This could take a while...
-Successfully installed gem_plugin-0.2.3
-Successfully installed fastthread-1.0.1
-Successfully installed cgi_multipart_eof_fix-2.5.0
-Successfully installed mongrel-1.1.5
-...
-...
-Installing RDoc documentation for mongrel-1.1.5...
-$ rails server mongrel
-=> Booting Mongrel (use 'rails server webrick' to force WEBrick)
-=> Rails 3.1.0 application starting on http://0.0.0.0:3000
-...
-```
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 5fe8e2fba6..ced04bbbc0 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -304,6 +304,8 @@ The schema dumper adds one additional configuration option:
* `config.action_controller.permit_all_parameters` sets all the parameters for mass assignment to be permitted by default. The default value is `false`.
+* `config.action_controller.raise_on_unpermitted_parameters` enables raising an exception if parameters that are not explicitly permitted are found. The default value is `true` in development and test environments, `false` otherwise.
+
### Configuring Action Dispatch
* `config.action_dispatch.session_store` sets the name of the store for session data. The default is `:cookie_store`; other valid options include `:active_record_store`, `:mem_cache_store` or the name of your own custom class.
@@ -583,7 +585,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 behavior 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/credits.html.erb b/guides/source/credits.html.erb
index e25168d58d..ff76fa2b85 100644
--- a/guides/source/credits.html.erb
+++ b/guides/source/credits.html.erb
@@ -28,7 +28,7 @@ Ruby on Rails Guides: Credits
<h3 class="section">Rails Guides Authors</h3>
<%= author('Ryan Bigg', 'radar', 'radar.png') do %>
-Ryan Bigg works as a consultant at <a href="http://rubyx.com">RubyX</a> and has been working with Rails since 2006. He's co-authoring a book called <a href="http://manning.com/katz">Rails 3 in Action</a> and he's written many gems which can be seen on <a href="http://github.com/radar">his GitHub page</a> and he also tweets prolifically as <a href="http://twitter.com/ryanbigg">@ryanbigg</a>.
+Ryan Bigg works as a consultant at <a href="http://rubyx.com">RubyX</a> and has been working with Rails since 2006. He's co-authoring a book called <a href="http://manning.com/katz">Rails 3 in Action</a> and he's written many gems which can be seen on <a href="https://github.com/radar">his GitHub page</a> and he also tweets prolifically as <a href="http://twitter.com/ryanbigg">@ryanbigg</a>.
<% end %>
<%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %>
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index 524fe46408..5531dee343 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -664,7 +664,7 @@ References
----------
* [ruby-debug Homepage](http://bashdb.sourceforge.net/ruby-debug/home-page.html)
-* [debugger Homepage](http://github.com/cldwalker/debugger)
+* [debugger Homepage](https://github.com/cldwalker/debugger)
* [Article: Debugging a Rails application with ruby-debug](http://www.sitepoint.com/article/debug-rails-app-ruby-debug/)
* [ruby-debug Basics screencast](http://brian.maybeyoureinsane.net/blog/2007/05/07/ruby-debug-basics-screencast/)
* [Ryan Bates' debugging ruby (revised) screencast](http://railscasts.com/episodes/54-debugging-ruby-revised)
diff --git a/guides/source/engines.md b/guides/source/engines.md
index 8c0cbed3f2..f35233993c 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -16,9 +16,9 @@ After reading this guide, you will know:
What are engines?
-----------------
-Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the `Rails::Application` class inheriting a lot of its behaviour from `Rails::Engine`.
+Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the `Rails::Application` class inheriting a lot of its behavior from `Rails::Engine`.
-Therefore, engines and applications can be thought of almost the same thing, just with very minor differences, as you'll see throughout this guide. Engines and applications also share a common structure.
+Therefore, engines and applications can be thought of almost the same thing, just with subtle differences, as you'll see throughout this guide. Engines and applications also share a common structure.
Engines are also closely related to plugins where the two share a common `lib` directory structure and are both generated using the `rails plugin new` generator. The difference being that an engine is considered a "full plugin" by Rails as indicated by the `--full` option that's passed to the generator command, but this guide will refer to them simply as "engines" throughout. An engine **can** be a plugin, and a plugin **can** be an engine.
@@ -171,7 +171,7 @@ end
This line mounts the engine at the path `/blorgh`, which will make it accessible through the application only at that path.
-Also in the test directory is the `test/integration` directory, where integration tests for the engine should be placed. Other directories can be created in the `test` directory also. For example, you may wish to create a `test/models` directory for your models tests.
+In the test directory there is the `test/integration` directory, where integration tests for the engine should be placed. Other directories can be created in the `test` directory as well. For example, you may wish to create a `test/models` directory for your models tests.
Providing engine functionality
------------------------------
@@ -232,7 +232,8 @@ Blorgh::Engine.routes.draw do
end
```
-Note here that the routes are drawn upon the `Blorgh::Engine` object rather than the `YourApp::Application` class. This is so that the engine routes are confined to the engine itself and can be mounted at a specific point as shown in the [test directory](#test-directory) section. This is also what causes the engine's routes to be isolated from those routes that are within the application. This is discussed further in the [Routes](#routes) section of this guide.
+Note here that the routes are drawn upon the `Blorgh::Engine` object rather than the `YourApp::Application` class. This is so that the engine routes are confined to the engine itself and can be mounted at a specific point as shown in the [test directory](#test-directory) section. It also causes the engine's routes to be isolated from those routes that are within the application. The [Routes](#routes) section of
+this guide describes it in details.
Next, the `scaffold_controller` generator is invoked, generating a controller called `Blorgh::PostsController` (at `app/controllers/blorgh/posts_controller.rb`) and its related views at `app/views/blorgh/posts`. This generator also generates a test for the controller (`test/controllers/blorgh/posts_controller_test.rb`) and a helper (`app/helpers/blorgh/posts_controller.rb`).
@@ -258,7 +259,7 @@ module Blorgh
end
```
-This helps prevent conflicts with any other engine or application that may have a post resource also.
+This helps prevent conflicts with any other engine or application that may have a post resource as well.
Finally, two files that are the assets for this resource are generated, `app/assets/javascripts/blorgh/posts.js` and `app/assets/javascripts/blorgh/posts.css`. You'll see how to use these a little later.
@@ -287,7 +288,7 @@ Now people will only need to go to the root of the engine to see all the posts,
### Generating a comments resource
-Now that the engine has the ability to create new blog posts, it only makes sense to add commenting functionality as well. To do get this, you'll need to generate a comment model, a comment controller and then modify the posts scaffold to display comments and allow people to create new ones.
+Now that the engine can to create new blog posts, it only makes sense to add commenting functionality as well. To do get this, you'll need to generate a comment model, a comment controller and then modify the posts scaffold to display comments and allow people to create new ones.
Run the model generator and tell it to generate a `Comment` model, with the related table having two columns: a `post_id` integer and `text` text column.
@@ -531,7 +532,7 @@ before_save :set_author
private
def set_author
- self.author = User.find_or_create_by_name(author_name)
+ self.author = User.find_or_create_by(name: author_name)
end
```
@@ -630,7 +631,7 @@ belongs_to :author, class_name: Blorgh.user_class
The `set_author` method also located in this class should also use this class:
```ruby
-self.author = Blorgh.user_class.constantize.find_or_create_by_name(author_name)
+self.author = Blorgh.user_class.constantize.find_or_create_by(name: author_name)
```
To save having to call `constantize` on the `user_class` result all the time, you could instead just override the `user_class` getter method inside the `Blorgh` module in the `lib/blorgh.rb` file to always call `constantize` on the saved value before returning the result:
@@ -644,10 +645,10 @@ end
This would then turn the above code for `set_author` into this:
```ruby
-self.author = Blorgh.user_class.find_or_create_by_name(author_name)
+self.author = Blorgh.user_class.find_or_create_by(name: author_name)
```
-Resulting in something a little shorter, and more implicit in its behaviour. The `user_class` method should always return a `Class` object.
+Resulting in something a little shorter, and more implicit in its behavior. The `user_class` method should always return a `Class` object.
To set this configuration setting within the application, an initializer should be used. By using an initializer, the configuration will be set up before the application starts and calls the engine's models which may depend on this configuration setting existing.
@@ -661,7 +662,7 @@ WARNING: It's very important here to use the `String` version of the class, rath
Go ahead and try to create a new post. You will see that it works exactly in the same way as before, except this time the engine is using the configuration setting in `config/initializers/blorgh.rb` to learn what the class is.
-There are now no strict dependencies on what the class is, only what the API for the class must be. The engine simply requires this class to define a `find_or_create_by_name` method which returns an object of that class to be associated with a post when it's created. This object, of course, should have some sort of identifier by which it can be referenced.
+There are now no strict dependencies on what the class is, only what the API for the class must be. The engine simply requires this class to define a `find_or_create_by` method which returns an object of that class to be associated with a post when it's created. This object, of course, should have some sort of identifier by which it can be referenced.
#### General engine configuration
@@ -800,7 +801,7 @@ module Blorgh::Concerns::Models::Post
private
def set_author
- self.author = User.find_or_create_by_name(author_name)
+ self.author = User.find_or_create_by(name: author_name)
end
end
@@ -914,9 +915,10 @@ For more information, read the [Asset Pipeline guide](http://guides.rubyonrails.
### Other gem dependencies
-Gem dependencies inside an engine should be specified inside the `.gemspec` file at the root of the engine. The reason for this is because the engine may
+Gem dependencies inside an engine should be specified inside the
+`.gemspec` file at the root of the engine. The reason is that the engine may
be installed as a gem. If dependencies were to be specified inside the `Gemfile`,
-these would not be recognised by a traditional gem install and so they would not
+these would not be recognized by a traditional gem install and so they would not
be installed, causing the engine to malfunction.
To specify a dependency that should be installed with the engine during a
diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md
index b7145c46dc..b8681d493a 100644
--- a/guides/source/form_helpers.md
+++ b/guides/source/form_helpers.md
@@ -238,7 +238,7 @@ end
The corresponding view `app/views/articles/new.html.erb` using `form_for` looks like this:
```erb
-<%= form_for @article, url: {action: "create"}, html => {class: "nifty_form"} do |f| %>
+<%= form_for @article, url: {action: "create"}, html: {class: "nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, size: "60x12" %>
<%= f.submit "Create" %>
@@ -428,7 +428,7 @@ WARNING: when `:inlude_blank` or `:prompt:` are not present, `:include_blank` is
You can add arbitrary attributes to the options using hashes:
```html+erb
-<%= options_for_select([['Lisbon', 1, 'data-size': '2.8 million'], ['Madrid', 2, 'data-size': '3.2 million']], 2) %>
+<%= options_for_select([['Lisbon', 1, {'data-size' => '2.8 million'}], ['Madrid', 2, {'data-size' => '3.2 million'}]], 2) %>
output:
@@ -497,7 +497,7 @@ To leverage time zone support in Rails, you have to ask your users what time zon
There is also `time_zone_options_for_select` helper for a more manual (therefore more customizable) way of doing this. Read the API documentation to learn about the possible arguments for these two methods.
-Rails _used_ to have a `country_select` helper for choosing countries, but this has been extracted to the [country_select plugin](https://github.com/chrislerum/country_select). When using this, be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from Rails).
+Rails _used_ to have a `country_select` helper for choosing countries, but this has been extracted to the [country_select plugin](https://github.com/stefanpenner/country_select). When using this, be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from Rails).
Using Date and Time Form Helpers
--------------------------------
diff --git a/guides/source/generators.md b/guides/source/generators.md
index 62de5a70bb..8b91dfc5a5 100644
--- a/guides/source/generators.md
+++ b/guides/source/generators.md
@@ -176,7 +176,8 @@ $ rails generate scaffold User name:string
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
- route resources :users
+ invoke resource_route
+ route resources :users
invoke scaffold_controller
create app/controllers/users_controller.rb
invoke erb
@@ -192,8 +193,13 @@ $ rails generate scaffold User name:string
create app/helpers/users_helper.rb
invoke test_unit
create test/helpers/users_helper_test.rb
- invoke stylesheets
- create app/assets/stylesheets/scaffold.css
+ invoke assets
+ invoke coffee
+ create app/assets/javascripts/users.js.coffee
+ invoke scss
+ create app/assets/stylesheets/users.css.scss
+ invoke scss
+ create app/assets/stylesheets/scaffolds.css.scss
```
Looking at this output, it's easy to understand how generators work in Rails 3.0 and above. The scaffold generator doesn't actually generate anything, it just invokes others to do the work. This allows us to add/replace/remove any of those invocations. For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication.
@@ -350,6 +356,7 @@ $ rails generate scaffold Comment body:text
invoke shoulda
create test/models/comment_test.rb
create test/fixtures/comments.yml
+ invoke resource_route
route resources :comments
invoke scaffold_controller
create app/controllers/comments_controller.rb
@@ -360,13 +367,16 @@ $ rails generate scaffold Comment body:text
create app/views/comments/show.html.erb
create app/views/comments/new.html.erb
create app/views/comments/_form.html.erb
- create app/views/layouts/comments.html.erb
invoke shoulda
create test/controllers/comments_controller_test.rb
invoke my_helper
create app/helpers/comments_helper.rb
invoke shoulda
create test/helpers/comments_helper_test.rb
+ invoke assets
+ invoke coffee
+ create app/assets/javascripts/comments.js.coffee
+ invoke scss
```
Fallbacks allow your generators to have a single responsibility, increasing code reuse and reducing the amount of duplication.
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 7b119a027f..7d86b3866a 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -45,7 +45,7 @@ code while accomplishing more than many other languages and frameworks.
Experienced Rails developers also report that it makes web application
development more fun.
-Rails is opinionated software. It makes the assumption that there is a "best"
+Rails is opinionated software. It makes the assumption that there is the "best"
way to do things, and it's designed to encourage that way - and in some cases to
discourage alternatives. If you learn "The Rails Way" you'll probably discover a
tremendous increase in productivity. If you persist in bringing old habits from
@@ -71,7 +71,9 @@ By following along with this guide, you'll create a Rails project called
(very) simple weblog. Before you can start building the application, you need to
make sure that you have Rails itself installed.
-TIP: The examples below use # and $ to denote superuser and regular user terminal prompts respectively in a UNIX-like OS. If you are using Windows, your prompt will look something like c:\source_code>
+TIP: The examples below use `#` and `$` to denote superuser and regular
+user terminal prompts respectively in a UNIX-like OS. If you are using
+Windows, your prompt will look something like `c:\source_code>`
### Installing Rails
@@ -829,7 +831,7 @@ it look as follows:
<h1>Editing post</h1>
<%= form_for :post, url: { action: :update, id: @post.id },
-method: :put do |f| %>
+method: :patch do |f| %>
<% if @post.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited
@@ -862,7 +864,7 @@ method: :put do |f| %>
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
+The `method: :patch` option tells Rails that we want this form to be
submitted via the `PUT` HTTP method which is the HTTP method you're expected to use to
**update** resources according to the REST protocol.
@@ -872,7 +874,7 @@ 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"
+patch "posts/:id" => "posts#update"
```
And then create the `update` action in `app/controllers/posts_controller.rb`:
@@ -1050,7 +1052,7 @@ 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`
+NOTE: The `:as` option is available on the `post`, `patch`, `put`, `delete` and `match`
routing methods also.
### Deleting Posts
@@ -1144,7 +1146,7 @@ get "posts/new"
post "posts" => "posts#create"
get "posts/:id" => "posts#show", as: :post
get "posts/:id/edit" => "posts#edit"
-put "posts/:id" => "posts#update"
+patch "posts/:id" => "posts#update"
delete "posts/:id" => "posts#destroy"
```
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index 2e61bea5ea..69232d9bd4 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -897,7 +897,7 @@ The I18n API will catch all of these exceptions when they are thrown in the back
The reason for this is that during development you'd usually want your views to still render even though a translation is missing.
-In other contexts you might want to change this behaviour, though. E.g. the default exception handling does not allow to catch missing translations during automated tests easily. For this purpose a different exception handler can be specified. The specified exception handler must be a method on the I18n module or a class with `#call` method:
+In other contexts you might want to change this behavior, though. E.g. the default exception handling does not allow to catch missing translations during automated tests easily. For this purpose a different exception handler can be specified. The specified exception handler must be a method on the I18n module or a class with `#call` method:
```ruby
module I18n
@@ -927,7 +927,7 @@ else
end
```
-Another example where the default behaviour is less desirable is the Rails TranslationHelper which provides the method `#t` (as well as `#translate`). When a `MissingTranslationData` exception occurs in this context, the helper wraps the message into a span with the CSS class `translation_missing`.
+Another example where the default behavior is less desirable is the Rails TranslationHelper which provides the method `#t` (as well as `#translate`). When a `MissingTranslationData` exception occurs in this context, the helper wraps the message into a span with the CSS class `translation_missing`.
To do so, the helper forces `I18n#translate` to raise exceptions no matter what exception handler is defined by setting the `:raise` option:
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index fa303745b8..7c26512046 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -97,7 +97,7 @@ NOTE: The actual rendering is done by subclasses of `ActionView::TemplateHandler
### Using `render`
-In most cases, the `ActionController::Base#render` method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customize the behaviour of `render`. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.
+In most cases, the `ActionController::Base#render` method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customize the behavior of `render`. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.
TIP: If you want to see the exact results of a call to `render` without needing to inspect it in a browser, you can call `render_to_string`. This method takes exactly the same options as `render`, but it returns a string instead of sending a response back to the browser.
diff --git a/guides/source/nested_model_forms.md b/guides/source/nested_model_forms.md
index 2b46a9d51e..93d8e8dfcd 100644
--- a/guides/source/nested_model_forms.md
+++ b/guides/source/nested_model_forms.md
@@ -56,7 +56,7 @@ end
### Custom model
-As you might have inflected from this explanation, you _don’t_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behaviour:
+As you might have inflected from this explanation, you _don’t_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behavior:
#### Single associated object
diff --git a/guides/source/performance_testing.md b/guides/source/performance_testing.md
index ee0059623c..6bc175d3b6 100644
--- a/guides/source/performance_testing.md
+++ b/guides/source/performance_testing.md
@@ -426,19 +426,11 @@ will behave much as they do in the `production` environment.
To get the best from Rails' performance tests under MRI, you'll need to build
a special Ruby binary with some super powers.
-The recommended patches for each MRI version are:
-
-| Version | Patch |
-| --------------- | --------- |
-| 1.8.6 | ruby186gc |
-| 1.8.7 | ruby187gc |
-| 1.9.2 and above | gcdata |
-
-All of these can be found on [RVM's _patches_ directory](https://github.com/wayneeseguin/rvm/tree/master/patches/ruby)
+The recommended patches for MRI can be found on [RVM's _patches_ directory](https://github.com/wayneeseguin/rvm/tree/master/patches/ruby)
under each specific interpreter version.
Concerning the installation itself, you can either do this easily by using
-[RVM](http://rvm.beginrescueend.com) or you can build everything from source,
+[RVM](https://rvm.io/) or you can build everything from source,
which is a little bit harder.
#### Install Using RVM
@@ -449,7 +441,6 @@ patched Ruby interpreter:
```bash
$ rvm install 1.9.2-p180 --patch gcdata
-$ rvm install 1.8.7 --patch ruby187gc
$ rvm install 1.9.2-p180 --patch ~/Downloads/downloaded_gcdata_patch.patch
```
@@ -482,8 +473,7 @@ $ cd <ruby-version>
##### Apply the Patch
```bash
-$ curl http://github.com/wayneeseguin/rvm/raw/master/patches/ruby/1.9.2/p180/gcdata.patch | patch -p0 # if you're on 1.9.2!
-$ curl http://github.com/wayneeseguin/rvm/raw/master/patches/ruby/1.8.7/ruby187gc.patch | patch -p0 # if you're on 1.8.7!
+$ curl https://raw.github.com/wayneeseguin/rvm/master/patches/ruby/1.9.2/p180/gcdata.patch | patch -p0 # if you're on 1.9.2!
```
##### Configure and Install
diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md
index 9e694acb98..77138d8871 100644
--- a/guides/source/rails_application_templates.md
+++ b/guides/source/rails_application_templates.md
@@ -34,7 +34,6 @@ Rails templates API is very self explanatory and easy to understand. Here's an e
```ruby
# template.rb
-run "rm public/index.html"
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")
@@ -158,10 +157,10 @@ generate(:scaffold, "person", "name:string", "address:text", "age:number")
### run(command)
-Executes an arbitrary command. Just like the backticks. Let's say you want to remove the `public/index.html` file:
+Executes an arbitrary command. Just like the backticks. Let's say you want to remove the `README.rdoc` file:
```ruby
-run "rm public/index.html"
+run "rm README.rdoc"
```
### rake(command, options = {})
@@ -180,7 +179,7 @@ rake "db:migrate", env: 'production'
### route(routing_code)
-Adds a routing entry to the `config/routes.rb` file. In above steps, we generated a person scaffold and also removed `public/index.html`. Now to make `PeopleController#index` as the default page for the application:
+Adds a routing entry to the `config/routes.rb` file. In above steps, we generated a person scaffold and also removed `README.rdoc`. Now to make `PeopleController#index` as the default page for the application:
```ruby
route "root to: 'person#index'"
diff --git a/guides/source/security.md b/guides/source/security.md
index 0b0cfe69c4..3706a61431 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -210,7 +210,7 @@ The HTTP protocol basically provides two main types of requests - GET and POST (
* The interaction _changes the state_ of the resource in a way that the user would perceive (e.g., a subscription to a service), or
* The user is _held accountable for the results_ of the interaction.
-If your web application is RESTful, you might be used to additional HTTP verbs, such as PUT or DELETE. Most of today's web browsers, however do not support them - only GET and POST. Rails uses a hidden `_method` field to handle this barrier.
+If your web application is RESTful, you might be used to additional HTTP verbs, such as PATCH, PUT or DELETE. Most of today's web browsers, however do not support them - only GET and POST. Rails uses a hidden `_method` field to handle this barrier.
_POST requests can be sent automatically, too_. Here is an example for a link which displays www.harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request.
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 25cdd75cd9..0ae2f16aba 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -175,7 +175,7 @@ module Rails
# There are some places where an Engine's name is used:
#
# * routes: when you mount an Engine with <tt>mount(MyEngine::Engine => '/my_engine')</tt>,
- # it's used as default :as option
+ # it's used as default <tt>:as</tt> option
# * rake task for installing migrations <tt>my_engine:install:migrations</tt>
#
# Engine name is set by default based on class name. For <tt>MyEngine::Engine</tt> it will be
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index bf60616e2b..784c97aee0 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -38,7 +38,7 @@ module Rails
end
def readme
- copy_file "README", "README.rdoc"
+ copy_file "README.rdoc", "README.rdoc"
end
def gemfile
diff --git a/railties/lib/rails/generators/rails/app/templates/README b/railties/lib/rails/generators/rails/app/templates/README.rdoc
index 8d1b0f42e5..dd4e97e22e 100644
--- a/railties/lib/rails/generators/rails/app/templates/README
+++ b/railties/lib/rails/generators/rails/app/templates/README.rdoc
@@ -23,6 +23,6 @@ Things you may want to cover:
* ...
-If you plan to generate application documentation with `rake doc:app` this file
-is expected to be `README.rdoc`, otherwise please feel free to rename it and use
-a different markup language.
+
+Please feel free to use a different markup language if you do not plan to run
+<tt>rake doc:app</tt>.
diff --git a/railties/lib/rails/templates/rails/welcome/index.html.erb b/railties/lib/rails/templates/rails/welcome/index.html.erb
index abe705618a..e239e1695e 100644
--- a/railties/lib/rails/templates/rails/welcome/index.html.erb
+++ b/railties/lib/rails/templates/rails/welcome/index.html.erb
@@ -59,7 +59,7 @@
#header {
- background-image: url("assets/rails.png");
+ background-image: url("/assets/rails.png");
background-repeat: no-repeat;
background-position: top left;
height: 64px;
@@ -178,7 +178,7 @@
if (info.innerHTML === '') {
xhr = new XMLHttpRequest();
- xhr.open("GET", "rails/info/properties", false);
+ xhr.open("GET", "/rails/info/properties", false);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.send("");
info.innerHTML = xhr.responseText;
@@ -211,7 +211,7 @@
</div>
<div id="about">
- <h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
+ <h3><a href="/rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
<div id="about-content" style="display: none"></div>
</div>
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 654a44e648..f9108ed7b9 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -577,54 +577,6 @@ module ApplicationTests
assert_equal 'permitted', last_response.body
end
- test "config.action_controller.raise_on_unpermitted_parameters = true" do
- app_file 'app/controllers/posts_controller.rb', <<-RUBY
- class PostsController < ActionController::Base
- def create
- render text: params.require(:post).permit(:name)
- end
- end
- RUBY
-
- add_to_config <<-RUBY
- routes.prepend do
- resources :posts
- end
- config.action_controller.raise_on_unpermitted_parameters = true
- RUBY
-
- require "#{app_path}/config/environment"
-
- assert_equal true, ActionController::Parameters.raise_on_unpermitted_parameters
-
- post "/posts", {post: {"title" =>"zomg"}}
- assert_match "We're sorry, but something went wrong", last_response.body
- end
-
- test "config.action_controller.raise_on_unpermitted_parameters is true by default on development" do
- ENV["RAILS_ENV"] = "development"
-
- require "#{app_path}/config/environment"
-
- assert_equal true, ActionController::Parameters.raise_on_unpermitted_parameters
- end
-
- test "config.action_controller.raise_on_unpermitted_parameters is true by defaul on test" do
- ENV["RAILS_ENV"] = "test"
-
- require "#{app_path}/config/environment"
-
- assert_equal true, ActionController::Parameters.raise_on_unpermitted_parameters
- end
-
- test "config.action_controller.raise_on_unpermitted_parameters is false by default on production" do
- ENV["RAILS_ENV"] = "production"
-
- require "#{app_path}/config/environment"
-
- assert_equal false, ActionController::Parameters.raise_on_unpermitted_parameters
- end
-
test "config.action_dispatch.ignore_accept_header" do
make_basic_app do |app|
app.config.action_dispatch.ignore_accept_header = true