aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--CODE_OF_CONDUCT.md20
-rw-r--r--Gemfile.lock10
-rw-r--r--README.md2
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb34
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb23
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb25
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb92
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb12
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb34
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb44
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb56
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb4
-rw-r--r--actionpack/test/abstract_unit.rb2
-rw-r--r--actionpack/test/dispatch/header_test.rb14
-rw-r--r--actionpack/test/dispatch/request/session_test.rb40
-rw-r--r--actionpack/test/dispatch/session/abstract_store_test.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb3
-rw-r--r--activerecord/lib/active_record/type.rb4
-rw-r--r--activerecord/lib/active_record/type/internal/abstract_json.rb33
-rw-r--r--activerecord/lib/active_record/type/json.rb31
-rw-r--r--guides/source/4_2_release_notes.md11
-rw-r--r--guides/source/api_documentation_guidelines.md5
-rw-r--r--guides/source/debugging_rails_applications.md16
-rw-r--r--guides/source/layouts_and_rendering.md7
31 files changed, 286 insertions, 265 deletions
diff --git a/.travis.yml b/.travis.yml
index 605d1ff247..c648bd2ca7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,7 +21,7 @@ env:
- "GEM=aj:integration"
- "GEM=guides"
rvm:
- - 2.2.2
+ - 2.2.3
- ruby-head
matrix:
allow_failures:
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 65c05c5748..078d5f1219 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,22 +1,12 @@
# Contributor Code of Conduct
-As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
+The Rails team is committed to fostering a welcoming community.
-We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
+**Our Code of Conduct can be found here**:
-Examples of unacceptable behavior by participants include:
+http://rubyonrails.org/conduct/
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing other's private information, such as physical or electronic addresses, without explicit permission
-* Other unethical or unprofessional conduct.
+For a history of updates, see the page history here:
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
+https://github.com/rails/rails.github.com/commits/master/conduct/index.html
-This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
-
-This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) \ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
index daaa208a74..7cd4832b3a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -27,7 +27,7 @@ GIT
GIT
remote: git://github.com/rack/rack.git
- revision: 2cb9430fce32da2f2dbccf9de97ab691351c1408
+ revision: c94e22401d4719b4d78378c7b63362cd692f9005
specs:
rack (2.0.0.alpha)
json
@@ -79,7 +79,7 @@ GIT
GIT
remote: git://github.com/rails/sprockets.git
- revision: 653de5268ba862ea23457291824180c67ad5dc99
+ revision: a61550db7184fc83964fb983547ff09da9efa9be
branch: master
specs:
sprockets (4.0.0)
@@ -203,7 +203,7 @@ GEM
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
pg (0.18.2)
- psych (2.0.13)
+ psych (2.0.15)
que (0.10.0)
racc (1.4.12)
rack-cache (1.2)
@@ -236,7 +236,7 @@ GEM
resque (~> 1.25)
rufus-scheduler (~> 3.0)
rufus-scheduler (3.1.3)
- sass (3.4.16)
+ sass (3.4.17)
sdoc (0.4.1)
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
@@ -252,7 +252,7 @@ GEM
sigdump (0.2.3)
sinatra (1.0)
rack (>= 1.0)
- sneakers (1.1.0)
+ sneakers (1.1.1)
bunny (>= 1.7.0, <= 2.0.0)
serverengine (~> 1.5.5)
thor
diff --git a/README.md b/README.md
index 2bc35fa63d..ca796cebe7 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ and may also be used independently outside Rails.
We encourage you to contribute to Ruby on Rails! Please check out the
[Contributing to Ruby on Rails guide](http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html) for guidelines about how to proceed. [Join us!](http://contributors.rubyonrails.org)
-Everyone interacting in Rails and its sub-project’s codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](CODE_OF_CONDUCT.md).
+Everyone interacting in Rails and its sub-project’s codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](http://rubyonrails.org/conduct/).
## Code Status
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 3170389b36..e70e90018c 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -50,13 +50,13 @@ module ActionDispatch
protected
def parameter_filter
- parameter_filter_for @env.fetch("action_dispatch.parameter_filter") {
+ parameter_filter_for get_header("action_dispatch.parameter_filter") {
return NULL_PARAM_FILTER
}
end
def env_filter
- user_key = @env.fetch("action_dispatch.parameter_filter") {
+ user_key = get_header("action_dispatch.parameter_filter") {
return NULL_ENV_FILTER
}
parameter_filter_for(Array(user_key) + ENV_MATCH)
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index bc5410dc38..fbdec6c132 100644
--- a/actionpack/lib/action_dispatch/http/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -30,27 +30,32 @@ module ActionDispatch
HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
include Enumerable
- attr_reader :env
- def initialize(env = {}) # :nodoc:
- @env = env
+ def self.from_hash(hash)
+ new ActionDispatch::Request.new hash
+ end
+
+ def initialize(request) # :nodoc:
+ @req = request
end
# Returns the value for the given key mapped to @env.
def [](key)
- @env[env_name(key)]
+ @req.get_header env_name(key)
end
# Sets the given value for the key mapped to @env.
def []=(key, value)
- @env[env_name(key)] = value
+ @req.set_header env_name(key), value
end
def key?(key)
- @env.key? env_name(key)
+ @req.has_header? env_name(key)
end
alias :include? :key?
+ DEFAULT = Object.new # :nodoc:
+
# Returns the value for the given key mapped to @env.
#
# If the key is not found and an optional code block is not provided,
@@ -58,18 +63,22 @@ module ActionDispatch
#
# If the code block is provided, then it will be run and
# its result returned.
- def fetch(key, *args, &block)
- @env.fetch env_name(key), *args, &block
+ def fetch(key, default = DEFAULT)
+ @req.get_header(env_name(key)) do
+ return default unless default == DEFAULT
+ return yield if block_given?
+ raise NameError, key
+ end
end
def each(&block)
- @env.each(&block)
+ @req.each_header(&block)
end
# Returns a new Http::Headers instance containing the contents of
# <tt>headers_or_env</tt> and the original instance.
def merge(headers_or_env)
- headers = Http::Headers.new(env.dup)
+ headers = @req.dup.headers
headers.merge!(headers_or_env)
headers
end
@@ -79,11 +88,14 @@ module ActionDispatch
# <tt>headers_or_env</tt>.
def merge!(headers_or_env)
headers_or_env.each do |key, value|
- self[env_name(key)] = value
+ @req.set_header env_name(key), value
end
end
+ def env; @req.env.dup; end
+
private
+
# Converts a HTTP header name to an environment variable name if it is
# not contained within the headers hash.
def env_name(key)
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index ff336b7354..e01d5ecc8f 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -15,12 +15,13 @@ module ActionDispatch
# For backward compatibility, the post \format is extracted from the
# X-Post-Data-Format HTTP header if present.
def content_mime_type
- @env["action_dispatch.request.content_type"] ||= begin
- if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
+ get_header("action_dispatch.request.content_type") do |k|
+ v = if get_header('CONTENT_TYPE') =~ /^([^,\;]*)/
Mime::Type.lookup($1.strip.downcase)
else
nil
end
+ set_header k, v
end
end
@@ -30,14 +31,15 @@ module ActionDispatch
# Returns the accepted MIME type for the request.
def accepts
- @env["action_dispatch.request.accepts"] ||= begin
- header = @env['HTTP_ACCEPT'].to_s.strip
+ get_header("action_dispatch.request.accepts") do |k|
+ header = get_header('HTTP_ACCEPT').to_s.strip
- if header.empty?
+ v = if header.empty?
[content_mime_type]
else
Mime::Type.parse(header)
end
+ set_header k, v
end
end
@@ -52,14 +54,14 @@ module ActionDispatch
end
def formats
- @env["action_dispatch.request.formats"] ||= begin
+ get_header("action_dispatch.request.formats") do |k|
params_readable = begin
parameters[:format]
rescue ActionController::BadRequest
false
end
- if params_readable
+ v = if params_readable
Array(Mime[parameters[:format]])
elsif use_accept_header && valid_accept_header
accepts
@@ -68,6 +70,7 @@ module ActionDispatch
else
[Mime::HTML]
end
+ set_header k, v
end
end
@@ -102,7 +105,7 @@ module ActionDispatch
# end
def format=(extension)
parameters[:format] = extension.to_s
- @env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])]
+ set_header "action_dispatch.request.formats", [Mime::Type.lookup_by_extension(parameters[:format])]
end
# Sets the \formats by string extensions. This differs from #format= by allowing you
@@ -121,9 +124,9 @@ module ActionDispatch
# end
def formats=(extensions)
parameters[:format] = extensions.first.to_s
- @env["action_dispatch.request.formats"] = extensions.collect do |extension|
+ set_header "action_dispatch.request.formats", extensions.collect { |extension|
Mime::Type.lookup_by_extension(extension)
- end
+ }
end
# Receives an array of mimes and return the first user sent mime that
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 4defb7f858..277207ae6e 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -8,20 +8,23 @@ module ActionDispatch
# Returns both GET and POST \parameters in a single hash.
def parameters
- @env["action_dispatch.request.parameters"] ||= begin
- params = begin
- request_parameters.merge(query_parameters)
- rescue EOFError
- query_parameters.dup
- end
- params.merge!(path_parameters)
- end
+ params = get_header("action_dispatch.request.parameters")
+ return params if params
+
+ params = begin
+ request_parameters.merge(query_parameters)
+ rescue EOFError
+ query_parameters.dup
+ end
+ params.merge!(path_parameters)
+ set_header("action_dispatch.request.parameters", params)
+ params
end
alias :params :parameters
def path_parameters=(parameters) #:nodoc:
- @env.delete('action_dispatch.request.parameters')
- @env[PARAMETERS_KEY] = parameters
+ delete_header('action_dispatch.request.parameters')
+ set_header PARAMETERS_KEY, parameters
end
# Returns a hash with the \parameters used to form the \path of the request.
@@ -29,7 +32,7 @@ module ActionDispatch
#
# {'action' => 'my_action', 'controller' => 'my_controller'}
def path_parameters
- @env[PARAMETERS_KEY] ||= {}
+ get_header(PARAMETERS_KEY) || {}
end
private
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index de28cd0998..4748a54550 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -20,8 +20,6 @@ module ActionDispatch
include ActionDispatch::Http::FilterParameters
include ActionDispatch::Http::URL
- HTTP_X_REQUEST_ID = "HTTP_X_REQUEST_ID".freeze # :nodoc:
-
autoload :Session, 'action_dispatch/request/session'
autoload :Utils, 'action_dispatch/request/utils'
@@ -31,17 +29,19 @@ module ActionDispatch
PATH_TRANSLATED REMOTE_HOST
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
SERVER_NAME SERVER_PROTOCOL
+ ORIGINAL_SCRIPT_NAME
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR HTTP_VERSION
+ HTTP_X_REQUEST_ID
].freeze
ENV_METHODS.each do |env|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset
- @env["#{env}".freeze] # @env["HTTP_ACCEPT_CHARSET".freeze]
+ get_header "#{env}".freeze # get_header "HTTP_ACCEPT_CHARSET".freeze
end # end
METHOD
end
@@ -67,8 +67,20 @@ module ActionDispatch
end
end
+ def controller_class
+ check_path_parameters!
+ params = path_parameters
+ controller_param = params[:controller].underscore if params.key?(:controller)
+ params[:action] ||= 'index'
+
+ yield unless controller_param
+
+ const_name = "#{controller_param.camelize}Controller"
+ ActiveSupport::Dependencies.constantize(const_name)
+ end
+
def key?(key)
- @env.key?(key)
+ has_header? key
end
# List of HTTP request methods from the following RFCs:
@@ -109,44 +121,40 @@ module ActionDispatch
end
def routes # :nodoc:
- env["action_dispatch.routes".freeze]
+ get_header("action_dispatch.routes".freeze)
end
def routes=(routes) # :nodoc:
- env["action_dispatch.routes".freeze] = routes
- end
-
- def original_script_name # :nodoc:
- env['ORIGINAL_SCRIPT_NAME'.freeze]
+ set_header("action_dispatch.routes".freeze, routes)
end
def engine_script_name(_routes) # :nodoc:
- env[_routes.env_key]
+ get_header(_routes.env_key)
end
def engine_script_name=(name) # :nodoc:
- env[routes.env_key] = name.dup
+ set_header(routes.env_key, name.dup)
end
def request_method=(request_method) #:nodoc:
if check_method(request_method)
- @request_method = env["REQUEST_METHOD"] = request_method
+ @request_method = set_header("REQUEST_METHOD", request_method)
end
end
def controller_instance # :nodoc:
- env['action_controller.instance'.freeze]
+ get_header('action_controller.instance'.freeze)
end
def controller_instance=(controller) # :nodoc:
- env['action_controller.instance'.freeze] = controller
+ set_header('action_controller.instance'.freeze, controller)
end
def show_exceptions? # :nodoc:
# We're treating `nil` as "unset", and we want the default setting to be
# `true`. This logic should be extracted to `env_config` and calculated
# once.
- !(env['action_dispatch.show_exceptions'.freeze] == false)
+ !(get_header('action_dispatch.show_exceptions'.freeze) == false)
end
# Returns a symbol form of the #request_method
@@ -158,7 +166,7 @@ module ActionDispatch
# even if it was overridden by middleware. See #request_method for
# more information.
def method
- @method ||= check_method(env["rack.methodoverride.original_method"] || env['REQUEST_METHOD'])
+ @method ||= check_method(get_header("rack.methodoverride.original_method") || get_header('REQUEST_METHOD'))
end
# Returns a symbol form of the #method
@@ -170,7 +178,7 @@ module ActionDispatch
#
# request.headers["Content-Type"] # => "text/plain"
def headers
- @headers ||= Http::Headers.new(@env)
+ @headers ||= Http::Headers.new(self)
end
# Returns a +String+ with the last requested path including their params.
@@ -181,7 +189,7 @@ module ActionDispatch
# # get '/foo?bar'
# request.original_fullpath # => '/foo?bar'
def original_fullpath
- @original_fullpath ||= (env["ORIGINAL_FULLPATH"] || fullpath)
+ @original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
end
# Returns the +String+ full path including params of the last URL requested.
@@ -220,7 +228,7 @@ module ActionDispatch
# (case-insensitive), which may need to be manually added depending on the
# choice of JavaScript libraries and frameworks.
def xml_http_request?
- @env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
+ get_header('HTTP_X_REQUESTED_WITH') =~ /XMLHttpRequest/i
end
alias :xhr? :xml_http_request?
@@ -232,11 +240,11 @@ module ActionDispatch
# Returns the IP address of client as a +String+,
# usually set by the RemoteIp middleware.
def remote_ip
- @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
+ @remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
end
def remote_ip=(remote_ip)
- @env["action_dispatch.remote_ip".freeze] = remote_ip
+ set_header "action_dispatch.remote_ip".freeze, remote_ip
end
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
@@ -248,43 +256,39 @@ module ActionDispatch
# This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
# This relies on the rack variable set by the ActionDispatch::RequestId middleware.
def request_id
- env[ACTION_DISPATCH_REQUEST_ID]
+ get_header ACTION_DISPATCH_REQUEST_ID
end
def request_id=(id) # :nodoc:
- env[ACTION_DISPATCH_REQUEST_ID] = id
+ set_header ACTION_DISPATCH_REQUEST_ID, id
end
alias_method :uuid, :request_id
- def x_request_id # :nodoc:
- @env[HTTP_X_REQUEST_ID]
- end
-
# Returns the lowercase name of the HTTP server software.
def server_software
- (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
+ (get_header('SERVER_SOFTWARE') && /^([a-zA-Z]+)/ =~ get_header('SERVER_SOFTWARE')) ? $1.downcase : nil
end
# Read the request \body. This is useful for web services that need to
# work with raw requests directly.
def raw_post
- unless @env.include? 'RAW_POST_DATA'
+ unless has_header? 'RAW_POST_DATA'
raw_post_body = body
- @env['RAW_POST_DATA'] = raw_post_body.read(content_length)
+ set_header('RAW_POST_DATA', raw_post_body.read(content_length))
raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
end
- @env['RAW_POST_DATA']
+ get_header 'RAW_POST_DATA'
end
# The request body is an IO input stream. If the RAW_POST_DATA environment
# variable is already set, wrap it in a StringIO.
def body
- if raw_post = @env['RAW_POST_DATA']
+ if raw_post = get_header('RAW_POST_DATA')
raw_post.force_encoding(Encoding::BINARY)
StringIO.new(raw_post)
else
- @env['rack.input']
+ body_stream
end
end
@@ -295,7 +299,7 @@ module ActionDispatch
end
def body_stream #:nodoc:
- @env['rack.input']
+ get_header('rack.input')
end
# TODO This should be broken apart into AD::Request::Session and probably
@@ -306,15 +310,15 @@ module ActionDispatch
else
self.session = {}
end
- @env['action_dispatch.request.flash_hash'] = nil
+ set_header('action_dispatch.request.flash_hash', nil)
end
def session=(session) #:nodoc:
- Session.set @env, session
+ Session.set self, session
end
def session_options=(options)
- Session::Options.set @env, options
+ Session::Options.set self, options
end
# Override Rack's GET method to support indifferent access
@@ -336,10 +340,10 @@ module ActionDispatch
# Returns the authorization header regardless of whether it was specified directly or through one of the
# proxy alternatives.
def authorization
- @env['HTTP_AUTHORIZATION'] ||
- @env['X-HTTP_AUTHORIZATION'] ||
- @env['X_HTTP_AUTHORIZATION'] ||
- @env['REDIRECT_X_HTTP_AUTHORIZATION']
+ get_header('HTTP_AUTHORIZATION') ||
+ get_header('X-HTTP_AUTHORIZATION') ||
+ get_header('X_HTTP_AUTHORIZATION') ||
+ get_header('REDIRECT_X_HTTP_AUTHORIZATION')
end
# True if the request came from localhost, 127.0.0.1.
@@ -348,11 +352,11 @@ module ActionDispatch
end
def request_parameters=(params)
- env["action_dispatch.request.request_parameters".freeze] = params
+ set_header("action_dispatch.request.request_parameters".freeze, params)
end
def logger
- env["action_dispatch.logger".freeze]
+ get_header("action_dispatch.logger".freeze)
end
private
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 23da169b22..379e7ffdc5 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -274,7 +274,7 @@ module ActionDispatch
req = ActionDispatch::Request.new env
@app.call(env)
ensure
- session = Request::Session.find(env) || {}
+ session = Request::Session.find(req) || {}
flash_hash = req.flash_hash
if flash_hash && (flash_hash.present? || session.key?('flash'))
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 84df55fd5a..b924df789f 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -36,6 +36,11 @@ module ActionDispatch
@default_options.delete(:sidbits)
@default_options.delete(:secure_random)
end
+
+ private
+ def make_request(env)
+ ActionDispatch::Request.new env
+ end
end
module StaleSessionCheck
@@ -65,8 +70,8 @@ module ActionDispatch
end
module SessionObject # :nodoc:
- def prepare_session(env)
- Request::Session.create(self, env, @default_options)
+ def prepare_session(req)
+ Request::Session.create(self, req, @default_options)
end
def loaded_session?(session)
@@ -81,8 +86,7 @@ module ActionDispatch
private
- def set_cookie(env, session_id, cookie)
- request = ActionDispatch::Request.new(env)
+ def set_cookie(request, session_id, cookie)
request.cookie_jar[key] = cookie
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index d8f9614904..e225f356df 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -71,16 +71,16 @@ module ActionDispatch
super(app, options.merge!(:cookie_only => true))
end
- def destroy_session(env, session_id, options)
+ def destroy_session(req, session_id, options)
new_sid = generate_sid unless options[:drop]
# Reset hash and Assign the new session id
- env["action_dispatch.request.unsigned_session_cookie"] = new_sid ? { "session_id" => new_sid } : {}
+ req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid } : {})
new_sid
end
- def load_session(env)
+ def load_session(req)
stale_session_check! do
- data = unpacked_cookie_data(env)
+ data = unpacked_cookie_data(req)
data = persistent_session_id!(data)
[data["session_id"], data]
end
@@ -88,20 +88,21 @@ module ActionDispatch
private
- def extract_session_id(env)
+ def extract_session_id(req)
stale_session_check! do
- unpacked_cookie_data(env)["session_id"]
+ unpacked_cookie_data(req)["session_id"]
end
end
- def unpacked_cookie_data(env)
- env["action_dispatch.request.unsigned_session_cookie"] ||= begin
- stale_session_check! do
- if data = get_cookie(env)
+ def unpacked_cookie_data(req)
+ req.get_header("action_dispatch.request.unsigned_session_cookie") do |k|
+ v = stale_session_check! do
+ if data = get_cookie(req)
data.stringify_keys!
end
data || {}
end
+ req.set_header k, v
end
end
@@ -111,21 +112,20 @@ module ActionDispatch
data
end
- def set_session(env, sid, session_data, options)
+ def set_session(req, sid, session_data, options)
session_data["session_id"] = sid
session_data
end
- def set_cookie(env, session_id, cookie)
- cookie_jar(env)[@key] = cookie
+ def set_cookie(request, session_id, cookie)
+ cookie_jar(request)[@key] = cookie
end
- def get_cookie(env)
- cookie_jar(env)[@key]
+ def get_cookie(req)
+ cookie_jar(req)[@key]
end
- def cookie_jar(env)
- request = ActionDispatch::Request.new(env)
+ def cookie_jar(request)
request.cookie_jar.signed_or_encrypted
end
end
diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb
index bae3d909fa..b946ccb49f 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -11,31 +11,31 @@ module ActionDispatch
Unspecified = Object.new
# Creates a session hash, merging the properties of the previous session if any
- def self.create(store, env, default_options)
- session_was = find env
- session = Request::Session.new(store, env)
+ def self.create(store, req, default_options)
+ session_was = find req
+ session = Request::Session.new(store, req)
session.merge! session_was if session_was
- set(env, session)
- Options.set(env, Request::Session::Options.new(store, default_options))
+ set(req, session)
+ Options.set(req, Request::Session::Options.new(store, default_options))
session
end
- def self.find(env)
- env[ENV_SESSION_KEY]
+ def self.find(req)
+ req.get_header ENV_SESSION_KEY
end
- def self.set(env, session)
- env[ENV_SESSION_KEY] = session
+ def self.set(req, session)
+ req.set_header ENV_SESSION_KEY, session
end
class Options #:nodoc:
- def self.set(env, options)
- env[ENV_SESSION_OPTIONS_KEY] = options
+ def self.set(req, options)
+ req.set_header ENV_SESSION_OPTIONS_KEY, options
end
- def self.find(env)
- env[ENV_SESSION_OPTIONS_KEY]
+ def self.find(req)
+ req.get_header ENV_SESSION_OPTIONS_KEY
end
def initialize(by, default_options)
@@ -47,9 +47,9 @@ module ActionDispatch
@delegate[key]
end
- def id(env)
+ def id(req)
@delegate.fetch(:id) {
- @by.send(:extract_session_id, env)
+ @by.send(:extract_session_id, req)
}
end
@@ -58,26 +58,26 @@ module ActionDispatch
def values_at(*args); @delegate.values_at(*args); end
end
- def initialize(by, env)
+ def initialize(by, req)
@by = by
- @env = env
+ @req = req
@delegate = {}
@loaded = false
@exists = nil # we haven't checked yet
end
def id
- options.id(@env)
+ options.id(@req)
end
def options
- Options.find @env
+ Options.find @req
end
def destroy
clear
options = self.options || {}
- @by.send(:destroy_session, @env, options.id(@env), options)
+ @by.send(:destroy_session, @req, options.id(@req), options)
# Load the new sid to be written with the response
@loaded = false
@@ -181,7 +181,7 @@ module ActionDispatch
def exists?
return @exists unless @exists.nil?
- @exists = @by.send(:session_exists?, @env)
+ @exists = @by.send(:session_exists?, @req)
end
def loaded?
@@ -209,7 +209,7 @@ module ActionDispatch
end
def load!
- id, session = @by.load_session @env
+ id, session = @by.load_session @req
options[:id] = id
@delegate.replace(stringify_keys(session))
@loaded = true
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 20926012b4..af6f0de556 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,6 +1,5 @@
require 'action_dispatch/journey'
require 'forwardable'
-require 'thread_safe'
require 'active_support/concern'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
@@ -23,49 +22,27 @@ module ActionDispatch
class Dispatcher < Routing::Endpoint
def initialize(raise_on_name_error)
@raise_on_name_error = raise_on_name_error
- @controller_class_names = ThreadSafe::Cache.new
end
def dispatcher?; true; end
def serve(req)
- req.check_path_parameters!
params = req.path_parameters
-
- prepare_params!(params)
-
- controller = controller(params, @raise_on_name_error) do
+ controller = controller_reference(req) do
return [404, {'X-Cascade' => 'pass'}, []]
end
-
dispatch(controller, params[:action], req)
- end
-
- def prepare_params!(params)
- normalize_controller!(params)
- merge_default_action!(params)
- end
-
- # If this is a default_controller (i.e. a controller specified by the user)
- # we should raise an error in case it's not found, because it usually means
- # a user error. However, if the controller was retrieved through a dynamic
- # segment, as in :controller(/:action), we should simply return nil and
- # delegate the control back to Rack cascade. Besides, if this is not a default
- # controller, it means we should respect the @scope[:module] parameter.
- def controller(params, raise_on_name_error=true)
- controller_reference params.fetch(:controller) { yield }
rescue NameError => e
- raise ActionController::RoutingError, e.message, e.backtrace if raise_on_name_error
- yield
+ if @raise_on_name_error
+ raise ActionController::RoutingError, e.message, e.backtrace
+ else
+ return [404, {'X-Cascade' => 'pass'}, []]
+ end
end
protected
-
- attr_reader :controller_class_names
-
- def controller_reference(controller_param)
- const_name = controller_class_names[controller_param] ||= "#{controller_param.camelize}Controller"
- ActiveSupport::Dependencies.constantize(const_name)
+ def controller_reference(req, &block)
+ req.controller_class(&block)
end
private
@@ -73,14 +50,6 @@ module ActionDispatch
def dispatch(controller, action, req)
controller.action(action).call(req.env)
end
-
- def normalize_controller!(params)
- params[:controller] = params[:controller].underscore if params.key?(:controller)
- end
-
- def merge_default_action!(params)
- params[:action] ||= 'index'
- end
end
# A NamedRouteCollection instance is a collection of named routes, and also
@@ -760,14 +729,13 @@ module ActionDispatch
req.path_parameters = old_params.merge params
app = route.app
if app.matches?(req) && app.dispatcher?
- dispatcher = app.app
-
- dispatcher.controller(params, false) do
+ begin
+ req.controller_class
+ rescue NameError
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
end
- dispatcher.prepare_params!(params)
- return params
+ return req.path_parameters
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 0cdc6d4e77..4dfd4f3f71 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -359,10 +359,10 @@ module ActionDispatch
# this modifies the passed request_env directly
if headers.present?
- Http::Headers.new(request_env).merge!(headers)
+ Http::Headers.from_hash(request_env).merge!(headers)
end
if env.present?
- Http::Headers.new(request_env).merge!(env)
+ Http::Headers.from_hash(request_env).merge!(env)
end
session = Rack::Test::Session.new(_mock_session)
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 60e2cea8a2..fa0b6087ba 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -122,7 +122,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
protected
def controller_reference(controller_param)
- controller_param
+ controller_param.params[:controller]
end
def dispatch(controller, action, env)
diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb
index e2b38c23bc..79600b654b 100644
--- a/actionpack/test/dispatch/header_test.rb
+++ b/actionpack/test/dispatch/header_test.rb
@@ -1,15 +1,19 @@
require "abstract_unit"
class HeaderTest < ActiveSupport::TestCase
+ def make_headers(hash)
+ ActionDispatch::Http::Headers.new ActionDispatch::Request.new hash
+ end
+
setup do
- @headers = ActionDispatch::Http::Headers.new(
+ @headers = make_headers(
"CONTENT_TYPE" => "text/plain",
"HTTP_REFERER" => "/some/page"
)
end
test "#new does not normalize the data" do
- headers = ActionDispatch::Http::Headers.new(
+ headers = make_headers(
"Content-Type" => "application/json",
"HTTP_REFERER" => "/some/page",
"Host" => "http://test.com")
@@ -108,7 +112,7 @@ class HeaderTest < ActiveSupport::TestCase
end
test "env variables with . are not modified" do
- headers = ActionDispatch::Http::Headers.new
+ headers = make_headers({})
headers.merge! "rack.input" => "",
"rack.request.cookie_hash" => "",
"action_dispatch.logger" => ""
@@ -119,7 +123,7 @@ class HeaderTest < ActiveSupport::TestCase
end
test "symbols are treated as strings" do
- headers = ActionDispatch::Http::Headers.new
+ headers = make_headers({})
headers.merge!(:SERVER_NAME => "example.com",
"HTTP_REFERER" => "/",
:Host => "test.com")
@@ -130,7 +134,7 @@ class HeaderTest < ActiveSupport::TestCase
test "headers directly modifies the passed environment" do
env = {"HTTP_REFERER" => "/"}
- headers = ActionDispatch::Http::Headers.new(env)
+ headers = make_headers(env)
headers['Referer'] = "http://example.com/"
headers.merge! "CONTENT_TYPE" => "text/plain"
assert_equal({"HTTP_REFERER"=>"http://example.com/",
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
index 8bcc07dd04..410e3194e2 100644
--- a/actionpack/test/dispatch/request/session_test.rb
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -4,40 +4,42 @@ require 'action_dispatch/middleware/session/abstract_store'
module ActionDispatch
class Request
class SessionTest < ActiveSupport::TestCase
+ attr_reader :req
+
+ def setup
+ @req = ActionDispatch::Request.new({})
+ end
+
def test_create_adds_itself_to_env
- env = {}
- s = Session.create(store, env, {})
- assert_equal s, env[Rack::RACK_SESSION]
+ s = Session.create(store, req, {})
+ assert_equal s, req.env[Rack::RACK_SESSION]
end
def test_to_hash
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, req, {})
s['foo'] = 'bar'
assert_equal 'bar', s['foo']
assert_equal({'foo' => 'bar'}, s.to_hash)
end
def test_create_merges_old
- env = {}
- s = Session.create(store, env, {})
+ s = Session.create(store, req, {})
s['foo'] = 'bar'
- s1 = Session.create(store, env, {})
+ s1 = Session.create(store, req, {})
assert_not_equal s, s1
assert_equal 'bar', s1['foo']
end
def test_find
- env = {}
- assert_nil Session.find(env)
+ assert_nil Session.find(req)
- s = Session.create(store, env, {})
- assert_equal s, Session.find(env)
+ s = Session.create(store, req, {})
+ assert_equal s, Session.find(req)
end
def test_destroy
- s = Session.create(store, {}, {})
+ s = Session.create(store, req, {})
s['rails'] = 'ftw'
s.destroy
@@ -46,21 +48,21 @@ module ActionDispatch
end
def test_keys
- s = Session.create(store, {}, {})
+ s = Session.create(store, req, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
assert_equal %w[rails adequate], s.keys
end
def test_values
- s = Session.create(store, {}, {})
+ s = Session.create(store, req, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
assert_equal %w[ftw awesome], s.values
end
def test_clear
- s = Session.create(store, {}, {})
+ s = Session.create(store, req, {})
s['rails'] = 'ftw'
s['adequate'] = 'awesome'
@@ -69,7 +71,7 @@ module ActionDispatch
end
def test_update
- s = Session.create(store, {}, {})
+ s = Session.create(store, req, {})
s['rails'] = 'ftw'
s.update(:rails => 'awesome')
@@ -79,7 +81,7 @@ module ActionDispatch
end
def test_delete
- s = Session.create(store, {}, {})
+ s = Session.create(store, req, {})
s['rails'] = 'ftw'
s.delete('rails')
@@ -88,7 +90,7 @@ module ActionDispatch
end
def test_fetch
- session = Session.create(store, {}, {})
+ session = Session.create(store, req, {})
session['one'] = '1'
assert_equal '1', session.fetch(:one)
diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb
index fe1a7b4f86..1c35144e6f 100644
--- a/actionpack/test/dispatch/session/abstract_store_test.rb
+++ b/actionpack/test/dispatch/session/abstract_store_test.rb
@@ -27,7 +27,7 @@ module ActionDispatch
as.call(env)
assert @env
- assert Request::Session.find @env
+ assert Request::Session.find ActionDispatch::Request.new @env
end
def test_new_session_object_is_merged_with_old
@@ -36,11 +36,11 @@ module ActionDispatch
as.call(env)
assert @env
- session = Request::Session.find @env
+ session = Request::Session.find ActionDispatch::Request.new @env
session['foo'] = 'bar'
as.call(@env)
- session1 = Request::Session.find @env
+ session1 = Request::Session.find ActionDispatch::Request.new @env
assert_not_equal session, session1
assert_equal session.to_hash, session1.to_hash
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 96ea866580..b3e55a0b90 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -1050,7 +1050,7 @@ module ActiveRecord
end
end
- class MysqlJson < Type::Json # :nodoc:
+ class MysqlJson < Type::Internal::AbstractJson # :nodoc:
def changed_in_place?(raw_old_value, new_value)
# Normalization is required because MySQL JSON data format includes
# the space between the elements.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 37226831dc..68752cdd80 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -8,6 +8,7 @@ require 'active_record/connection_adapters/postgresql/oid/decimal'
require 'active_record/connection_adapters/postgresql/oid/enum'
require 'active_record/connection_adapters/postgresql/oid/hstore'
require 'active_record/connection_adapters/postgresql/oid/inet'
+require 'active_record/connection_adapters/postgresql/oid/json'
require 'active_record/connection_adapters/postgresql/oid/jsonb'
require 'active_record/connection_adapters/postgresql/oid/money'
require 'active_record/connection_adapters/postgresql/oid/point'
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
new file mode 100644
index 0000000000..dbc879ffd4
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
@@ -0,0 +1,10 @@
+module ActiveRecord
+ module ConnectionAdapters
+ module PostgreSQL
+ module OID # :nodoc:
+ class Json < Type::Internal::AbstractJson
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
index 1f6d63582c..87391b5dc7 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
- class Jsonb < Type::Json # :nodoc:
+ class Jsonb < Json # :nodoc:
def type
:jsonb
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 861edbf3a2..27291bd2ea 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -482,7 +482,7 @@ module ActiveRecord
m.register_type 'bytea', OID::Bytea.new
m.register_type 'point', OID::Point.new
m.register_type 'hstore', OID::Hstore.new
- m.register_type 'json', Type::Json.new
+ m.register_type 'json', OID::Json.new
m.register_type 'jsonb', OID::Jsonb.new
m.register_type 'cidr', OID::Cidr.new
m.register_type 'inet', OID::Inet.new
@@ -838,6 +838,7 @@ module ActiveRecord
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
+ ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index 8f56a37f3c..53f3b53bec 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -10,7 +10,6 @@ require 'active_record/type/decimal'
require 'active_record/type/decimal_without_scale'
require 'active_record/type/float'
require 'active_record/type/integer'
-require 'active_record/type/json'
require 'active_record/type/serialized'
require 'active_record/type/string'
require 'active_record/type/text'
@@ -21,6 +20,8 @@ require 'active_record/type/adapter_specific_registry'
require 'active_record/type/type_map'
require 'active_record/type/hash_lookup_type_map'
+require 'active_record/type/internal/abstract_json'
+
module ActiveRecord
module Type
@registry = AdapterSpecificRegistry.new
@@ -60,7 +61,6 @@ module ActiveRecord
register(:decimal, Type::Decimal, override: false)
register(:float, Type::Float, override: false)
register(:integer, Type::Integer, override: false)
- register(:json, Type::Json, override: false)
register(:string, Type::String, override: false)
register(:text, Type::Text, override: false)
register(:time, Type::Time, override: false)
diff --git a/activerecord/lib/active_record/type/internal/abstract_json.rb b/activerecord/lib/active_record/type/internal/abstract_json.rb
new file mode 100644
index 0000000000..963a8245d0
--- /dev/null
+++ b/activerecord/lib/active_record/type/internal/abstract_json.rb
@@ -0,0 +1,33 @@
+module ActiveRecord
+ module Type
+ module Internal # :nodoc:
+ class AbstractJson < Type::Value # :nodoc:
+ include Type::Helpers::Mutable
+
+ def type
+ :json
+ end
+
+ def deserialize(value)
+ if value.is_a?(::String)
+ ::ActiveSupport::JSON.decode(value) rescue nil
+ else
+ value
+ end
+ end
+
+ def serialize(value)
+ if value.is_a?(::Array) || value.is_a?(::Hash)
+ ::ActiveSupport::JSON.encode(value)
+ else
+ value
+ end
+ end
+
+ def accessor
+ ActiveRecord::Store::StringKeyedHashAccessor
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/type/json.rb b/activerecord/lib/active_record/type/json.rb
deleted file mode 100644
index 1728bd3a8e..0000000000
--- a/activerecord/lib/active_record/type/json.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module ActiveRecord
- module Type
- class Json < Type::Value # :nodoc:
- include Type::Helpers::Mutable
-
- def type
- :json
- end
-
- def deserialize(value)
- if value.is_a?(::String)
- ::ActiveSupport::JSON.decode(value) rescue nil
- else
- value
- end
- end
-
- def serialize(value)
- if value.is_a?(::Array) || value.is_a?(::Hash)
- ::ActiveSupport::JSON.encode(value)
- else
- value
- end
- end
-
- def accessor
- ActiveRecord::Store::StringKeyedHashAccessor
- end
- end
- end
-end
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index 684bd286bc..8a59007420 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -227,6 +227,17 @@ restore the old behavior.
If you do this, be sure to configure your firewall properly such that only
trusted machines on your network can access your development server.
+### Changed status option symbols for `render`
+
+Due to a [change in Rack](https://github.com/rack/rack/commit/be28c6a2ac152fe4adfbef71f3db9f4200df89e8), the symbols that the `render` method accepts for the `:status` option have changed:
+
+- 306: `:reserved` has been removed.
+- 413: `:request_entity_too_large` has been renamed to `:payload_too_large`.
+- 414: `:request_uri_too_long` has been renamed to `:uri_too_long`.
+- 416: `:requested_range_not_satisfiable` has been renamed to `:range_not_satisfiable`.
+
+Keep in mind that if calling `render` with an unknown symbol, the response status will default to 500.
+
### HTML Sanitizer
The HTML sanitizer has been replaced with a new, more robust, implementation
diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md
index 46c9013087..8e9833c381 100644
--- a/guides/source/api_documentation_guidelines.md
+++ b/guides/source/api_documentation_guidelines.md
@@ -84,6 +84,11 @@ English
Please use American English (*color*, *center*, *modularize*, etc). See [a list of American and British English spelling differences here](http://en.wikipedia.org/wiki/American_and_British_English_spelling_differences).
+Comma
+-------
+
+Please use Oxford comma (*red, white, and blue* style). See [the detail of Oxford comma](http://en.wikipedia.org/wiki/Serial_comma).
+
Example Code
------------
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index c486009741..40d5bd2012 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -619,13 +619,15 @@ Processing by ArticlesController#index as HTML
(byebug)
```
-If we use `next`, we want go deep inside method calls. Instead, byebug will go
-to the next line within the same context. In this case, this is the last line of
-the method, so `byebug` will jump to next next line of the previous frame.
-
+If we use `next`, we won't go deep inside method calls. Instead, `byebug` will
+go to the next line within the same context. In this case, it is the last line
+of the current method, so `byebug` will return to the next line of the caller
++method.
```
(byebug) next
-Next went up a frame because previous frame finished
+
+Next advances to the next line (line 6: `end`), which returns to the next line
+of the caller method:
[4, 13] in /PathTo/project/test_app/app/controllers/articles_controller.rb
4: # GET /articles
@@ -642,8 +644,8 @@ Next went up a frame because previous frame finished
(byebug)
```
-If we use `step` in the same situation, we will literally go to the next Ruby
-instruction to be executed. In this case, Active Support's `week` method.
+If we use `step` in the same situation, `byebug` will literally go to the next
+Ruby instruction to be executed -- in this case, Active Support's `week` method.
```
(byebug) step
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index 94cd7297e2..b425eb126a 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -360,7 +360,6 @@ Rails understands both numeric status codes and the corresponding symbols shown
| | 303 | :see_other |
| | 304 | :not_modified |
| | 305 | :use_proxy |
-| | 306 | :reserved |
| | 307 | :temporary_redirect |
| | 308 | :permanent_redirect |
| **Client Error** | 400 | :bad_request |
@@ -376,10 +375,10 @@ Rails understands both numeric status codes and the corresponding symbols shown
| | 410 | :gone |
| | 411 | :length_required |
| | 412 | :precondition_failed |
-| | 413 | :request_entity_too_large |
-| | 414 | :request_uri_too_long |
+| | 413 | :payload_too_large |
+| | 414 | :uri_too_long |
| | 415 | :unsupported_media_type |
-| | 416 | :requested_range_not_satisfiable |
+| | 416 | :range_not_satisfiable |
| | 417 | :expectation_failed |
| | 422 | :unprocessable_entity |
| | 423 | :locked |