Merge branch 'master' into fix_26964
This commit is contained in:
commit
ca3eb2c156
@ -6,6 +6,7 @@ AllCops:
|
||||
Exclude:
|
||||
- '**/templates/**/*'
|
||||
- '**/vendor/**/*'
|
||||
- 'actionpack/lib/action_dispatch/journey/parser.rb'
|
||||
|
||||
# Prefer &&/|| over and/or.
|
||||
Style/AndOr:
|
||||
|
@ -34,19 +34,19 @@ env:
|
||||
- "JRUBY_OPTS='--dev -J-Xmx1024M'"
|
||||
matrix:
|
||||
- "GEM=railties"
|
||||
- "GEM=ap"
|
||||
- "GEM=ac"
|
||||
- "GEM=ac:integration"
|
||||
- "GEM=ap,ac"
|
||||
- "GEM=am,amo,as,av,aj"
|
||||
- "GEM=as PRESERVE_TIMEZONES=1"
|
||||
- "GEM=ar:mysql2"
|
||||
- "GEM=ar:sqlite3"
|
||||
- "GEM=ar:postgresql"
|
||||
- "GEM=guides"
|
||||
- "GEM=ac:integration"
|
||||
|
||||
rvm:
|
||||
- 2.2.6
|
||||
- 2.3.3
|
||||
- 2.4.0
|
||||
- ruby-head
|
||||
|
||||
matrix:
|
||||
@ -85,6 +85,7 @@ matrix:
|
||||
allow_failures:
|
||||
- rvm: ruby-head
|
||||
- rvm: jruby-9.1.5.0
|
||||
- env: "GEM=ac:integration"
|
||||
fast_finish: true
|
||||
|
||||
notifications:
|
||||
|
7
Gemfile
7
Gemfile
@ -29,9 +29,6 @@ gem "bcrypt", "~> 3.1.11", require: false
|
||||
# sprockets.
|
||||
gem "uglifier", ">= 1.3.0", require: false
|
||||
|
||||
# Track stable branch of sass because it doesn't have circular require warnings.
|
||||
gem "sass", github: "sass/sass", branch: "stable", require: false
|
||||
|
||||
# FIXME: Remove this fork after https://github.com/nex3/rb-inotify/pull/49 is fixed.
|
||||
gem "rb-inotify", github: "matthewd/rb-inotify", branch: "close-handling", require: false
|
||||
|
||||
@ -41,10 +38,10 @@ gem "json", ">= 2.0.0"
|
||||
gem "rubocop", require: false
|
||||
|
||||
group :doc do
|
||||
gem "sdoc", "1.0.0.beta2"
|
||||
gem "sdoc", "1.0.0.rc1"
|
||||
gem "redcarpet", "~> 3.2.3", platforms: :ruby
|
||||
gem "w3c_validators"
|
||||
gem "kindlerb", ">= 1.0.1"
|
||||
gem "kindlerb", "~> 1.2.0"
|
||||
end
|
||||
|
||||
# Active Support.
|
||||
|
104
Gemfile.lock
104
Gemfile.lock
@ -40,7 +40,7 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: https://github.com/resque/resque.git
|
||||
revision: 20d885065ac19e7f7d7a982f4ed1296083db0300
|
||||
revision: 835a4a7e61a2e33832dbf11975ecfab54af293c6
|
||||
specs:
|
||||
resque (1.27.0)
|
||||
mono_logger (~> 1.0)
|
||||
@ -49,19 +49,12 @@ GIT
|
||||
sinatra (>= 0.9.2)
|
||||
vegas (~> 0.1.2)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/sass/sass.git
|
||||
revision: 7716e67f3507c6f65878c69aa49ec358ebf675c7
|
||||
branch: stable
|
||||
specs:
|
||||
sass (3.4.22)
|
||||
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
actioncable (5.1.0.alpha)
|
||||
actionpack (= 5.1.0.alpha)
|
||||
nio4r (~> 1.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (~> 0.6.1)
|
||||
actionmailer (5.1.0.alpha)
|
||||
actionpack (= 5.1.0.alpha)
|
||||
@ -121,7 +114,7 @@ GEM
|
||||
addressable (2.5.0)
|
||||
public_suffix (~> 2.0, >= 2.0.2)
|
||||
amq-protocol (2.0.1)
|
||||
arel (7.1.2)
|
||||
arel (7.1.4)
|
||||
ast (2.3.0)
|
||||
backburner (1.3.1)
|
||||
beaneater (~> 1.0)
|
||||
@ -132,7 +125,7 @@ GEM
|
||||
bcrypt (3.1.11-x86-mingw32)
|
||||
beaneater (1.0.0)
|
||||
benchmark-ips (2.7.2)
|
||||
blade (0.6.1)
|
||||
blade (0.7.0)
|
||||
activesupport (>= 3.0.0)
|
||||
blade-qunit_adapter (~> 2.0.1)
|
||||
coffee-script
|
||||
@ -141,17 +134,16 @@ GEM
|
||||
eventmachine
|
||||
faye
|
||||
sprockets (>= 3.0)
|
||||
sprockets-export (~> 0.9.1)
|
||||
thin (>= 1.6.0)
|
||||
thor (~> 0.19.1)
|
||||
useragent (~> 0.16.7)
|
||||
blade-qunit_adapter (2.0.1)
|
||||
blade-sauce_labs_plugin (0.6.1)
|
||||
blade-sauce_labs_plugin (0.6.2)
|
||||
childprocess
|
||||
faraday
|
||||
selenium-webdriver
|
||||
builder (3.2.2)
|
||||
bunny (2.2.2)
|
||||
bunny (2.6.2)
|
||||
amq-protocol (>= 2.0.1)
|
||||
byebug (9.0.6)
|
||||
childprocess (0.5.9)
|
||||
@ -162,9 +154,9 @@ GEM
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
concurrent-ruby (1.0.2)
|
||||
connection_pool (2.2.0)
|
||||
coffee-script-source (1.12.2)
|
||||
concurrent-ruby (1.0.4)
|
||||
connection_pool (2.2.1)
|
||||
cookiejar (0.3.3)
|
||||
curses (1.0.2)
|
||||
daemons (1.2.4)
|
||||
@ -201,8 +193,6 @@ GEM
|
||||
eventmachine (>= 0.12.0)
|
||||
websocket-driver (>= 0.5.1)
|
||||
ffi (1.9.14)
|
||||
ffi (1.9.14-x64-mingw32)
|
||||
ffi (1.9.14-x86-mingw32)
|
||||
globalid (0.3.7)
|
||||
activesupport (>= 4.1.0)
|
||||
hiredis (0.6.1)
|
||||
@ -213,7 +203,7 @@ GEM
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.0.2)
|
||||
kindlerb (1.0.1)
|
||||
kindlerb (1.2.0)
|
||||
mustache
|
||||
nokogiri
|
||||
libxml-ruby (2.9.0)
|
||||
@ -241,22 +231,22 @@ GEM
|
||||
mysql2 (0.4.5)
|
||||
mysql2 (0.4.5-x64-mingw32)
|
||||
mysql2 (0.4.5-x86-mingw32)
|
||||
nio4r (1.2.1)
|
||||
nokogiri (1.6.8.1)
|
||||
nio4r (2.0.0)
|
||||
nokogiri (1.7.0)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
nokogiri (1.6.8.1-x64-mingw32)
|
||||
nokogiri (1.7.0-x64-mingw32)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
nokogiri (1.6.8.1-x86-mingw32)
|
||||
nokogiri (1.7.0-x86-mingw32)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
parser (2.3.2.0)
|
||||
parser (2.3.3.1)
|
||||
ast (~> 2.2)
|
||||
pg (0.19.0)
|
||||
pg (0.19.0-x64-mingw32)
|
||||
pg (0.19.0-x86-mingw32)
|
||||
powerpack (0.1.1)
|
||||
psych (2.1.1)
|
||||
psych (2.2.2)
|
||||
public_suffix (2.0.4)
|
||||
puma (3.6.0)
|
||||
puma (3.6.2)
|
||||
qu (0.2.0)
|
||||
multi_json
|
||||
qu-redis (0.2.0)
|
||||
@ -272,17 +262,17 @@ GEM
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails-dom-testing (2.0.1)
|
||||
rails-dom-testing (2.0.2)
|
||||
activesupport (>= 4.2.0, < 6.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
nokogiri (~> 1.6)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rainbow (2.1.0)
|
||||
rake (11.3.0)
|
||||
rb-fsevent (0.9.7)
|
||||
rdoc (5.0.0.beta2)
|
||||
rake (12.0.0)
|
||||
rb-fsevent (0.9.8)
|
||||
rdoc (5.0.0)
|
||||
redcarpet (3.2.3)
|
||||
redis (3.3.1)
|
||||
redis (3.3.2)
|
||||
redis-namespace (1.5.2)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
resque-scheduler (4.3.0)
|
||||
@ -290,49 +280,50 @@ GEM
|
||||
redis (~> 3.3)
|
||||
resque (~> 1.26)
|
||||
rufus-scheduler (~> 3.2)
|
||||
rubocop (0.45.0)
|
||||
rubocop (0.46.0)
|
||||
parser (>= 2.3.1.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-progressbar (1.8.1)
|
||||
ruby_dep (1.4.0)
|
||||
ruby_dep (1.5.0)
|
||||
rubyzip (1.2.0)
|
||||
rufus-scheduler (3.2.2)
|
||||
rufus-scheduler (3.3.1)
|
||||
tzinfo
|
||||
sass (3.4.23)
|
||||
sass-rails (5.0.6)
|
||||
railties (>= 4.0.0, < 6)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
sdoc (1.0.0.beta2)
|
||||
rdoc (= 5.0.0.beta2)
|
||||
selenium-webdriver (3.0.1)
|
||||
sdoc (1.0.0.rc1)
|
||||
rdoc (= 5.0.0)
|
||||
selenium-webdriver (3.0.5)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.0)
|
||||
websocket (~> 1.0)
|
||||
sequel (4.39.0)
|
||||
sequel (4.41.0)
|
||||
serverengine (1.5.11)
|
||||
sigdump (~> 0.2.2)
|
||||
sidekiq (4.2.2)
|
||||
sidekiq (4.2.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
rack-protection (~> 1.5)
|
||||
rack-protection (>= 1.5.0)
|
||||
redis (~> 3.2, >= 3.2.1)
|
||||
sigdump (0.2.4)
|
||||
simple_uuid (0.4.0)
|
||||
sinatra (1.0)
|
||||
rack (>= 1.0)
|
||||
sneakers (2.3.5)
|
||||
bunny (~> 2.2.0)
|
||||
sneakers (2.4.0)
|
||||
bunny (~> 2.6)
|
||||
serverengine (~> 1.5.11)
|
||||
thor
|
||||
thread (~> 0.1.7)
|
||||
sprockets (3.7.0)
|
||||
sprockets (3.7.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-export (0.9.1)
|
||||
sprockets-rails (3.2.0)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
@ -347,7 +338,7 @@ GEM
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (>= 1, < 3)
|
||||
thor (0.19.1)
|
||||
thor (0.19.4)
|
||||
thread (0.1.7)
|
||||
thread_safe (0.3.5)
|
||||
tilt (2.0.5)
|
||||
@ -356,17 +347,17 @@ GEM
|
||||
turbolinks-source (5.0.0)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2016.7)
|
||||
tzinfo-data (1.2016.10)
|
||||
tzinfo (>= 1.0.0)
|
||||
uglifier (3.0.2)
|
||||
uglifier (3.0.4)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.1.1)
|
||||
unicode-display_width (1.1.2)
|
||||
useragent (0.16.8)
|
||||
vegas (0.1.11)
|
||||
rack (>= 1.0.0)
|
||||
w3c_validators (1.2)
|
||||
json
|
||||
nokogiri
|
||||
w3c_validators (1.3.1)
|
||||
json (~> 2.0)
|
||||
nokogiri (~> 1.6)
|
||||
wdm (0.1.1)
|
||||
websocket (1.2.3)
|
||||
websocket-driver (0.6.4)
|
||||
@ -396,7 +387,7 @@ DEPENDENCIES
|
||||
hiredis
|
||||
jquery-rails
|
||||
json (>= 2.0.0)
|
||||
kindlerb (>= 1.0.1)
|
||||
kindlerb (~> 1.2.0)
|
||||
libxml-ruby
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
minitest (< 5.3.4)
|
||||
@ -419,9 +410,8 @@ DEPENDENCIES
|
||||
resque!
|
||||
resque-scheduler
|
||||
rubocop
|
||||
sass!
|
||||
sass-rails
|
||||
sdoc (= 1.0.0.beta2)
|
||||
sdoc (= 1.0.0.rc1)
|
||||
sequel
|
||||
sidekiq
|
||||
sneakers
|
||||
@ -436,4 +426,4 @@ DEPENDENCIES
|
||||
websocket-client-simple!
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.6
|
||||
1.13.7
|
||||
|
@ -13,12 +13,12 @@
|
||||
|
||||
*Vladimir Dementyev*
|
||||
|
||||
* Buffer now writes to websocket connections, to avoid blocking threads
|
||||
* Buffer now writes to WebSocket connections, to avoid blocking threads
|
||||
that could be doing more useful things.
|
||||
|
||||
*Matthew Draper*, *Tinco Andringa*
|
||||
|
||||
* Protect against concurrent writes to a websocket connection from
|
||||
* Protect against concurrent writes to a WebSocket connection from
|
||||
multiple threads; the underlying OS write is not always threadsafe.
|
||||
|
||||
*Tinco Andringa*
|
||||
|
@ -51,7 +51,7 @@ module ApplicationCable
|
||||
self.current_user = find_verified_user
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def find_verified_user
|
||||
if current_user = User.find_by(id: cookies.signed[:user_id])
|
||||
current_user
|
||||
|
@ -20,6 +20,6 @@
|
||||
|
||||
s.add_dependency "actionpack", version
|
||||
|
||||
s.add_dependency "nio4r", "~> 1.2"
|
||||
s.add_dependency "nio4r", "~> 2.0"
|
||||
s.add_dependency "websocket-driver", "~> 0.6.1"
|
||||
end
|
||||
|
@ -122,16 +122,16 @@ def action_methods
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
# action_methods are cached and there is sometimes need to refresh
|
||||
# them. ::clear_action_methods! allows you to do that, so next time
|
||||
# you run action_methods, they will be recalculated.
|
||||
def clear_action_methods!
|
||||
def clear_action_methods! # :doc:
|
||||
@action_methods = nil
|
||||
end
|
||||
|
||||
# Refresh the cached action_methods when a new action_method is added.
|
||||
def method_added(name)
|
||||
def method_added(name) # :doc:
|
||||
super
|
||||
clear_action_methods!
|
||||
end
|
||||
@ -189,22 +189,22 @@ def unsubscribe_from_channel # :nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
# Called once a consumer has become a subscriber of the channel. Usually the place to setup any streams
|
||||
# you want this channel to be sending to the subscriber.
|
||||
def subscribed
|
||||
def subscribed # :doc:
|
||||
# Override in subclasses
|
||||
end
|
||||
|
||||
# Called once a consumer has cut its cable connection. Can be used for cleaning up connections or marking
|
||||
# users as offline or the like.
|
||||
def unsubscribed
|
||||
def unsubscribed # :doc:
|
||||
# Override in subclasses
|
||||
end
|
||||
|
||||
# Transmit a hash of data to the subscriber. The hash will automatically be wrapped in a JSON envelope with
|
||||
# the proper channel identifier marked as the recipient.
|
||||
def transmit(data, via: nil)
|
||||
def transmit(data, via: nil) # :doc:
|
||||
logger.info "#{self.class.name} transmitting #{data.inspect.truncate(300)}".tap { |m| m << " (via #{via})" if via }
|
||||
|
||||
payload = { channel_class: self.class.name, data: data, via: via }
|
||||
@ -213,33 +213,32 @@ def transmit(data, via: nil)
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_confirmation_sent
|
||||
def ensure_confirmation_sent # :doc:
|
||||
return if subscription_rejected?
|
||||
@defer_subscription_confirmation_counter.decrement
|
||||
transmit_subscription_confirmation unless defer_subscription_confirmation?
|
||||
end
|
||||
|
||||
def defer_subscription_confirmation!
|
||||
def defer_subscription_confirmation! # :doc:
|
||||
@defer_subscription_confirmation_counter.increment
|
||||
end
|
||||
|
||||
def defer_subscription_confirmation?
|
||||
def defer_subscription_confirmation? # :doc:
|
||||
@defer_subscription_confirmation_counter.value > 0
|
||||
end
|
||||
|
||||
def subscription_confirmation_sent?
|
||||
def subscription_confirmation_sent? # :doc:
|
||||
@subscription_confirmation_sent
|
||||
end
|
||||
|
||||
def reject
|
||||
def reject # :doc:
|
||||
@reject_subscription = true
|
||||
end
|
||||
|
||||
def subscription_rejected?
|
||||
def subscription_rejected? # :doc:
|
||||
@reject_subscription
|
||||
end
|
||||
|
||||
private
|
||||
def delegate_connection_identifiers
|
||||
connection.identifiers.each do |identifier|
|
||||
define_singleton_method(identifier) do
|
||||
|
@ -22,13 +22,10 @@ module Connection
|
||||
# # Any cleanup work needed when the cable connection is cut.
|
||||
# end
|
||||
#
|
||||
# protected
|
||||
# private
|
||||
# def find_verified_user
|
||||
# if current_user = User.find_by_identity cookies.signed[:identity_id]
|
||||
# current_user
|
||||
# else
|
||||
# User.find_by_identity(cookies.signed[:identity_id]) ||
|
||||
# reject_unauthorized_connection
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
@ -136,9 +133,15 @@ def on_close(reason, code) # :nodoc:
|
||||
send_async :handle_close
|
||||
end
|
||||
|
||||
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
||||
# Workaround for Ruby 2.2 "private attribute?" warning.
|
||||
protected
|
||||
attr_reader :websocket
|
||||
attr_reader :message_buffer
|
||||
|
||||
private
|
||||
# The request that initiated the WebSocket connection is available here. This gives access to the environment, cookies, etc.
|
||||
def request
|
||||
def request # :doc:
|
||||
@request ||= begin
|
||||
environment = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
|
||||
ActionDispatch::Request.new(environment || env)
|
||||
@ -146,14 +149,10 @@ def request
|
||||
end
|
||||
|
||||
# The cookies of the request that initiated the WebSocket connection. Useful for performing authorization checks.
|
||||
def cookies
|
||||
def cookies # :doc:
|
||||
request.cookie_jar
|
||||
end
|
||||
|
||||
attr_reader :websocket
|
||||
attr_reader :message_buffer
|
||||
|
||||
private
|
||||
def encode(cable_message)
|
||||
@coder.encode cable_message
|
||||
end
|
||||
|
@ -28,6 +28,8 @@ def process!
|
||||
receive_buffered_messages
|
||||
end
|
||||
|
||||
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
||||
# Workaround for Ruby 2.2 "private attribute?" warning.
|
||||
protected
|
||||
attr_reader :connection
|
||||
attr_reader :buffered_messages
|
||||
|
@ -61,6 +61,8 @@ def unsubscribe_from_all
|
||||
subscriptions.each { |id, channel| remove_subscription(channel) }
|
||||
end
|
||||
|
||||
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
||||
# Workaround for Ruby 2.2 "private attribute?" warning.
|
||||
protected
|
||||
attr_reader :connection, :subscriptions
|
||||
|
||||
|
@ -31,8 +31,8 @@ def tag(logger)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def log(type, message)
|
||||
private
|
||||
def log(type, message) # :doc:
|
||||
tag(@logger) { @logger.send type, message }
|
||||
end
|
||||
end
|
||||
|
@ -32,6 +32,8 @@ def rack_response
|
||||
websocket.rack_response
|
||||
end
|
||||
|
||||
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
||||
# Workaround for Ruby 2.2 "private attribute?" warning.
|
||||
protected
|
||||
attr_reader :websocket
|
||||
end
|
||||
|
@ -3,7 +3,7 @@ Description:
|
||||
Stubs out a new cable channel for the server (in Ruby) and client (in CoffeeScript).
|
||||
Pass the channel name, either CamelCased or under_scored, and an optional list of channel actions as arguments.
|
||||
|
||||
Note: Turn on the cable connection in app/assets/javascript/cable.js after generating any channels.
|
||||
Note: Turn on the cable connection in app/assets/javascripts/cable.js after generating any channels.
|
||||
|
||||
Example:
|
||||
========
|
||||
@ -11,4 +11,4 @@ Example:
|
||||
|
||||
creates a Chat channel class and CoffeeScript asset:
|
||||
Channel: app/channels/chat_channel.rb
|
||||
Assets: app/assets/javascript/channels/chat.coffee
|
||||
Assets: app/assets/javascripts/channels/chat.coffee
|
||||
|
@ -23,7 +23,7 @@ def create_channel_file
|
||||
generate_application_cable_files
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def file_name
|
||||
@_file_name ||= super.gsub(/_channel/i, "")
|
||||
end
|
||||
|
@ -53,7 +53,7 @@ def connect
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def open_connection_with_stubbed_pubsub
|
||||
server = TestServer.new
|
||||
server.stubs(:adapter).returns(stub_everything("adapter"))
|
||||
|
@ -19,7 +19,7 @@ def connect
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def open_connection_with_stubbed_pubsub
|
||||
server = TestServer.new
|
||||
server.stubs(:pubsub).returns(stub_everything("pubsub"))
|
||||
|
@ -21,7 +21,7 @@ def send_async(method, *args)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def open_connection_with_stubbed_pubsub
|
||||
@server = TestServer.new
|
||||
@server.stubs(:pubsub).returns(stub_everything("pubsub"))
|
||||
|
@ -544,9 +544,9 @@ def deliver_mail(mail) #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def set_payload_for_mail(payload, mail) #:nodoc:
|
||||
def set_payload_for_mail(payload, mail)
|
||||
payload[:mailer] = name
|
||||
payload[:message_id] = mail.message_id
|
||||
payload[:subject] = mail.subject
|
||||
@ -558,7 +558,7 @@ def set_payload_for_mail(payload, mail) #:nodoc:
|
||||
payload[:mail] = mail.encoded
|
||||
end
|
||||
|
||||
def method_missing(method_name, *args) # :nodoc:
|
||||
def method_missing(method_name, *args)
|
||||
if action_methods.include?(method_name.to_s)
|
||||
MessageDelivery.new(self, method_name, *args)
|
||||
else
|
||||
@ -566,9 +566,7 @@ def method_missing(method_name, *args) # :nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def respond_to_missing?(method, include_all = false) #:nodoc:
|
||||
def respond_to_missing?(method, include_all = false)
|
||||
action_methods.include?(method.to_s)
|
||||
end
|
||||
end
|
||||
@ -830,7 +828,7 @@ def mail(headers = {}, &block)
|
||||
message
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
# Used by #mail to set the content type of the message.
|
||||
#
|
||||
@ -841,7 +839,7 @@ def mail(headers = {}, &block)
|
||||
# If there is no content type passed in via headers, and there are no
|
||||
# attachments, or the message is multipart, then the default content type is
|
||||
# used.
|
||||
def set_content_type(m, user_content_type, class_default)
|
||||
def set_content_type(m, user_content_type, class_default) # :doc:
|
||||
params = m.content_type_parameters || {}
|
||||
case
|
||||
when user_content_type.present?
|
||||
@ -863,18 +861,16 @@ def set_content_type(m, user_content_type, class_default)
|
||||
# If it does not find a translation for the +subject+ under the specified scope it will default to a
|
||||
# humanized version of the <tt>action_name</tt>.
|
||||
# If the subject has interpolations, you can pass them through the +interpolations+ parameter.
|
||||
def default_i18n_subject(interpolations = {})
|
||||
def default_i18n_subject(interpolations = {}) # :doc:
|
||||
mailer_scope = self.class.mailer_name.tr("/", ".")
|
||||
I18n.t(:subject, interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize))
|
||||
end
|
||||
|
||||
# Emails do not support relative path links.
|
||||
def self.supports_path?
|
||||
def self.supports_path? # :doc:
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def apply_defaults(headers)
|
||||
default_values = self.class.default.map do |key, value|
|
||||
[
|
||||
|
@ -94,22 +94,22 @@ def preview_name
|
||||
name.sub(/Preview$/, "").underscore
|
||||
end
|
||||
|
||||
protected
|
||||
def load_previews #:nodoc:
|
||||
private
|
||||
def load_previews
|
||||
if preview_path
|
||||
Dir["#{preview_path}/**/*_preview.rb"].each { |file| require_dependency file }
|
||||
end
|
||||
end
|
||||
|
||||
def preview_path #:nodoc:
|
||||
def preview_path
|
||||
Base.preview_path
|
||||
end
|
||||
|
||||
def show_previews #:nodoc:
|
||||
def show_previews
|
||||
Base.show_previews
|
||||
end
|
||||
|
||||
def inform_preview_interceptors(message) #:nodoc:
|
||||
def inform_preview_interceptors(message)
|
||||
Base.preview_interceptors.each do |interceptor|
|
||||
interceptor.previewing_email(message)
|
||||
end
|
||||
|
@ -73,38 +73,36 @@ def determine_default_mailer(name)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def initialize_test_deliveries # :nodoc:
|
||||
def initialize_test_deliveries
|
||||
set_delivery_method :test
|
||||
@old_perform_deliveries = ActionMailer::Base.perform_deliveries
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries.clear
|
||||
end
|
||||
|
||||
def restore_test_deliveries # :nodoc:
|
||||
def restore_test_deliveries
|
||||
restore_delivery_method
|
||||
ActionMailer::Base.perform_deliveries = @old_perform_deliveries
|
||||
end
|
||||
|
||||
def set_delivery_method(method) # :nodoc:
|
||||
def set_delivery_method(method)
|
||||
@old_delivery_method = ActionMailer::Base.delivery_method
|
||||
ActionMailer::Base.delivery_method = method
|
||||
end
|
||||
|
||||
def restore_delivery_method # :nodoc:
|
||||
def restore_delivery_method
|
||||
ActionMailer::Base.deliveries.clear
|
||||
ActionMailer::Base.delivery_method = @old_delivery_method
|
||||
end
|
||||
|
||||
def set_expected_mail # :nodoc:
|
||||
def set_expected_mail
|
||||
@expected = Mail.new
|
||||
@expected.content_type ["text", "plain", { "charset" => charset }]
|
||||
@expected.mime_version = "1.0"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def charset
|
||||
"UTF-8"
|
||||
end
|
||||
|
@ -19,12 +19,11 @@ def create_mailer_file
|
||||
|
||||
hook_for :template_engine, :test_framework
|
||||
|
||||
protected
|
||||
def file_name
|
||||
private
|
||||
def file_name # :doc:
|
||||
@_file_name ||= super.gsub(/_mailer/i, "")
|
||||
end
|
||||
|
||||
private
|
||||
def application_mailer_file_name
|
||||
@_application_mailer_file_name ||= if mountable_engine?
|
||||
"app/mailers/#{namespaced_path}/application_mailer.rb"
|
||||
|
@ -829,7 +829,7 @@ def a_callback
|
||||
assert_equal "special indeed!", mail["X-Special-Header"].to_s
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
# Execute the block setting the given values and restoring old values after
|
||||
# the block is executed.
|
||||
|
@ -66,7 +66,7 @@ def test_send_mail
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def with_translation(locale, data)
|
||||
I18n.backend.store_translations(locale, data)
|
||||
|
@ -65,7 +65,7 @@ def use_cache
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def mail_with_defaults(&block)
|
||||
mail(to: "test@localhost", from: "tester@example.com",
|
||||
|
@ -1,15 +1,15 @@
|
||||
* Use accept header in integration tests with `as: :json`
|
||||
|
||||
Instead of appending the `format` to the request path. Rails will figure
|
||||
Instead of appending the `format` to the request path, Rails will figure
|
||||
out the format from the header instead.
|
||||
|
||||
This allows devs to use `:as` on routes that don't have a format.
|
||||
|
||||
|
||||
Fixes #27144.
|
||||
|
||||
*Kasper Timm Hansen*
|
||||
|
||||
* Reset a new session directly after its creation in ActionDispatch::IntegrationTest#open_session.
|
||||
* Reset a new session directly after its creation in `ActionDispatch::IntegrationTest#open_session`.
|
||||
|
||||
Fixes #22742.
|
||||
|
||||
|
@ -52,9 +52,9 @@ def view_cache_dependencies
|
||||
self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
# Convenience accessor.
|
||||
def cache(key, options = {}, &block)
|
||||
def cache(key, options = {}, &block) # :doc:
|
||||
if cache_configured?
|
||||
cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
|
||||
else
|
||||
|
@ -19,7 +19,7 @@ def #{sym}(*args, &block)
|
||||
generate_method_for_mime(mime) unless instance_methods.include?(mime.to_sym)
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def method_missing(symbol, &block)
|
||||
unless mime_constant = Mime[symbol]
|
||||
|
@ -139,8 +139,8 @@ def self.make_response!(request)
|
||||
end
|
||||
end
|
||||
|
||||
def self.encoding_for_param(action, param) # :nodoc:
|
||||
::Encoding::UTF_8
|
||||
def self.binary_params_for?(action) # :nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
# Delegates to the class' <tt>controller_name</tt>
|
||||
|
@ -11,7 +11,7 @@ module DataStreaming
|
||||
DEFAULT_SEND_FILE_TYPE = "application/octet-stream".freeze #:nodoc:
|
||||
DEFAULT_SEND_FILE_DISPOSITION = "attachment".freeze #:nodoc:
|
||||
|
||||
protected
|
||||
private
|
||||
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
|
||||
# via the Rack::Sendfile middleware. The header to use is set via
|
||||
# +config.action_dispatch.x_sendfile_header+.
|
||||
@ -70,7 +70,6 @@ def send_file(path, options = {}) #:doc:
|
||||
send_file_headers! options
|
||||
|
||||
self.status = options[:status] || 200
|
||||
self.content_type = options[:type] if options.key?(:type)
|
||||
self.content_type = options[:content_type] if options.key?(:content_type)
|
||||
response.send_file path
|
||||
end
|
||||
@ -109,10 +108,12 @@ def send_data(data, options = {}) #:doc:
|
||||
render options.slice(:status, :content_type).merge(body: data)
|
||||
end
|
||||
|
||||
private
|
||||
def send_file_headers!(options)
|
||||
type_provided = options.has_key?(:type)
|
||||
|
||||
self.content_type = DEFAULT_SEND_FILE_TYPE
|
||||
response.sending_file = true
|
||||
|
||||
content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE)
|
||||
raise ArgumentError, ":type option required" if content_type.nil?
|
||||
|
||||
@ -137,8 +138,6 @@ def send_file_headers!(options)
|
||||
|
||||
headers["Content-Transfer-Encoding"] = "binary"
|
||||
|
||||
response.sending_file = true
|
||||
|
||||
# Fix a problem with IE 6.0 on opening downloaded files:
|
||||
# If Cache-Control: no-cache is set (which Rails does by default),
|
||||
# IE removes the file it just downloaded from its cache immediately
|
||||
|
@ -42,7 +42,7 @@ def add_flash_types(*types)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
|
||||
self.class._flash_types.each do |flash_type|
|
||||
if type = response_status_and_flash.delete(flash_type)
|
||||
|
@ -28,7 +28,7 @@ module HttpAuthentication
|
||||
# class ApplicationController < ActionController::Base
|
||||
# before_action :set_account, :authenticate
|
||||
#
|
||||
# protected
|
||||
# private
|
||||
# def set_account
|
||||
# @account = Account.find_by(url_name: request.subdomains.first)
|
||||
# end
|
||||
@ -363,7 +363,7 @@ def opaque(secret_key)
|
||||
# class ApplicationController < ActionController::Base
|
||||
# before_action :set_account, :authenticate
|
||||
#
|
||||
# protected
|
||||
# private
|
||||
# def set_account
|
||||
# @account = Account.find_by(url_name: request.subdomains.first)
|
||||
# end
|
||||
|
@ -83,14 +83,14 @@ def halted_callback_hook(filter)
|
||||
# end
|
||||
#
|
||||
# :api: plugin
|
||||
def cleanup_view_runtime #:nodoc:
|
||||
def cleanup_view_runtime
|
||||
yield
|
||||
end
|
||||
|
||||
# Every time after an action is processed, this method is invoked
|
||||
# with the payload, so you can add more information.
|
||||
# :api: plugin
|
||||
def append_info_to_payload(payload) #:nodoc:
|
||||
def append_info_to_payload(payload)
|
||||
payload[:view_runtime] = view_runtime
|
||||
end
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
module ActionController
|
||||
# Allows encoding to be specified per parameter per action.
|
||||
# Specify binary encoding for parameters for a given action.
|
||||
module ParameterEncoding
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
@ -13,17 +13,36 @@ def setup_param_encode # :nodoc:
|
||||
@_parameter_encodings = {}
|
||||
end
|
||||
|
||||
def encoding_for_param(action, param) # :nodoc:
|
||||
if @_parameter_encodings[action.to_s] && @_parameter_encodings[action.to_s][param.to_s]
|
||||
@_parameter_encodings[action.to_s][param.to_s]
|
||||
else
|
||||
super
|
||||
end
|
||||
def binary_params_for?(action) # :nodoc:
|
||||
@_parameter_encodings[action.to_s]
|
||||
end
|
||||
|
||||
def parameter_encoding(action, param_name, encoding)
|
||||
@_parameter_encodings[action.to_s] ||= {}
|
||||
@_parameter_encodings[action.to_s][param_name.to_s] = encoding
|
||||
# Specify that a given action's parameters should all be encoded as
|
||||
# ASCII-8BIT (it "skips" the encoding default of UTF-8).
|
||||
#
|
||||
# For example, a controller would use it like this:
|
||||
#
|
||||
# class RepositoryController < ActionController::Base
|
||||
# skip_parameter_encoding :show
|
||||
#
|
||||
# def show
|
||||
# @repo = Repository.find_by_filesystem_path params[:file_path]
|
||||
#
|
||||
# # `repo_name` is guaranteed to be UTF-8, but was ASCII-8BIT, so
|
||||
# # tag it as such
|
||||
# @repo_name = params[:repo_name].force_encoding 'UTF-8'
|
||||
# end
|
||||
#
|
||||
# def index
|
||||
# @repositories = Repository.all
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# The show action in the above controller would have all parameter values
|
||||
# encoded as ASCII-8BIT. This is useful in the case where an application
|
||||
# must handle data but encoding of the data is unknown, like file system data.
|
||||
def skip_parameter_encoding(action)
|
||||
@_parameter_encodings[action.to_s] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -135,7 +135,7 @@ def name
|
||||
#
|
||||
# This method also does namespace lookup. Foo::Bar::UsersController will
|
||||
# try to find Foo::Bar::User, Foo::User and finally User.
|
||||
def _default_wrap_model #:nodoc:
|
||||
def _default_wrap_model
|
||||
return nil if klass.anonymous?
|
||||
model_name = klass.name.sub(/Controller$/, "").classify
|
||||
|
||||
|
@ -104,7 +104,7 @@ module ClassMethods
|
||||
#
|
||||
# Since <tt>ActionController::Metal</tt> controllers cannot render, the controller
|
||||
# must include <tt>AbstractController::Rendering</tt>, <tt>ActionController::Rendering</tt>,
|
||||
# and <tt>ActionController::Renderers</tt>, and have at lest one renderer.
|
||||
# and <tt>ActionController::Renderers</tt>, and have at least one renderer.
|
||||
#
|
||||
# Rather than including <tt>ActionController::Renderers::All</tt> and including all renderers,
|
||||
# you may specify which renderers to include by passing the renderer name or names to
|
||||
|
@ -67,20 +67,20 @@ def _set_html_content_type
|
||||
end
|
||||
|
||||
def _set_rendered_content_type(format)
|
||||
unless response.content_type
|
||||
if format && !response.content_type
|
||||
self.content_type = format.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Normalize arguments by catching blocks and setting them on :update.
|
||||
def _normalize_args(action = nil, options = {}, &blk) #:nodoc:
|
||||
def _normalize_args(action = nil, options = {}, &blk)
|
||||
options = super
|
||||
options[:update] = blk if block_given?
|
||||
options
|
||||
end
|
||||
|
||||
# Normalize both text and status options.
|
||||
def _normalize_options(options) #:nodoc:
|
||||
def _normalize_options(options)
|
||||
_normalize_text(options)
|
||||
|
||||
if options[:html]
|
||||
@ -103,7 +103,7 @@ def _normalize_text(options)
|
||||
end
|
||||
|
||||
# Process controller specific options, as status, content-type and location.
|
||||
def _process_options(options) #:nodoc:
|
||||
def _process_options(options)
|
||||
status, content_type, location = options.values_at(:status, :content_type, :location)
|
||||
|
||||
self.status = status if status
|
||||
|
@ -152,7 +152,7 @@ def handle_unverified_request
|
||||
request.cookie_jar = NullCookieJar.build(request, {})
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc:
|
||||
def initialize(req)
|
||||
@ -197,7 +197,7 @@ def handle_unverified_request
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
# The actual before_action that is used to verify the CSRF token.
|
||||
# Don't override this directly. Provide your own forgery protection
|
||||
# strategy instead. If you override, you'll disable same-origin
|
||||
@ -208,7 +208,7 @@ def handle_unverified_request
|
||||
# enabled on an action, this before_action flags its after_action to
|
||||
# verify that JavaScript responses are for XHR requests, ensuring they
|
||||
# follow the browser's same-origin policy.
|
||||
def verify_authenticity_token
|
||||
def verify_authenticity_token # :doc:
|
||||
mark_for_same_origin_verification!
|
||||
|
||||
if !verified_request?
|
||||
@ -219,7 +219,7 @@ def verify_authenticity_token
|
||||
end
|
||||
end
|
||||
|
||||
def handle_unverified_request
|
||||
def handle_unverified_request # :doc:
|
||||
forgery_protection_strategy.new(self).handle_unverified_request
|
||||
end
|
||||
|
||||
@ -233,7 +233,7 @@ def handle_unverified_request
|
||||
# If `verify_authenticity_token` was run (indicating that we have
|
||||
# forgery protection enabled for this request) then also verify that
|
||||
# we aren't serving an unauthorized cross-origin response.
|
||||
def verify_same_origin_request
|
||||
def verify_same_origin_request # :doc:
|
||||
if marked_for_same_origin_verification? && non_xhr_javascript_response?
|
||||
if logger && log_warning_on_csrf_failure
|
||||
logger.warn CROSS_ORIGIN_JAVASCRIPT_WARNING
|
||||
@ -243,18 +243,18 @@ def verify_same_origin_request
|
||||
end
|
||||
|
||||
# GET requests are checked for cross-origin JavaScript after rendering.
|
||||
def mark_for_same_origin_verification!
|
||||
def mark_for_same_origin_verification! # :doc:
|
||||
@marked_for_same_origin_verification = request.get?
|
||||
end
|
||||
|
||||
# If the `verify_authenticity_token` before_action ran, verify that
|
||||
# JavaScript responses are only served to same-origin GET requests.
|
||||
def marked_for_same_origin_verification?
|
||||
def marked_for_same_origin_verification? # :doc:
|
||||
@marked_for_same_origin_verification ||= false
|
||||
end
|
||||
|
||||
# Check for cross-origin JavaScript responses.
|
||||
def non_xhr_javascript_response?
|
||||
def non_xhr_javascript_response? # :doc:
|
||||
content_type =~ %r(\Atext/javascript) && !request.xhr?
|
||||
end
|
||||
|
||||
@ -265,20 +265,20 @@ def non_xhr_javascript_response?
|
||||
# * Is it a GET or HEAD request? Gets should be safe and idempotent
|
||||
# * Does the form_authenticity_token match the given token value from the params?
|
||||
# * Does the X-CSRF-Token header match the form_authenticity_token
|
||||
def verified_request?
|
||||
def verified_request? # :doc:
|
||||
!protect_against_forgery? || request.get? || request.head? ||
|
||||
(valid_request_origin? && any_authenticity_token_valid?)
|
||||
end
|
||||
|
||||
# Checks if any of the authenticity tokens from the request are valid.
|
||||
def any_authenticity_token_valid?
|
||||
def any_authenticity_token_valid? # :doc:
|
||||
request_authenticity_tokens.any? do |token|
|
||||
valid_authenticity_token?(session, token)
|
||||
end
|
||||
end
|
||||
|
||||
# Possible authenticity tokens sent in the request.
|
||||
def request_authenticity_tokens
|
||||
def request_authenticity_tokens # :doc:
|
||||
[form_authenticity_param, request.x_csrf_token]
|
||||
end
|
||||
|
||||
@ -290,7 +290,7 @@ def form_authenticity_token(form_options: {})
|
||||
# Creates a masked version of the authenticity token that varies
|
||||
# on each request. The masking is used to mitigate SSL attacks
|
||||
# like BREACH.
|
||||
def masked_authenticity_token(session, form_options: {})
|
||||
def masked_authenticity_token(session, form_options: {}) # :doc:
|
||||
action, method = form_options.values_at(:action, :method)
|
||||
|
||||
raw_token = if per_form_csrf_tokens && action && method
|
||||
@ -309,7 +309,7 @@ def masked_authenticity_token(session, form_options: {})
|
||||
# Checks the client's masked token to see if it matches the
|
||||
# session token. Essentially the inverse of
|
||||
# +masked_authenticity_token+.
|
||||
def valid_authenticity_token?(session, encoded_masked_token)
|
||||
def valid_authenticity_token?(session, encoded_masked_token) # :doc:
|
||||
if encoded_masked_token.nil? || encoded_masked_token.empty? || !encoded_masked_token.is_a?(String)
|
||||
return false
|
||||
end
|
||||
@ -340,7 +340,7 @@ def valid_authenticity_token?(session, encoded_masked_token)
|
||||
end
|
||||
end
|
||||
|
||||
def unmask_token(masked_token)
|
||||
def unmask_token(masked_token) # :doc:
|
||||
# Split the token into the one-time pad and the encrypted
|
||||
# value and decrypt it
|
||||
one_time_pad = masked_token[0...AUTHENTICITY_TOKEN_LENGTH]
|
||||
@ -348,11 +348,11 @@ def unmask_token(masked_token)
|
||||
xor_byte_strings(one_time_pad, encrypted_csrf_token)
|
||||
end
|
||||
|
||||
def compare_with_real_token(token, session)
|
||||
def compare_with_real_token(token, session) # :doc:
|
||||
ActiveSupport::SecurityUtils.secure_compare(token, real_csrf_token(session))
|
||||
end
|
||||
|
||||
def valid_per_form_csrf_token?(token, session)
|
||||
def valid_per_form_csrf_token?(token, session) # :doc:
|
||||
if per_form_csrf_tokens
|
||||
correct_token = per_form_csrf_token(
|
||||
session,
|
||||
@ -366,12 +366,12 @@ def valid_per_form_csrf_token?(token, session)
|
||||
end
|
||||
end
|
||||
|
||||
def real_csrf_token(session)
|
||||
def real_csrf_token(session) # :doc:
|
||||
session[:_csrf_token] ||= SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH)
|
||||
Base64.strict_decode64(session[:_csrf_token])
|
||||
end
|
||||
|
||||
def per_form_csrf_token(session, action_path, method)
|
||||
def per_form_csrf_token(session, action_path, method) # :doc:
|
||||
OpenSSL::HMAC.digest(
|
||||
OpenSSL::Digest::SHA256.new,
|
||||
real_csrf_token(session),
|
||||
@ -379,25 +379,25 @@ def per_form_csrf_token(session, action_path, method)
|
||||
)
|
||||
end
|
||||
|
||||
def xor_byte_strings(s1, s2)
|
||||
def xor_byte_strings(s1, s2) # :doc:
|
||||
s2_bytes = s2.bytes
|
||||
s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 }
|
||||
s2_bytes.pack("C*")
|
||||
end
|
||||
|
||||
# The form's authenticity parameter. Override to provide your own.
|
||||
def form_authenticity_param
|
||||
def form_authenticity_param # :doc:
|
||||
params[request_forgery_protection_token]
|
||||
end
|
||||
|
||||
# Checks if the controller allows forgery protection.
|
||||
def protect_against_forgery?
|
||||
def protect_against_forgery? # :doc:
|
||||
allow_forgery_protection
|
||||
end
|
||||
|
||||
# Checks if the request originated from the same origin by looking at the
|
||||
# Origin header.
|
||||
def valid_request_origin?
|
||||
def valid_request_origin? # :doc:
|
||||
if forgery_protection_origin_check
|
||||
# We accept blank origin headers because some user agents don't send it.
|
||||
request.origin.nil? || request.origin == request.base_url
|
||||
@ -406,7 +406,7 @@ def valid_request_origin?
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_action_path(action_path)
|
||||
def normalize_action_path(action_path) # :doc:
|
||||
uri = URI.parse(action_path)
|
||||
uri.path.chomp("/")
|
||||
end
|
||||
|
@ -193,10 +193,10 @@ module ActionController #:nodoc:
|
||||
module Streaming
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
# Set proper cache control and transfer encoding when streaming
|
||||
def _process_options(options) #:nodoc:
|
||||
def _process_options(options)
|
||||
super
|
||||
if options[:stream]
|
||||
if request.version == "HTTP/1.0"
|
||||
@ -210,7 +210,7 @@ def _process_options(options) #:nodoc:
|
||||
end
|
||||
|
||||
# Call render_body if we are streaming instead of usual +render+.
|
||||
def _render_template(options) #:nodoc:
|
||||
def _render_template(options)
|
||||
if options.delete(:stream)
|
||||
Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
|
||||
else
|
||||
|
@ -3,6 +3,7 @@
|
||||
require "active_support/core_ext/object/to_query"
|
||||
require "active_support/core_ext/module/anonymous"
|
||||
require "active_support/core_ext/hash/keys"
|
||||
require "active_support/testing/constant_lookup"
|
||||
require "action_controller/template_assertions"
|
||||
require "rails-dom-testing"
|
||||
|
||||
@ -514,8 +515,6 @@ def process(action, method: "GET", params: {}, session: nil, body: nil, flash: {
|
||||
@request = @controller.request
|
||||
@response = @controller.response
|
||||
|
||||
@request.delete_header "HTTP_COOKIE"
|
||||
|
||||
if @request.have_cookie_jar?
|
||||
unless @request.cookie_jar.committed?
|
||||
@request.cookie_jar.write(@response)
|
||||
|
@ -51,28 +51,28 @@ def filtered_path
|
||||
@filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}"
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def parameter_filter
|
||||
def parameter_filter # :doc:
|
||||
parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
|
||||
return NULL_PARAM_FILTER
|
||||
}
|
||||
end
|
||||
|
||||
def env_filter
|
||||
def env_filter # :doc:
|
||||
user_key = fetch_header("action_dispatch.parameter_filter") {
|
||||
return NULL_ENV_FILTER
|
||||
}
|
||||
parameter_filter_for(Array(user_key) + ENV_MATCH)
|
||||
end
|
||||
|
||||
def parameter_filter_for(filters)
|
||||
def parameter_filter_for(filters) # :doc:
|
||||
ParameterFilter.new(filters)
|
||||
end
|
||||
|
||||
KV_RE = "[^&;=]+"
|
||||
PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
|
||||
def filtered_query_string
|
||||
def filtered_query_string # :doc:
|
||||
query_string.gsub(PAIR_RE) do |_|
|
||||
parameter_filter.filter([[$1, $2]]).first.join("=")
|
||||
end
|
||||
|
@ -150,20 +150,20 @@ def negotiate_mime(order)
|
||||
order.include?(Mime::ALL) ? format : nil
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
|
||||
|
||||
def valid_accept_header
|
||||
def valid_accept_header # :doc:
|
||||
(xhr? && (accept.present? || content_mime_type)) ||
|
||||
(accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
|
||||
end
|
||||
|
||||
def use_accept_header
|
||||
def use_accept_header # :doc:
|
||||
!self.class.ignore_accept_header
|
||||
end
|
||||
|
||||
def format_from_path_extension
|
||||
def format_from_path_extension # :doc:
|
||||
path = get_header("action_dispatch.original_path") || get_header("PATH_INFO")
|
||||
if match = path && path.match(/\.(\w+)\z/)
|
||||
Mime[match.captures.first]
|
||||
|
@ -278,6 +278,8 @@ def html?
|
||||
|
||||
def all?; false; end
|
||||
|
||||
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
||||
# Workaround for Ruby 2.2 "private attribute?" warning.
|
||||
protected
|
||||
|
||||
attr_reader :string, :synonyms
|
||||
@ -295,7 +297,7 @@ def method_missing(method, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def respond_to_missing?(method, include_private = false) #:nodoc:
|
||||
def respond_to_missing?(method, include_private = false)
|
||||
method.to_s.ends_with? "?"
|
||||
end
|
||||
end
|
||||
|
@ -45,7 +45,7 @@ def parameters
|
||||
query_parameters.dup
|
||||
end
|
||||
params.merge!(path_parameters)
|
||||
params = set_custom_encoding(params)
|
||||
params = set_binary_encoding(params)
|
||||
set_header("action_dispatch.request.parameters", params)
|
||||
params
|
||||
end
|
||||
@ -73,21 +73,16 @@ def path_parameters
|
||||
|
||||
private
|
||||
|
||||
def set_custom_encoding(params)
|
||||
def set_binary_encoding(params)
|
||||
action = params[:action]
|
||||
params.each do |k, v|
|
||||
if v.is_a?(String) && v.encoding != encoding_template(action, k)
|
||||
params[k] = v.force_encoding(encoding_template(action, k))
|
||||
if controller_class.binary_params_for?(action)
|
||||
ActionDispatch::Request::Utils.each_param_value(params) do |param|
|
||||
param.force_encoding ::Encoding::ASCII_8BIT
|
||||
end
|
||||
end
|
||||
|
||||
params
|
||||
end
|
||||
|
||||
def encoding_template(action, param)
|
||||
controller_class.encoding_for_param(action, param)
|
||||
end
|
||||
|
||||
def parse_formatted_parameters(parsers)
|
||||
return yield if content_length.zero? || content_mime_type.nil?
|
||||
|
||||
|
@ -69,7 +69,7 @@ def commit_cookie_jar! # :nodoc:
|
||||
PASS_NOT_FOUND = Class.new { # :nodoc:
|
||||
def self.action(_); self; end
|
||||
def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
|
||||
def self.encoding_for_param(action, param); ::Encoding::UTF_8; end
|
||||
def self.binary_params_for?(action); false; end
|
||||
}
|
||||
|
||||
def controller_class
|
||||
@ -85,6 +85,9 @@ def controller_class
|
||||
end
|
||||
end
|
||||
|
||||
# Returns true if the request has a header matching the given key parameter.
|
||||
#
|
||||
# request.key? :ip_spoofing_check # => true
|
||||
def key?(key)
|
||||
has_header? key
|
||||
end
|
||||
|
@ -227,7 +227,9 @@ def content_type=(content_type)
|
||||
return unless content_type
|
||||
new_header_info = parse_content_type(content_type.to_s)
|
||||
prev_header_info = parsed_content_type_header
|
||||
set_content_type new_header_info.mime_type, new_header_info.charset || prev_header_info.charset || self.class.default_charset
|
||||
charset = new_header_info.charset || prev_header_info.charset
|
||||
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
||||
set_content_type new_header_info.mime_type, charset
|
||||
end
|
||||
|
||||
# Sets the HTTP response's content MIME type. For example, in the controller
|
||||
@ -408,7 +410,7 @@ def cookies
|
||||
def parse_content_type(content_type)
|
||||
if content_type
|
||||
type, charset = content_type.split(/;\s*charset=/)
|
||||
type = nil if type.empty?
|
||||
type = nil if type && type.empty?
|
||||
ContentTypeHeader.new(type, charset)
|
||||
else
|
||||
NullContentTypeHeader
|
||||
|
@ -36,7 +36,7 @@ def generate(name, options, path_parameters, parameterize = nil)
|
||||
|
||||
route.parts.reverse_each do |key|
|
||||
break if defaults[key].nil? && parameterized_parts[key].present?
|
||||
break if parameterized_parts[key].to_s != defaults[key].to_s
|
||||
next if parameterized_parts[key].to_s != defaults[key].to_s
|
||||
break if required_parts.include?(key)
|
||||
|
||||
parameterized_parts.delete(key)
|
||||
@ -92,7 +92,11 @@ def match_route(name, options)
|
||||
else
|
||||
routes = non_recursive(cache, options)
|
||||
|
||||
hash = routes.group_by { |_, r| r.score(options) }
|
||||
supplied_keys = options.each_with_object({}) do |(k, v), h|
|
||||
h[k.to_s] = true if v
|
||||
end
|
||||
|
||||
hash = routes.group_by { |_, r| r.score(supplied_keys) }
|
||||
|
||||
hash.keys.sort.reverse_each do |score|
|
||||
break if score < 0
|
||||
|
@ -1,198 +1,199 @@
|
||||
#
|
||||
# DO NOT MODIFY!!!!
|
||||
# This file is automatically generated by Racc 1.4.11
|
||||
# This file is automatically generated by Racc 1.4.14
|
||||
# from Racc grammer file "".
|
||||
#
|
||||
|
||||
require "racc/parser.rb"
|
||||
require 'racc/parser.rb'
|
||||
|
||||
# :stopdoc:
|
||||
|
||||
require "action_dispatch/journey/parser_extras"
|
||||
module ActionDispatch
|
||||
# :stopdoc:
|
||||
module Journey
|
||||
class Parser < Racc::Parser
|
||||
##### State transition tables begin ###
|
||||
##### State transition tables begin ###
|
||||
|
||||
racc_action_table = [
|
||||
13, 15, 14, 7, 21, 16, 8, 19, 13, 15,
|
||||
14, 7, 17, 16, 8, 13, 15, 14, 7, 24,
|
||||
16, 8, 13, 15, 14, 7, 19, 16, 8 ]
|
||||
racc_action_table = [
|
||||
13, 15, 14, 7, 19, 16, 8, 19, 13, 15,
|
||||
14, 7, 17, 16, 8, 13, 15, 14, 7, 21,
|
||||
16, 8, 13, 15, 14, 7, 24, 16, 8 ]
|
||||
|
||||
racc_action_check = [
|
||||
2, 2, 2, 2, 17, 2, 2, 2, 0, 0,
|
||||
0, 0, 1, 0, 0, 19, 19, 19, 19, 20,
|
||||
19, 19, 7, 7, 7, 7, 22, 7, 7 ]
|
||||
racc_action_check = [
|
||||
2, 2, 2, 2, 22, 2, 2, 2, 19, 19,
|
||||
19, 19, 1, 19, 19, 7, 7, 7, 7, 17,
|
||||
7, 7, 0, 0, 0, 0, 20, 0, 0 ]
|
||||
|
||||
racc_action_pointer = [
|
||||
6, 12, -2, nil, nil, nil, nil, 20, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, 4, nil, 13,
|
||||
13, nil, 17, nil, nil ]
|
||||
racc_action_pointer = [
|
||||
20, 12, -2, nil, nil, nil, nil, 13, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, 19, nil, 6,
|
||||
20, nil, -5, nil, nil ]
|
||||
|
||||
racc_action_default = [
|
||||
-19, -19, -2, -3, -4, -5, -6, -19, -10, -11,
|
||||
-12, -13, -14, -15, -16, -17, -18, -19, -1, -19,
|
||||
-19, 25, -8, -9, -7 ]
|
||||
racc_action_default = [
|
||||
-19, -19, -2, -3, -4, -5, -6, -19, -10, -11,
|
||||
-12, -13, -14, -15, -16, -17, -18, -19, -1, -19,
|
||||
-19, 25, -8, -9, -7 ]
|
||||
|
||||
racc_goto_table = [
|
||||
1, 22, 18, 23, nil, nil, nil, 20 ]
|
||||
racc_goto_table = [
|
||||
1, 22, 18, 23, nil, nil, nil, 20 ]
|
||||
|
||||
racc_goto_check = [
|
||||
1, 2, 1, 3, nil, nil, nil, 1 ]
|
||||
racc_goto_check = [
|
||||
1, 2, 1, 3, nil, nil, nil, 1 ]
|
||||
|
||||
racc_goto_pointer = [
|
||||
nil, 0, -18, -16, nil, nil, nil, nil, nil, nil,
|
||||
nil ]
|
||||
racc_goto_pointer = [
|
||||
nil, 0, -18, -16, nil, nil, nil, nil, nil, nil,
|
||||
nil ]
|
||||
|
||||
racc_goto_default = [
|
||||
nil, nil, 2, 3, 4, 5, 6, 9, 10, 11,
|
||||
12 ]
|
||||
racc_goto_default = [
|
||||
nil, nil, 2, 3, 4, 5, 6, 9, 10, 11,
|
||||
12 ]
|
||||
|
||||
racc_reduce_table = [
|
||||
0, 0, :racc_error,
|
||||
2, 11, :_reduce_1,
|
||||
1, 11, :_reduce_2,
|
||||
1, 11, :_reduce_none,
|
||||
1, 12, :_reduce_none,
|
||||
1, 12, :_reduce_none,
|
||||
1, 12, :_reduce_none,
|
||||
3, 15, :_reduce_7,
|
||||
3, 13, :_reduce_8,
|
||||
3, 13, :_reduce_9,
|
||||
1, 16, :_reduce_10,
|
||||
1, 14, :_reduce_none,
|
||||
1, 14, :_reduce_none,
|
||||
1, 14, :_reduce_none,
|
||||
1, 14, :_reduce_none,
|
||||
1, 19, :_reduce_15,
|
||||
1, 17, :_reduce_16,
|
||||
1, 18, :_reduce_17,
|
||||
1, 20, :_reduce_18 ]
|
||||
racc_reduce_table = [
|
||||
0, 0, :racc_error,
|
||||
2, 11, :_reduce_1,
|
||||
1, 11, :_reduce_2,
|
||||
1, 11, :_reduce_none,
|
||||
1, 12, :_reduce_none,
|
||||
1, 12, :_reduce_none,
|
||||
1, 12, :_reduce_none,
|
||||
3, 15, :_reduce_7,
|
||||
3, 13, :_reduce_8,
|
||||
3, 13, :_reduce_9,
|
||||
1, 16, :_reduce_10,
|
||||
1, 14, :_reduce_none,
|
||||
1, 14, :_reduce_none,
|
||||
1, 14, :_reduce_none,
|
||||
1, 14, :_reduce_none,
|
||||
1, 19, :_reduce_15,
|
||||
1, 17, :_reduce_16,
|
||||
1, 18, :_reduce_17,
|
||||
1, 20, :_reduce_18 ]
|
||||
|
||||
racc_reduce_n = 19
|
||||
racc_reduce_n = 19
|
||||
|
||||
racc_shift_n = 25
|
||||
racc_shift_n = 25
|
||||
|
||||
racc_token_table = {
|
||||
false => 0,
|
||||
:error => 1,
|
||||
:SLASH => 2,
|
||||
:LITERAL => 3,
|
||||
:SYMBOL => 4,
|
||||
:LPAREN => 5,
|
||||
:RPAREN => 6,
|
||||
:DOT => 7,
|
||||
:STAR => 8,
|
||||
:OR => 9 }
|
||||
racc_token_table = {
|
||||
false => 0,
|
||||
:error => 1,
|
||||
:SLASH => 2,
|
||||
:LITERAL => 3,
|
||||
:SYMBOL => 4,
|
||||
:LPAREN => 5,
|
||||
:RPAREN => 6,
|
||||
:DOT => 7,
|
||||
:STAR => 8,
|
||||
:OR => 9 }
|
||||
|
||||
racc_nt_base = 10
|
||||
racc_nt_base = 10
|
||||
|
||||
racc_use_result_var = false
|
||||
racc_use_result_var = false
|
||||
|
||||
Racc_arg = [
|
||||
racc_action_table,
|
||||
racc_action_check,
|
||||
racc_action_default,
|
||||
racc_action_pointer,
|
||||
racc_goto_table,
|
||||
racc_goto_check,
|
||||
racc_goto_default,
|
||||
racc_goto_pointer,
|
||||
racc_nt_base,
|
||||
racc_reduce_table,
|
||||
racc_token_table,
|
||||
racc_shift_n,
|
||||
racc_reduce_n,
|
||||
racc_use_result_var ]
|
||||
Racc_arg = [
|
||||
racc_action_table,
|
||||
racc_action_check,
|
||||
racc_action_default,
|
||||
racc_action_pointer,
|
||||
racc_goto_table,
|
||||
racc_goto_check,
|
||||
racc_goto_default,
|
||||
racc_goto_pointer,
|
||||
racc_nt_base,
|
||||
racc_reduce_table,
|
||||
racc_token_table,
|
||||
racc_shift_n,
|
||||
racc_reduce_n,
|
||||
racc_use_result_var ]
|
||||
|
||||
Racc_token_to_s_table = [
|
||||
"$end",
|
||||
"error",
|
||||
"SLASH",
|
||||
"LITERAL",
|
||||
"SYMBOL",
|
||||
"LPAREN",
|
||||
"RPAREN",
|
||||
"DOT",
|
||||
"STAR",
|
||||
"OR",
|
||||
"$start",
|
||||
"expressions",
|
||||
"expression",
|
||||
"or",
|
||||
"terminal",
|
||||
"group",
|
||||
"star",
|
||||
"symbol",
|
||||
"literal",
|
||||
"slash",
|
||||
"dot" ]
|
||||
Racc_token_to_s_table = [
|
||||
"$end",
|
||||
"error",
|
||||
"SLASH",
|
||||
"LITERAL",
|
||||
"SYMBOL",
|
||||
"LPAREN",
|
||||
"RPAREN",
|
||||
"DOT",
|
||||
"STAR",
|
||||
"OR",
|
||||
"$start",
|
||||
"expressions",
|
||||
"expression",
|
||||
"or",
|
||||
"terminal",
|
||||
"group",
|
||||
"star",
|
||||
"symbol",
|
||||
"literal",
|
||||
"slash",
|
||||
"dot" ]
|
||||
|
||||
Racc_debug_parser = false
|
||||
Racc_debug_parser = false
|
||||
|
||||
##### State transition tables end #####
|
||||
##### State transition tables end #####
|
||||
|
||||
# reduce 0 omitted
|
||||
# reduce 0 omitted
|
||||
|
||||
def _reduce_1(val, _values)
|
||||
Cat.new(val.first, val.last)
|
||||
end
|
||||
def _reduce_1(val, _values)
|
||||
Cat.new(val.first, val.last)
|
||||
end
|
||||
|
||||
def _reduce_2(val, _values)
|
||||
val.first
|
||||
end
|
||||
def _reduce_2(val, _values)
|
||||
val.first
|
||||
end
|
||||
|
||||
# reduce 3 omitted
|
||||
# reduce 3 omitted
|
||||
|
||||
# reduce 4 omitted
|
||||
# reduce 4 omitted
|
||||
|
||||
# reduce 5 omitted
|
||||
# reduce 5 omitted
|
||||
|
||||
# reduce 6 omitted
|
||||
# reduce 6 omitted
|
||||
|
||||
def _reduce_7(val, _values)
|
||||
Group.new(val[1])
|
||||
end
|
||||
def _reduce_7(val, _values)
|
||||
Group.new(val[1])
|
||||
end
|
||||
|
||||
def _reduce_8(val, _values)
|
||||
Or.new([val.first, val.last])
|
||||
end
|
||||
def _reduce_8(val, _values)
|
||||
Or.new([val.first, val.last])
|
||||
end
|
||||
|
||||
def _reduce_9(val, _values)
|
||||
Or.new([val.first, val.last])
|
||||
end
|
||||
def _reduce_9(val, _values)
|
||||
Or.new([val.first, val.last])
|
||||
end
|
||||
|
||||
def _reduce_10(val, _values)
|
||||
Star.new(Symbol.new(val.last))
|
||||
end
|
||||
def _reduce_10(val, _values)
|
||||
Star.new(Symbol.new(val.last))
|
||||
end
|
||||
|
||||
# reduce 11 omitted
|
||||
# reduce 11 omitted
|
||||
|
||||
# reduce 12 omitted
|
||||
# reduce 12 omitted
|
||||
|
||||
# reduce 13 omitted
|
||||
# reduce 13 omitted
|
||||
|
||||
# reduce 14 omitted
|
||||
# reduce 14 omitted
|
||||
|
||||
def _reduce_15(val, _values)
|
||||
Slash.new("/")
|
||||
end
|
||||
def _reduce_15(val, _values)
|
||||
Slash.new(val.first)
|
||||
end
|
||||
|
||||
def _reduce_16(val, _values)
|
||||
Symbol.new(val.first)
|
||||
end
|
||||
def _reduce_16(val, _values)
|
||||
Symbol.new(val.first)
|
||||
end
|
||||
|
||||
def _reduce_17(val, _values)
|
||||
Literal.new(val.first)
|
||||
end
|
||||
def _reduce_17(val, _values)
|
||||
Literal.new(val.first)
|
||||
end
|
||||
|
||||
def _reduce_18(val, _values)
|
||||
Dot.new(val.first)
|
||||
end
|
||||
def _reduce_18(val, _values)
|
||||
Dot.new(val.first)
|
||||
end
|
||||
|
||||
def _reduce_none(val, _values)
|
||||
val[0]
|
||||
end
|
||||
|
||||
def _reduce_none(val, _values)
|
||||
val[0]
|
||||
end
|
||||
end # class Parser
|
||||
end # module Journey
|
||||
# :startdoc:
|
||||
end # module ActionDispatch
|
||||
end # module Journey
|
||||
end # module ActionDispatch
|
||||
|
@ -30,7 +30,7 @@ rule
|
||||
| dot
|
||||
;
|
||||
slash
|
||||
: SLASH { Slash.new('/') }
|
||||
: SLASH { Slash.new(val.first) }
|
||||
;
|
||||
symbol
|
||||
: SYMBOL { Symbol.new(val.first) }
|
||||
@ -45,5 +45,6 @@ rule
|
||||
end
|
||||
|
||||
---- header
|
||||
# :stopdoc:
|
||||
|
||||
require 'action_dispatch/journey/parser_extras'
|
||||
require "action_dispatch/journey/parser_extras"
|
||||
|
@ -96,13 +96,18 @@ def required_keys
|
||||
required_parts + required_defaults.keys
|
||||
end
|
||||
|
||||
def score(constraints)
|
||||
def score(supplied_keys)
|
||||
required_keys = path.required_names
|
||||
supplied_keys = constraints.map { |k, v| v && k.to_s }.compact
|
||||
|
||||
return -1 unless (required_keys - supplied_keys).empty?
|
||||
required_keys.each do |k|
|
||||
return -1 unless supplied_keys.include?(k)
|
||||
end
|
||||
|
||||
score = 0
|
||||
path.names.each do |k|
|
||||
score += 1 if supplied_keys.include?(k)
|
||||
end
|
||||
|
||||
score = (supplied_keys & path.names).length
|
||||
score + (required_defaults.length * 2)
|
||||
end
|
||||
|
||||
|
@ -58,12 +58,12 @@ def unescape_uri(uri)
|
||||
uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack("C") }.force_encoding(encoding)
|
||||
end
|
||||
|
||||
protected
|
||||
def escape(component, pattern)
|
||||
private
|
||||
def escape(component, pattern) # :doc:
|
||||
component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
|
||||
end
|
||||
|
||||
def percent_encode(unsafe)
|
||||
def percent_encode(unsafe) # :doc:
|
||||
safe = EMPTY.dup
|
||||
unsafe.each_byte { |b| safe << DEC2HEX[b] }
|
||||
safe
|
||||
|
@ -1,3 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
require "strscan"
|
||||
|
||||
module ActionDispatch
|
||||
@ -35,22 +36,23 @@ def next_token
|
||||
def scan
|
||||
case
|
||||
# /
|
||||
when text = @ss.scan(/\//)
|
||||
[:SLASH, text]
|
||||
when @ss.skip(/\//)
|
||||
[:SLASH, "/"]
|
||||
when @ss.skip(/\(/)
|
||||
[:LPAREN, "("]
|
||||
when @ss.skip(/\)/)
|
||||
[:RPAREN, ")"]
|
||||
when @ss.skip(/\|/)
|
||||
[:OR, "|"]
|
||||
when @ss.skip(/\./)
|
||||
[:DOT, "."]
|
||||
when text = @ss.scan(/:\w+/)
|
||||
[:SYMBOL, text]
|
||||
when text = @ss.scan(/\*\w+/)
|
||||
[:STAR, text]
|
||||
when text = @ss.scan(/(?<!\\)\(/)
|
||||
[:LPAREN, text]
|
||||
when text = @ss.scan(/(?<!\\)\)/)
|
||||
[:RPAREN, text]
|
||||
when text = @ss.scan(/\|/)
|
||||
[:OR, text]
|
||||
when text = @ss.scan(/\./)
|
||||
[:DOT, text]
|
||||
when text = @ss.scan(/(?<!\\):\w+/)
|
||||
[:SYMBOL, text]
|
||||
when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\:|\\\(|\\\))+/)
|
||||
[:LITERAL, text.tr('\\', "")]
|
||||
when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
|
||||
text.tr! "\\", ""
|
||||
[:LITERAL, text]
|
||||
# any char
|
||||
when text = @ss.scan(/./)
|
||||
[:LITERAL, text]
|
||||
|
@ -281,7 +281,8 @@ def now_is_loaded?
|
||||
@now
|
||||
end
|
||||
|
||||
def stringify_array(array)
|
||||
private
|
||||
def stringify_array(array) # :doc:
|
||||
array.map do |item|
|
||||
item.kind_of?(Symbol) ? item.to_s : item
|
||||
end
|
||||
|
@ -153,9 +153,9 @@ def to_s
|
||||
@ip ||= calculate_ip
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def ips_from(header)
|
||||
def ips_from(header) # :doc:
|
||||
return [] unless header
|
||||
# Split the comma-separated list into an array of strings
|
||||
ips = header.strip.split(/[,\s]+/)
|
||||
@ -171,7 +171,7 @@ def ips_from(header)
|
||||
end
|
||||
end
|
||||
|
||||
def filter_proxies(ips)
|
||||
def filter_proxies(ips) # :doc:
|
||||
ips.reject do |ip|
|
||||
@proxies.any? { |proxy| proxy === ip }
|
||||
end
|
||||
|
@ -27,17 +27,16 @@ def generate_sid
|
||||
sid
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def initialize_sid
|
||||
def initialize_sid # :doc:
|
||||
@default_options.delete(:sidbits)
|
||||
@default_options.delete(:secure_random)
|
||||
end
|
||||
|
||||
private
|
||||
def make_request(env)
|
||||
ActionDispatch::Request.new env
|
||||
end
|
||||
def make_request(env)
|
||||
ActionDispatch::Request.new env
|
||||
end
|
||||
end
|
||||
|
||||
module StaleSessionCheck
|
||||
|
@ -4,6 +4,17 @@ class Utils # :nodoc:
|
||||
mattr_accessor :perform_deep_munge
|
||||
self.perform_deep_munge = true
|
||||
|
||||
def self.each_param_value(params, &block)
|
||||
case params
|
||||
when Array
|
||||
params.each { |element| each_param_value(element, &block) }
|
||||
when Hash
|
||||
params.each_value { |value| each_param_value(value, &block) }
|
||||
when String
|
||||
block.call params
|
||||
end
|
||||
end
|
||||
|
||||
def self.normalize_encode_params(params)
|
||||
if perform_deep_munge
|
||||
NoNilParamEncoder.normalize_encode_params params
|
||||
|
@ -1,4 +1,4 @@
|
||||
require 'active_support/core_ext/string/filters'
|
||||
require "active_support/core_ext/string/filters"
|
||||
|
||||
module ActionDispatch
|
||||
# The routing module provides URL rewriting in native Ruby. It's a way to
|
||||
|
@ -996,65 +996,65 @@ def defaults(defaults = {})
|
||||
end
|
||||
|
||||
private
|
||||
def merge_path_scope(parent, child) #:nodoc:
|
||||
def merge_path_scope(parent, child)
|
||||
Mapper.normalize_path("#{parent}/#{child}")
|
||||
end
|
||||
|
||||
def merge_shallow_path_scope(parent, child) #:nodoc:
|
||||
def merge_shallow_path_scope(parent, child)
|
||||
Mapper.normalize_path("#{parent}/#{child}")
|
||||
end
|
||||
|
||||
def merge_as_scope(parent, child) #:nodoc:
|
||||
def merge_as_scope(parent, child)
|
||||
parent ? "#{parent}_#{child}" : child
|
||||
end
|
||||
|
||||
def merge_shallow_prefix_scope(parent, child) #:nodoc:
|
||||
def merge_shallow_prefix_scope(parent, child)
|
||||
parent ? "#{parent}_#{child}" : child
|
||||
end
|
||||
|
||||
def merge_module_scope(parent, child) #:nodoc:
|
||||
def merge_module_scope(parent, child)
|
||||
parent ? "#{parent}/#{child}" : child
|
||||
end
|
||||
|
||||
def merge_controller_scope(parent, child) #:nodoc:
|
||||
def merge_controller_scope(parent, child)
|
||||
child
|
||||
end
|
||||
|
||||
def merge_action_scope(parent, child) #:nodoc:
|
||||
def merge_action_scope(parent, child)
|
||||
child
|
||||
end
|
||||
|
||||
def merge_via_scope(parent, child) #:nodoc:
|
||||
def merge_via_scope(parent, child)
|
||||
child
|
||||
end
|
||||
|
||||
def merge_format_scope(parent, child) #:nodoc:
|
||||
def merge_format_scope(parent, child)
|
||||
child
|
||||
end
|
||||
|
||||
def merge_path_names_scope(parent, child) #:nodoc:
|
||||
def merge_path_names_scope(parent, child)
|
||||
merge_options_scope(parent, child)
|
||||
end
|
||||
|
||||
def merge_constraints_scope(parent, child) #:nodoc:
|
||||
def merge_constraints_scope(parent, child)
|
||||
merge_options_scope(parent, child)
|
||||
end
|
||||
|
||||
def merge_defaults_scope(parent, child) #:nodoc:
|
||||
def merge_defaults_scope(parent, child)
|
||||
merge_options_scope(parent, child)
|
||||
end
|
||||
|
||||
def merge_blocks_scope(parent, child) #:nodoc:
|
||||
def merge_blocks_scope(parent, child)
|
||||
merged = parent ? parent.dup : []
|
||||
merged << child if child
|
||||
merged
|
||||
end
|
||||
|
||||
def merge_options_scope(parent, child) #:nodoc:
|
||||
def merge_options_scope(parent, child)
|
||||
(parent || {}).merge(child)
|
||||
end
|
||||
|
||||
def merge_shallow_scope(parent, child) #:nodoc:
|
||||
def merge_shallow_scope(parent, child)
|
||||
child ? true : false
|
||||
end
|
||||
|
||||
@ -1619,13 +1619,13 @@ def root(path, options = {})
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def parent_resource #:nodoc:
|
||||
def parent_resource
|
||||
@scope[:scope_level_resource]
|
||||
end
|
||||
|
||||
def apply_common_behavior_for(method, resources, options, &block) #:nodoc:
|
||||
def apply_common_behavior_for(method, resources, options, &block)
|
||||
if resources.length > 1
|
||||
resources.each { |r| send(method, r, options, &block) }
|
||||
return true
|
||||
@ -1658,39 +1658,39 @@ def apply_common_behavior_for(method, resources, options, &block) #:nodoc:
|
||||
false
|
||||
end
|
||||
|
||||
def apply_action_options(options) # :nodoc:
|
||||
def apply_action_options(options)
|
||||
return options if action_options? options
|
||||
options.merge scope_action_options
|
||||
end
|
||||
|
||||
def action_options?(options) #:nodoc:
|
||||
def action_options?(options)
|
||||
options[:only] || options[:except]
|
||||
end
|
||||
|
||||
def scope_action_options #:nodoc:
|
||||
def scope_action_options
|
||||
@scope[:action_options] || {}
|
||||
end
|
||||
|
||||
def resource_scope? #:nodoc:
|
||||
def resource_scope?
|
||||
@scope.resource_scope?
|
||||
end
|
||||
|
||||
def resource_method_scope? #:nodoc:
|
||||
def resource_method_scope?
|
||||
@scope.resource_method_scope?
|
||||
end
|
||||
|
||||
def nested_scope? #:nodoc:
|
||||
def nested_scope?
|
||||
@scope.nested?
|
||||
end
|
||||
|
||||
def with_scope_level(kind)
|
||||
def with_scope_level(kind) # :doc:
|
||||
@scope = @scope.new_level(kind)
|
||||
yield
|
||||
ensure
|
||||
@scope = @scope.parent
|
||||
end
|
||||
|
||||
def resource_scope(resource) #:nodoc:
|
||||
def resource_scope(resource)
|
||||
@scope = @scope.new(scope_level_resource: resource)
|
||||
|
||||
controller(resource.resource_scope) { yield }
|
||||
@ -1698,7 +1698,7 @@ def resource_scope(resource) #:nodoc:
|
||||
@scope = @scope.parent
|
||||
end
|
||||
|
||||
def nested_options #:nodoc:
|
||||
def nested_options
|
||||
options = { as: parent_resource.member_name }
|
||||
options[:constraints] = {
|
||||
parent_resource.nested_param => param_constraint
|
||||
@ -1707,25 +1707,25 @@ def nested_options #:nodoc:
|
||||
options
|
||||
end
|
||||
|
||||
def shallow_nesting_depth #:nodoc:
|
||||
def shallow_nesting_depth
|
||||
@scope.find_all { |node|
|
||||
node.frame[:scope_level_resource]
|
||||
}.count { |node| node.frame[:scope_level_resource].shallow? }
|
||||
end
|
||||
|
||||
def param_constraint? #:nodoc:
|
||||
def param_constraint?
|
||||
@scope[:constraints] && @scope[:constraints][parent_resource.param].is_a?(Regexp)
|
||||
end
|
||||
|
||||
def param_constraint #:nodoc:
|
||||
def param_constraint
|
||||
@scope[:constraints][parent_resource.param]
|
||||
end
|
||||
|
||||
def canonical_action?(action) #:nodoc:
|
||||
def canonical_action?(action)
|
||||
resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s)
|
||||
end
|
||||
|
||||
def shallow_scope #:nodoc:
|
||||
def shallow_scope
|
||||
scope = { as: @scope[:shallow_prefix],
|
||||
path: @scope[:shallow_path] }
|
||||
@scope = @scope.new scope
|
||||
@ -1735,7 +1735,7 @@ def shallow_scope #:nodoc:
|
||||
@scope = @scope.parent
|
||||
end
|
||||
|
||||
def path_for_action(action, path) #:nodoc:
|
||||
def path_for_action(action, path)
|
||||
return "#{@scope[:path]}/#{path}" if path
|
||||
|
||||
if canonical_action?(action)
|
||||
@ -1745,11 +1745,11 @@ def path_for_action(action, path) #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def action_path(name) #:nodoc:
|
||||
def action_path(name)
|
||||
@scope[:path_names][name.to_sym] || name
|
||||
end
|
||||
|
||||
def prefix_name_for_action(as, action) #:nodoc:
|
||||
def prefix_name_for_action(as, action)
|
||||
if as
|
||||
prefix = as
|
||||
elsif !canonical_action?(action)
|
||||
@ -1761,7 +1761,7 @@ def prefix_name_for_action(as, action) #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def name_for_action(as, action) #:nodoc:
|
||||
def name_for_action(as, action)
|
||||
prefix = prefix_name_for_action(as, action)
|
||||
name_prefix = @scope[:as]
|
||||
|
||||
@ -1787,7 +1787,7 @@ def name_for_action(as, action) #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def set_member_mappings_for_resource
|
||||
def set_member_mappings_for_resource # :doc:
|
||||
member do
|
||||
get :edit if parent_resource.actions.include?(:edit)
|
||||
get :show if parent_resource.actions.include?(:show)
|
||||
@ -1799,12 +1799,10 @@ def set_member_mappings_for_resource
|
||||
end
|
||||
end
|
||||
|
||||
def api_only?
|
||||
def api_only? # :doc:
|
||||
@set.api_only?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def path_scope(path)
|
||||
@scope = @scope.new(path: merge_path_scope(@scope[:path], path))
|
||||
yield
|
||||
@ -1868,7 +1866,7 @@ def using_match_shorthand?(path)
|
||||
path =~ %r{^/?[-\w]+/[-\w/]+$}
|
||||
end
|
||||
|
||||
def decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) # :nodoc:
|
||||
def decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints)
|
||||
if on = options.delete(:on)
|
||||
send(on) { decomposed_match(path, controller, options, _path, to, via, formatted, anchor, options_constraints) }
|
||||
else
|
||||
@ -1883,7 +1881,7 @@ def decomposed_match(path, controller, options, _path, to, via, formatted, ancho
|
||||
end
|
||||
end
|
||||
|
||||
def add_route(action, controller, options, _path, to, via, formatted, anchor, options_constraints) # :nodoc:
|
||||
def add_route(action, controller, options, _path, to, via, formatted, anchor, options_constraints)
|
||||
path = path_for_action(action, _path)
|
||||
raise ArgumentError, "path is required" if path.blank?
|
||||
|
||||
|
@ -198,14 +198,16 @@ def optimize_routes_generation?
|
||||
_routes.optimize_routes_generation? && default_url_options.empty?
|
||||
end
|
||||
|
||||
def _with_routes(routes)
|
||||
private
|
||||
|
||||
def _with_routes(routes) # :doc:
|
||||
old_routes, @_routes = @_routes, routes
|
||||
yield
|
||||
ensure
|
||||
@_routes = old_routes
|
||||
end
|
||||
|
||||
def _routes_context
|
||||
def _routes_context # :doc:
|
||||
self
|
||||
end
|
||||
end
|
||||
|
@ -69,7 +69,7 @@ class Session
|
||||
DEFAULT_HOST = "www.example.com"
|
||||
|
||||
include Minitest::Assertions
|
||||
include RequestHelpers, Assertions
|
||||
include TestProcess, RequestHelpers, Assertions
|
||||
|
||||
%w( status status_message headers body redirect? ).each do |method|
|
||||
delegate method, to: :response, allow_nil: true
|
||||
@ -598,7 +598,7 @@ def method_missing(sym, *args, &block)
|
||||
# Consult the Rails Testing Guide for more.
|
||||
|
||||
class IntegrationTest < ActiveSupport::TestCase
|
||||
include TestProcess
|
||||
include TestProcess::FixtureFile
|
||||
|
||||
module UrlOptions
|
||||
extend ActiveSupport::Concern
|
||||
|
@ -3,6 +3,26 @@
|
||||
|
||||
module ActionDispatch
|
||||
module TestProcess
|
||||
module FixtureFile
|
||||
# Shortcut for <tt>Rack::Test::UploadedFile.new(File.join(ActionDispatch::IntegrationTest.fixture_path, path), type)</tt>:
|
||||
#
|
||||
# post :change_avatar, avatar: fixture_file_upload('files/spongebob.png', 'image/png')
|
||||
#
|
||||
# To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
|
||||
# This will not affect other platforms:
|
||||
#
|
||||
# post :change_avatar, avatar: fixture_file_upload('files/spongebob.png', 'image/png', :binary)
|
||||
def fixture_file_upload(path, mime_type = nil, binary = false)
|
||||
if self.class.respond_to?(:fixture_path) && self.class.fixture_path &&
|
||||
!File.exist?(path)
|
||||
path = File.join(self.class.fixture_path, path)
|
||||
end
|
||||
Rack::Test::UploadedFile.new(path, mime_type, binary)
|
||||
end
|
||||
end
|
||||
|
||||
include FixtureFile
|
||||
|
||||
def assigns(key = nil)
|
||||
raise NoMethodError,
|
||||
"assigns has been extracted to a gem. To continue using it,
|
||||
@ -24,21 +44,5 @@ def cookies
|
||||
def redirect_to_url
|
||||
@response.redirect_url
|
||||
end
|
||||
|
||||
# Shortcut for <tt>Rack::Test::UploadedFile.new(File.join(ActionDispatch::IntegrationTest.fixture_path, path), type)</tt>:
|
||||
#
|
||||
# post :change_avatar, avatar: fixture_file_upload('files/spongebob.png', 'image/png')
|
||||
#
|
||||
# To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
|
||||
# This will not affect other platforms:
|
||||
#
|
||||
# post :change_avatar, avatar: fixture_file_upload('files/spongebob.png', 'image/png', :binary)
|
||||
def fixture_file_upload(path, mime_type = nil, binary = false)
|
||||
if self.class.respond_to?(:fixture_path) && self.class.fixture_path &&
|
||||
!File.exist?(path)
|
||||
path = File.join(self.class.fixture_path, path)
|
||||
end
|
||||
Rack::Test::UploadedFile.new(path, mime_type, binary)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -55,7 +55,7 @@ class TestMultipleFiltersController < ActionController::Base
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
(1..3).each do |i|
|
||||
define_method "try_#{i}" do
|
||||
instance_variable_set :@try, i
|
||||
@ -296,7 +296,7 @@ def change_password
|
||||
render inline: "ran action"
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def find_user
|
||||
@ran_filter ||= []
|
||||
@ran_filter << "find_user"
|
||||
@ -428,7 +428,7 @@ def bar
|
||||
render plain: "bar"
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def first
|
||||
@first = true
|
||||
end
|
||||
@ -1040,7 +1040,7 @@ def test_last_action_in_multiple_before_action_chain_halts
|
||||
assert_equal 3, controller.instance_variable_get(:@try)
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def test_process(controller, action = "show")
|
||||
@controller = controller.is_a?(Class) ? controller.new : controller
|
||||
process(action)
|
||||
|
@ -63,10 +63,10 @@ def test_to_session_value
|
||||
assert_equal({ "flashes" => { "foo" => "bar" }, "discard" => [] }, @hash.to_session_value)
|
||||
|
||||
@hash.discard("foo")
|
||||
assert_equal(nil, @hash.to_session_value)
|
||||
assert_nil(@hash.to_session_value)
|
||||
|
||||
@hash.sweep
|
||||
assert_equal(nil, @hash.to_session_value)
|
||||
assert_nil(@hash.to_session_value)
|
||||
end
|
||||
|
||||
def test_from_session_value
|
||||
@ -75,7 +75,7 @@ def test_from_session_value
|
||||
session = Marshal.load(Base64.decode64(rails_3_2_cookie))
|
||||
hash = Flash::FlashHash.from_session_value(session["flash"])
|
||||
assert_equal({ "greeting" => "Hello" }, hash.to_hash)
|
||||
assert_equal(nil, hash.to_session_value)
|
||||
assert_nil(hash.to_session_value)
|
||||
end
|
||||
|
||||
def test_from_session_value_on_json_serializer
|
||||
@ -84,7 +84,7 @@ def test_from_session_value_on_json_serializer
|
||||
hash = Flash::FlashHash.from_session_value(session["flash"])
|
||||
|
||||
assert_equal({ "greeting" => "Hello" }, hash.to_hash)
|
||||
assert_equal(nil, hash.to_session_value)
|
||||
assert_nil(hash.to_session_value)
|
||||
assert_equal "Hello", hash[:greeting]
|
||||
assert_equal "Hello", hash["greeting"]
|
||||
end
|
||||
|
@ -166,8 +166,7 @@ def authenticate_long_credentials
|
||||
|
||||
test "token_and_options returns nil with no value after the equal sign" do
|
||||
actual = ActionController::HttpAuthentication::Token.token_and_options(malformed_request).first
|
||||
expected = nil
|
||||
assert_equal(expected, actual)
|
||||
assert_nil actual
|
||||
end
|
||||
|
||||
test "raw_params returns a tuple of two key value pair strings" do
|
||||
|
@ -289,7 +289,7 @@ def test_post
|
||||
assert_response :success
|
||||
assert_equal "bar", body
|
||||
|
||||
assert_equal nil, headers["Set-Cookie"]
|
||||
assert_nil headers["Set-Cookie"]
|
||||
assert_equal({ "foo" => "bar" }, cookies.to_hash)
|
||||
end
|
||||
end
|
||||
@ -308,7 +308,7 @@ def test_post
|
||||
assert_response :success
|
||||
assert_equal "bar", body
|
||||
|
||||
assert_equal nil, headers["Set-Cookie"]
|
||||
assert_nil headers["Set-Cookie"]
|
||||
assert_equal({ "foo" => "bar" }, cookies.to_hash)
|
||||
end
|
||||
end
|
||||
|
@ -40,7 +40,7 @@ def index
|
||||
respond_to(:html, :iphone, :js)
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def with_iphone
|
||||
request.format = "iphone" if request.env["HTTP_ACCEPT"] == "text/iphone"
|
||||
|
@ -273,7 +273,7 @@ def format_any_variant_any
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def set_layout
|
||||
case action_name
|
||||
when "all_types_with_layout", "iphone_with_html_response_type"
|
||||
|
@ -52,7 +52,7 @@ class BareEmptyTest < ActiveSupport::TestCase
|
||||
controller.set_request!(ActionDispatch::Request.empty)
|
||||
controller.set_response!(BareController.make_response!(controller.request))
|
||||
controller.index
|
||||
assert_equal nil, controller.response_body
|
||||
assert_nil controller.response_body
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -25,7 +25,7 @@ def show_actions
|
||||
render body: "actions: #{action_methods.to_a.sort.join(', ')}"
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def authenticate
|
||||
end
|
||||
end
|
||||
|
@ -26,16 +26,14 @@ def with_layout
|
||||
render action: "hello_world", layout: "basic"
|
||||
end
|
||||
|
||||
protected
|
||||
protected def __controller_method__
|
||||
"controller context!"
|
||||
end
|
||||
|
||||
# 3) Set view_context to self
|
||||
def view_context
|
||||
self
|
||||
end
|
||||
|
||||
def __controller_method__
|
||||
"controller context!"
|
||||
end
|
||||
# 3) Set view_context to self
|
||||
private def view_context
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
class RenderContextTest < Rack::TestCase
|
||||
|
@ -101,12 +101,12 @@ class StreamingTest < Rack::TestCase
|
||||
assert_body "Hello world, I'm here!"
|
||||
assert_status 200
|
||||
assert_equal "22", headers["Content-Length"]
|
||||
assert_equal nil, headers["Transfer-Encoding"]
|
||||
assert_nil headers["Transfer-Encoding"]
|
||||
end
|
||||
|
||||
def assert_streaming!(cache = "no-cache")
|
||||
assert_status 200
|
||||
assert_equal nil, headers["Content-Length"]
|
||||
assert_nil headers["Content-Length"]
|
||||
assert_equal "chunked", headers["Transfer-Encoding"]
|
||||
assert_equal cache, headers["Cache-Control"]
|
||||
end
|
||||
|
@ -1,9 +1,8 @@
|
||||
require "abstract_unit"
|
||||
|
||||
class ParameterEncodingController < ActionController::Base
|
||||
parameter_encoding :test_bar, :bar, Encoding::ASCII_8BIT
|
||||
parameter_encoding :test_baz, :baz, Encoding::ISO_8859_1
|
||||
parameter_encoding :test_baz_to_ascii, :baz, Encoding::ASCII_8BIT
|
||||
skip_parameter_encoding :test_bar
|
||||
skip_parameter_encoding :test_all_values_encoding
|
||||
|
||||
def test_foo
|
||||
render body: params[:foo].encoding
|
||||
@ -13,16 +12,8 @@ def test_bar
|
||||
render body: params[:bar].encoding
|
||||
end
|
||||
|
||||
def test_baz
|
||||
render body: params[:baz].encoding
|
||||
end
|
||||
|
||||
def test_no_change_to_baz
|
||||
render body: params[:baz].encoding
|
||||
end
|
||||
|
||||
def test_baz_to_ascii
|
||||
render body: params[:baz].encoding
|
||||
def test_all_values_encoding
|
||||
render body: ::JSON.dump(params.values.map(&:encoding).map(&:name))
|
||||
end
|
||||
end
|
||||
|
||||
@ -36,32 +27,18 @@ class ParameterEncodingTest < ActionController::TestCase
|
||||
assert_equal "UTF-8", @response.body
|
||||
end
|
||||
|
||||
test "properly transcodes ASCII_8BIT parameters into declared encodings" do
|
||||
test "properly encodes ASCII_8BIT parameters into binary" do
|
||||
post :test_bar, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
|
||||
|
||||
assert_response :success
|
||||
assert_equal "ASCII-8BIT", @response.body
|
||||
end
|
||||
|
||||
test "properly transcodes ISO_8859_1 parameters into declared encodings" do
|
||||
post :test_baz, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
|
||||
test "properly encodes all ASCII_8BIT parameters into binary" do
|
||||
post :test_all_values_encoding, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
|
||||
|
||||
assert_response :success
|
||||
assert_equal "ISO-8859-1", @response.body
|
||||
end
|
||||
|
||||
test "does not transcode parameters when not specified" do
|
||||
post :test_no_change_to_baz, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
|
||||
|
||||
assert_response :success
|
||||
assert_equal "UTF-8", @response.body
|
||||
end
|
||||
|
||||
test "respects different encoding declarations for a param per action" do
|
||||
post :test_baz_to_ascii, params: { "foo" => "foo", "bar" => "bar", "baz" => "baz" }
|
||||
|
||||
assert_response :success
|
||||
assert_equal "ASCII-8BIT", @response.body
|
||||
assert_equal ["ASCII-8BIT"], JSON.parse(@response.body).uniq
|
||||
end
|
||||
|
||||
test "does not raise an error when passed a param declared as ASCII-8BIT that contains invalid bytes" do
|
||||
|
@ -141,7 +141,7 @@ def walk_permitted(params)
|
||||
permitted = params.permit(:a, c: [], b: [])
|
||||
assert_equal 1, permitted[:a]
|
||||
assert_equal [1, 2, 3], permitted[:b]
|
||||
assert_equal nil, permitted[:c]
|
||||
assert_nil permitted[:c]
|
||||
end
|
||||
|
||||
test "key to empty array: arrays of permitted scalars pass" do
|
||||
@ -216,7 +216,7 @@ def walk_permitted(params)
|
||||
test "fetch with a default value of a hash does not mutate the object" do
|
||||
params = ActionController::Parameters.new({})
|
||||
params.fetch :foo, {}
|
||||
assert_equal nil, params[:foo]
|
||||
assert_nil params[:foo]
|
||||
end
|
||||
|
||||
test "hashes in array values get wrapped" do
|
||||
@ -254,8 +254,8 @@ def walk_permitted(params)
|
||||
end
|
||||
|
||||
test "fetch doesnt raise ParameterMissing exception if there is a default that is nil" do
|
||||
assert_equal nil, @params.fetch(:foo, nil)
|
||||
assert_equal nil, @params.fetch(:foo) { nil }
|
||||
assert_nil @params.fetch(:foo, nil)
|
||||
assert_nil @params.fetch(:foo) { nil }
|
||||
end
|
||||
|
||||
test "KeyError in fetch block should not be covered up" do
|
||||
|
@ -50,7 +50,7 @@ def test_filtered_parameters
|
||||
with_default_wrapper_options do
|
||||
@request.env["CONTENT_TYPE"] = "application/json"
|
||||
post :parse, params: { "username" => "sikachu" }
|
||||
assert_equal @request.filtered_parameters, "controller" => "params_wrapper_test/users", "action" => "parse", "username" => "sikachu", "user" => { "username" => "sikachu" }
|
||||
assert_equal({ "controller" => "params_wrapper_test/users", "action" => "parse", "username" => "sikachu", "user" => { "username" => "sikachu" } }, @request.filtered_parameters)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -123,7 +123,7 @@ def redirect_with_null_bytes
|
||||
|
||||
def rescue_errors(e) raise e end
|
||||
|
||||
protected
|
||||
private
|
||||
def dashbord_url(id, message)
|
||||
url_for action: "dashboard", params: { "id" => id, "message" => message }
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ def test_test_request_has_session_options_initialized
|
||||
|
||||
def test_mutating_session_options_does_not_affect_default_options
|
||||
@request.session_options[:myparam] = 123
|
||||
assert_equal nil, ActionController::TestSession::DEFAULT_OPTIONS[:myparam]
|
||||
assert_nil ActionController::TestSession::DEFAULT_OPTIONS[:myparam]
|
||||
end
|
||||
|
||||
def test_content_length_has_bytes_count_value
|
||||
@ -17,8 +17,8 @@ def test_content_length_has_bytes_count_value
|
||||
@request.set_header "CONTENT_TYPE", "application/json"
|
||||
@request.assign_parameters(@routes, "test", "create", non_ascii_parameters,
|
||||
"/test", [:data, :controller, :action])
|
||||
assert_equal(@request.get_header("CONTENT_LENGTH"),
|
||||
StringIO.new(non_ascii_parameters.to_json).length.to_s)
|
||||
assert_equal(StringIO.new(non_ascii_parameters.to_json).length.to_s,
|
||||
@request.get_header("CONTENT_LENGTH"))
|
||||
end
|
||||
|
||||
ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option|
|
||||
|
@ -92,7 +92,7 @@ def index
|
||||
render inline: "OK"
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
|
||||
def add_called_callback(name)
|
||||
@called_callbacks ||= []
|
||||
|
@ -149,7 +149,7 @@ def exception_with_no_handler_for_wrapper
|
||||
raise RangeError
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def deny_access
|
||||
head :forbidden
|
||||
end
|
||||
@ -327,7 +327,7 @@ def b00m
|
||||
raise "b00m"
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def show_errors(exception)
|
||||
render plain: exception.message
|
||||
end
|
||||
|
@ -1089,7 +1089,7 @@ def test_singleton_resource_name_is_not_singularized
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def with_restful_routing(*args)
|
||||
options = args.extract_options!
|
||||
collection_methods = options.delete(:collection)
|
||||
|
@ -241,10 +241,17 @@ def test_send_file_charset_with_type_options_key
|
||||
assert_equal "text/calendar; charset=utf-8", response.headers["Content-Type"]
|
||||
end
|
||||
|
||||
def test_send_file_charset_with_type_options_key_without_charset
|
||||
@controller = SendFileWithActionControllerLive.new
|
||||
@controller.options = { type: "image/png" }
|
||||
response = process("file")
|
||||
assert_equal "image/png", response.headers["Content-Type"]
|
||||
end
|
||||
|
||||
def test_send_file_charset_with_content_type_options_key
|
||||
@controller = SendFileWithActionControllerLive.new
|
||||
@controller.options = { content_type: "text/calendar" }
|
||||
response = process("file")
|
||||
assert_equal "text/calendar; charset=utf-8", response.headers["Content-Type"]
|
||||
assert_equal "text/calendar", response.headers["Content-Type"]
|
||||
end
|
||||
end
|
||||
|
@ -100,11 +100,11 @@ def test_html_output
|
||||
end
|
||||
|
||||
def test_xml_output
|
||||
response.content_type = "application/xml"
|
||||
response.content_type = params[:response_as]
|
||||
render plain: <<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<area>area is an empty tag in HTML, raising an error if not in xml mode</area>
|
||||
<area><p>area is an empty tag in HTML, so it won't contain this content</p></area>
|
||||
</root>
|
||||
XML
|
||||
end
|
||||
@ -374,18 +374,18 @@ def test_multiple_calls
|
||||
assert_equal "OK", @response.body
|
||||
end
|
||||
|
||||
def test_should_impose_childless_html_tags_in_html
|
||||
process :test_xml_output, params: { response_as: "text/html" }
|
||||
|
||||
# <area> auto-closes, so the <p> becomes a sibling
|
||||
assert_select "root > area + p"
|
||||
end
|
||||
|
||||
def test_should_not_impose_childless_html_tags_in_xml
|
||||
process :test_xml_output
|
||||
process :test_xml_output, params: { response_as: "application/xml" }
|
||||
|
||||
begin
|
||||
$stderr = StringIO.new
|
||||
assert_select "area" #This will cause a warning if content is processed as HTML
|
||||
$stderr.rewind && err = $stderr.read
|
||||
ensure
|
||||
$stderr = STDERR
|
||||
end
|
||||
|
||||
assert err.empty?, err.inspect
|
||||
# <area> is not special, so the <p> is its child
|
||||
assert_select "root > area > p"
|
||||
end
|
||||
|
||||
def test_assert_generates
|
||||
|
@ -487,6 +487,27 @@ def test_url_for_with_array_is_unmodified
|
||||
end
|
||||
end
|
||||
|
||||
def test_default_params_first_empty
|
||||
with_routing do |set|
|
||||
set.draw do
|
||||
get "(:param1)/test(/:param2)" => "index#index",
|
||||
defaults: {
|
||||
param1: 1,
|
||||
param2: 2
|
||||
},
|
||||
constraints: {
|
||||
param1: /\d*/,
|
||||
param2: /\d+/
|
||||
}
|
||||
end
|
||||
|
||||
kls = Class.new { include set.url_helpers }
|
||||
kls.default_url_options[:host] = "www.basecamphq.com"
|
||||
|
||||
assert_equal "http://www.basecamphq.com/test", kls.new.url_for(controller: "index", param1: "1")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def extract_params(url)
|
||||
url.split("?", 2).last.split("&").sort
|
||||
|
@ -272,6 +272,10 @@ def string_key_mock
|
||||
def noop
|
||||
head :ok
|
||||
end
|
||||
|
||||
def encrypted_cookie
|
||||
cookies.encrypted["foo"]
|
||||
end
|
||||
end
|
||||
|
||||
tests TestController
|
||||
@ -940,8 +944,8 @@ def test_legacy_signed_cookie_is_treated_as_nil_by_signed_cookie_jar_if_tampered
|
||||
@request.headers["Cookie"] = "user_id=45"
|
||||
get :get_signed_cookie
|
||||
|
||||
assert_equal nil, @controller.send(:cookies).signed[:user_id]
|
||||
assert_equal nil, @response.cookies["user_id"]
|
||||
assert_nil @controller.send(:cookies).signed[:user_id]
|
||||
assert_nil @response.cookies["user_id"]
|
||||
end
|
||||
|
||||
def test_legacy_signed_cookie_is_treated_as_nil_by_encrypted_cookie_jar_if_tampered
|
||||
@ -951,8 +955,8 @@ def test_legacy_signed_cookie_is_treated_as_nil_by_encrypted_cookie_jar_if_tampe
|
||||
@request.headers["Cookie"] = "foo=baz"
|
||||
get :get_encrypted_cookie
|
||||
|
||||
assert_equal nil, @controller.send(:cookies).encrypted[:foo]
|
||||
assert_equal nil, @response.cookies["foo"]
|
||||
assert_nil @controller.send(:cookies).encrypted[:foo]
|
||||
assert_nil @response.cookies["foo"]
|
||||
end
|
||||
|
||||
def test_cookie_with_all_domain_option
|
||||
@ -1189,6 +1193,12 @@ def test_cookies_precedence_over_request_cookies
|
||||
assert_equal "david", cookies[:user_name]
|
||||
end
|
||||
|
||||
def test_cookies_are_not_cleared
|
||||
cookies.encrypted["foo"] = "bar"
|
||||
get :noop
|
||||
assert_equal "bar", @controller.encrypted_cookie
|
||||
end
|
||||
|
||||
private
|
||||
def assert_cookie_header(expected)
|
||||
header = @response.headers["Set-Cookie"]
|
||||
|
@ -129,7 +129,7 @@ def teardown
|
||||
params = parse_multipart("none")
|
||||
assert_equal %w(submit-name), params.keys.sort
|
||||
assert_equal "Larry", params["submit-name"]
|
||||
assert_equal nil, params["files"]
|
||||
assert_nil params["files"]
|
||||
end
|
||||
|
||||
test "parses empty upload file" do
|
||||
|
@ -18,7 +18,7 @@ def url_for(options = {})
|
||||
ActionDispatch::Http::URL.url_for(options)
|
||||
end
|
||||
|
||||
protected
|
||||
private
|
||||
def stub_request(env = {})
|
||||
ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
|
||||
@trusted_proxies ||= nil
|
||||
@ -94,13 +94,13 @@ class RequestIP < BaseRequestTest
|
||||
assert_equal "3.4.5.6", request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,192.168.0.1"
|
||||
assert_equal nil, request.remote_ip
|
||||
assert_nil request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 172.31.4.4, 10.0.0.1"
|
||||
assert_equal "3.4.5.6", request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address"
|
||||
assert_equal nil, request.remote_ip
|
||||
assert_nil request.remote_ip
|
||||
end
|
||||
|
||||
test "remote ip spoof detection" do
|
||||
@ -154,7 +154,7 @@ class RequestIP < BaseRequestTest
|
||||
assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,::1"
|
||||
assert_equal nil, request.remote_ip
|
||||
assert_nil request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::, fc01::, fdff"
|
||||
assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
|
||||
@ -163,7 +163,7 @@ class RequestIP < BaseRequestTest
|
||||
assert_equal "FE00::", request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address"
|
||||
assert_equal nil, request.remote_ip
|
||||
assert_nil request.remote_ip
|
||||
end
|
||||
|
||||
test "remote ip v6 spoof detection" do
|
||||
@ -200,7 +200,7 @@ class RequestIP < BaseRequestTest
|
||||
assert_equal "3.4.5.6", request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "67.205.106.73,unknown"
|
||||
assert_equal nil, request.remote_ip
|
||||
assert_nil request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73"
|
||||
assert_equal "3.4.5.6", request.remote_ip
|
||||
@ -222,7 +222,7 @@ class RequestIP < BaseRequestTest
|
||||
assert_equal "::1", request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
|
||||
assert_equal nil, request.remote_ip
|
||||
assert_nil request.remote_ip
|
||||
|
||||
request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334"
|
||||
assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
|
||||
@ -345,7 +345,7 @@ class RequestPort < BaseRequestTest
|
||||
|
||||
test "optional port" do
|
||||
request = stub_request "HTTP_HOST" => "www.example.org:80"
|
||||
assert_equal nil, request.optional_port
|
||||
assert_nil request.optional_port
|
||||
|
||||
request = stub_request "HTTP_HOST" => "www.example.org:8080"
|
||||
assert_equal 8080, request.optional_port
|
||||
@ -537,7 +537,7 @@ class RequestCGI < BaseRequestTest
|
||||
|
||||
assert_equal "Basic", request.auth_type
|
||||
assert_equal 0, request.content_length
|
||||
assert_equal nil, request.content_mime_type
|
||||
assert_nil request.content_mime_type
|
||||
assert_equal "CGI/1.1", request.gateway_interface
|
||||
assert_equal "*/*", request.accept
|
||||
assert_equal "UTF-8", request.accept_charset
|
||||
@ -957,7 +957,7 @@ class RequestMimeType < BaseRequestTest
|
||||
end
|
||||
|
||||
test "no content type" do
|
||||
assert_equal nil, stub_request.content_mime_type
|
||||
assert_nil stub_request.content_mime_type
|
||||
end
|
||||
|
||||
test "content type is XML" do
|
||||
@ -978,7 +978,7 @@ class RequestMimeType < BaseRequestTest
|
||||
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
|
||||
)
|
||||
|
||||
assert_equal nil, request.negotiate_mime([Mime[:xml], Mime[:json]])
|
||||
assert_nil request.negotiate_mime([Mime[:xml], Mime[:json]])
|
||||
assert_equal Mime[:html], request.negotiate_mime([Mime[:xml], Mime[:html]])
|
||||
assert_equal Mime[:html], request.negotiate_mime([Mime[:xml], Mime::ALL])
|
||||
end
|
||||
@ -1192,7 +1192,7 @@ class RequestEtag < BaseRequestTest
|
||||
test "doesn't match absent If-None-Match" do
|
||||
request = stub_request
|
||||
|
||||
assert_equal nil, request.if_none_match
|
||||
assert_nil request.if_none_match
|
||||
assert_equal [], request.if_none_match_etags
|
||||
|
||||
assert_not request.etag_matches?("foo")
|
||||
|
@ -74,7 +74,7 @@ def test_read_body_during_action
|
||||
@response.body = "Hello, World!"
|
||||
|
||||
# even though there's no explicitly set content-type,
|
||||
assert_equal nil, @response.content_type
|
||||
assert_nil @response.content_type
|
||||
|
||||
# after the action reads back @response.body,
|
||||
assert_equal "Hello, World!", @response.body
|
||||
@ -110,6 +110,11 @@ def test_setting_content_type_header_impacts_content_type_method
|
||||
assert_equal "application/aaron", @response.content_type
|
||||
end
|
||||
|
||||
def test_empty_content_type_returns_nil
|
||||
@response.headers["Content-Type"] = ""
|
||||
assert_nil @response.content_type
|
||||
end
|
||||
|
||||
test "simple output" do
|
||||
@response.body = "Hello, World!"
|
||||
|
||||
|
@ -7,7 +7,7 @@ class IPv6IntegrationTest < ActionDispatch::IntegrationTest
|
||||
class ::BadRouteRequestController < ActionController::Base
|
||||
include Routes.url_helpers
|
||||
def index
|
||||
render text: foo_path
|
||||
render plain: foo_path
|
||||
end
|
||||
|
||||
def foo
|
||||
|
@ -4189,7 +4189,7 @@ def app; APP end
|
||||
|
||||
test "parameters are reset between constraint checks" do
|
||||
get "/bar"
|
||||
assert_equal nil, @request.params[:foo]
|
||||
assert_nil @request.params[:foo]
|
||||
assert_equal "bar", @request.params[:bar]
|
||||
end
|
||||
end
|
||||
|
@ -142,20 +142,20 @@ def test_doesnt_write_session_cookie_if_session_id_is_already_exists
|
||||
|
||||
get "/get_session_value"
|
||||
assert_response :success
|
||||
assert_equal nil, headers["Set-Cookie"], "should not resend the cookie again if session_id cookie is already exists"
|
||||
assert_nil headers["Set-Cookie"], "should not resend the cookie again if session_id cookie is already exists"
|
||||
end
|
||||
end
|
||||
|
||||
def test_prevents_session_fixation
|
||||
with_test_route_set do
|
||||
assert_equal nil, @cache.read("_session_id:0xhax")
|
||||
assert_nil @cache.read("_session_id:0xhax")
|
||||
|
||||
cookies["_session_id"] = "0xhax"
|
||||
get "/set_session_value"
|
||||
|
||||
assert_response :success
|
||||
assert_not_equal "0xhax", cookies["_session_id"]
|
||||
assert_equal nil, @cache.read("_session_id:0xhax")
|
||||
assert_nil @cache.read("_session_id:0xhax")
|
||||
assert_equal({ "foo" => "bar" }, @cache.read("_session_id:#{cookies['_session_id']}"))
|
||||
end
|
||||
end
|
||||
|
@ -108,7 +108,7 @@ def test_does_not_set_secure_cookies_over_http
|
||||
with_test_route_set(secure: true) do
|
||||
get "/set_session_value"
|
||||
assert_response :success
|
||||
assert_equal nil, headers["Set-Cookie"]
|
||||
assert_nil headers["Set-Cookie"]
|
||||
end
|
||||
end
|
||||
|
||||
@ -169,7 +169,7 @@ def test_doesnt_write_session_cookie_if_session_is_not_accessed
|
||||
with_test_route_set do
|
||||
get "/no_session_access"
|
||||
assert_response :success
|
||||
assert_equal nil, headers["Set-Cookie"]
|
||||
assert_nil headers["Set-Cookie"]
|
||||
end
|
||||
end
|
||||
|
||||
@ -179,7 +179,7 @@ def test_doesnt_write_session_cookie_if_session_is_unchanged
|
||||
"fef868465920f415f2c0652d6910d3af288a0367"
|
||||
get "/no_session_access"
|
||||
assert_response :success
|
||||
assert_equal nil, headers["Set-Cookie"]
|
||||
assert_nil headers["Set-Cookie"]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -157,7 +157,7 @@ def test_doesnt_write_session_cookie_if_session_id_is_already_exists
|
||||
|
||||
get "/get_session_value"
|
||||
assert_response :success
|
||||
assert_equal nil, headers["Set-Cookie"], "should not resend the cookie again if session_id cookie is already exists"
|
||||
assert_nil headers["Set-Cookie"], "should not resend the cookie again if session_id cookie is already exists"
|
||||
end
|
||||
rescue Dalli::RingError => ex
|
||||
skip ex.message, ex.backtrace
|
||||
|
@ -177,9 +177,9 @@ def test_serves_gzip_files_with_not_modified
|
||||
last_modified = File.mtime(File.join(@root, "#{file_name}.gz"))
|
||||
response = get(file_name, "HTTP_ACCEPT_ENCODING" => "gzip", "HTTP_IF_MODIFIED_SINCE" => last_modified.httpdate)
|
||||
assert_equal 304, response.status
|
||||
assert_equal nil, response.headers["Content-Type"]
|
||||
assert_equal nil, response.headers["Content-Encoding"]
|
||||
assert_equal nil, response.headers["Vary"]
|
||||
assert_nil response.headers["Content-Type"]
|
||||
assert_nil response.headers["Content-Encoding"]
|
||||
assert_nil response.headers["Vary"]
|
||||
end
|
||||
|
||||
def test_serves_files_with_headers
|
||||
|
@ -30,7 +30,7 @@ class TestRequestTest < ActiveSupport::TestCase
|
||||
req = ActionDispatch::TestRequest.create({})
|
||||
|
||||
assert_equal({}, req.cookies)
|
||||
assert_equal nil, req.env["HTTP_COOKIE"]
|
||||
assert_nil req.env["HTTP_COOKIE"]
|
||||
|
||||
req.cookie_jar["user_name"] = "david"
|
||||
assert_cookies({ "user_name" => "david" }, req.cookie_jar)
|
||||
|
@ -96,7 +96,7 @@ def test_score
|
||||
path = Path::Pattern.from_string "/:controller(/:action(/:id))(.:format)"
|
||||
generic = Route.build "name", nil, path, constraints, [], {}
|
||||
|
||||
knowledge = { id: 20, controller: "pages", action: "show" }
|
||||
knowledge = { "id" => true, "controller" => true, "action" => true }
|
||||
|
||||
routes = [specific, generic]
|
||||
|
||||
|
@ -1,3 +1,17 @@
|
||||
* Return correct object name in form helper method after `fields_for`.
|
||||
|
||||
Fixes #26931.
|
||||
|
||||
*Yuji Yaginuma*
|
||||
|
||||
* Use `ActionView::Resolver.caching?` (`config.action_view.cache_template_loading`)
|
||||
to enable template recompilation.
|
||||
|
||||
Before it was enabled by `consider_all_requests_local`, which caused
|
||||
recompilation in tests.
|
||||
|
||||
*Max Melentiev*
|
||||
|
||||
* Add `form_with` to unify `form_tag` and `form_for` usage.
|
||||
|
||||
Used like `form_tag` (where just the open tag is output):
|
||||
|
@ -4,4 +4,4 @@ Ensure that you can build the project and run tests.
|
||||
Run rake ujs:server first, and then run the web tests by
|
||||
visiting http://localhost:4567 in your browser.
|
||||
|
||||
rake test:server
|
||||
rake ujs:server
|
||||
|
@ -49,7 +49,7 @@ end
|
||||
namespace :ujs do
|
||||
desc "Starts the test server"
|
||||
task :server do
|
||||
system 'bundle exec rackup test/ujs/config.ru -p 4567 -s puma'
|
||||
system "bundle exec rackup test/ujs/config.ru -p 4567 -s puma"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -35,18 +35,37 @@ module AssetTagHelper
|
||||
# When the Asset Pipeline is enabled, you can pass the name of your manifest as
|
||||
# source, and include other JavaScript or CoffeeScript files inside the manifest.
|
||||
#
|
||||
# ==== Options
|
||||
#
|
||||
# When the last parameter is a hash you can add HTML attributes using that
|
||||
# parameter. The following options are supported:
|
||||
#
|
||||
# * <tt>:extname</tt> - Append a extention to the generated url unless the extension
|
||||
# already exists. This only applies for relative urls.
|
||||
# * <tt>:protocol</tt> - Sets the protocol of the generated url, this option only
|
||||
# applies when a relative url and +host+ options are provided.
|
||||
# * <tt>:host</tt> - When a relative url is provided the host is added to the
|
||||
# that path.
|
||||
# * <tt>:skip_pipeline</tt> - This option is used to bypass the asset pipeline
|
||||
# when it is set to true.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# javascript_include_tag "xmlhr"
|
||||
# # => <script src="/assets/xmlhr.js?1284139606"></script>
|
||||
# # => <script src="/assets/xmlhr.debug-1284139606.js"></script>
|
||||
#
|
||||
# javascript_include_tag "xmlhr", host: "localhost", protocol: "https"
|
||||
# # => <script src="https://localhost/assets/xmlhr.debug-1284139606.js"></script>
|
||||
#
|
||||
# javascript_include_tag "template.jst", extname: false
|
||||
# # => <script src="/assets/template.jst?1284139606"></script>
|
||||
# # => <script src="/assets/template.debug-1284139606.jst"></script>
|
||||
#
|
||||
# javascript_include_tag "xmlhr.js"
|
||||
# # => <script src="/assets/xmlhr.js?1284139606"></script>
|
||||
# # => <script src="/assets/xmlhr.debug-1284139606.js"></script>
|
||||
#
|
||||
# javascript_include_tag "common.javascript", "/elsewhere/cools"
|
||||
# # => <script src="/assets/common.javascript?1284139606"></script>
|
||||
# # <script src="/elsewhere/cools.js?1423139606"></script>
|
||||
# # => <script src="/assets/common.javascript.debug-1284139606.js"></script>
|
||||
# # <script src="/elsewhere/cools.debug-1284139606.js"></script>
|
||||
#
|
||||
# javascript_include_tag "http://www.example.com/xmlhr"
|
||||
# # => <script src="http://www.example.com/xmlhr"></script>
|
||||
|
@ -215,7 +215,7 @@ def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
|
||||
|
||||
private
|
||||
|
||||
def fragment_name_with_digest(name, virtual_path) #:nodoc:
|
||||
def fragment_name_with_digest(name, virtual_path)
|
||||
virtual_path ||= @virtual_path
|
||||
if virtual_path
|
||||
name = controller.url_for(name).split("://").last if name.is_a?(Hash)
|
||||
@ -226,7 +226,7 @@ def fragment_name_with_digest(name, virtual_path) #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def fragment_for(name = {}, options = nil, &block) #:nodoc:
|
||||
def fragment_for(name = {}, options = nil, &block)
|
||||
if content = read_fragment_for(name, options)
|
||||
@cache_hit = true
|
||||
content
|
||||
@ -236,11 +236,11 @@ def fragment_for(name = {}, options = nil, &block) #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def read_fragment_for(name, options) #:nodoc:
|
||||
def read_fragment_for(name, options)
|
||||
controller.read_fragment(name, options)
|
||||
end
|
||||
|
||||
def write_fragment_for(name, options) #:nodoc:
|
||||
def write_fragment_for(name, options)
|
||||
# VIEW TODO: Make #capture usable outside of ERB
|
||||
# This dance is needed because Builder can't use capture
|
||||
pos = output_buffer.length
|
||||
|
@ -513,6 +513,17 @@ def apply_form_for_options!(record, object, options) #:nodoc:
|
||||
# <input type="text" name="post[title]" value="<the title of the post>">
|
||||
# </form>
|
||||
#
|
||||
# # Though the fields don't have to correspond to model attributes:
|
||||
# <%= form_with model: Cat.new do |form| %>
|
||||
# <%= form.text_field :cats_dont_have_gills %>
|
||||
# <%= form.text_field :but_in_forms_they_can %>
|
||||
# <% end %>
|
||||
# # =>
|
||||
# <form action="/cats" method="post" data-remote="true">
|
||||
# <input type="text" name="cat[cats_dont_have_gills]">
|
||||
# <input type="text" name="cat[but_in_forms_they_can]">
|
||||
# </form>
|
||||
#
|
||||
# The parameters in the forms are accessible in controllers according to
|
||||
# their name nesting. So inputs named +title+ and <tt>post[title]</tt> are
|
||||
# accessible as <tt>params[:title]</tt> and <tt>params[:post][:title]</tt>
|
||||
@ -521,7 +532,7 @@ def apply_form_for_options!(record, object, options) #:nodoc:
|
||||
# By default +form_with+ attaches the <tt>data-remote</tt> attribute
|
||||
# submitting the form via an XMLHTTPRequest in the background if an
|
||||
# Unobtrusive JavaScript driver, like rails-ujs, is used. See the
|
||||
# <tt>:remote</tt> option for more.
|
||||
# <tt>:local</tt> option for more.
|
||||
#
|
||||
# For ease of comparison the examples above left out the submit button,
|
||||
# as well as the auto generated hidden fields that enable UTF-8 support
|
||||
@ -595,6 +606,16 @@ def apply_form_for_options!(record, object, options) #:nodoc:
|
||||
#
|
||||
# Where <tt>@document = Document.find(params[:id])</tt>.
|
||||
#
|
||||
# When using labels +form_with+ requires setting the id on the field being
|
||||
# labelled:
|
||||
#
|
||||
# <%= form_with(model: @post) do |form| %>
|
||||
# <%= form.label :title %>
|
||||
# <%= form.text_field :title, id: :post_title %>
|
||||
# <% end %>
|
||||
#
|
||||
# See +label+ for more on how the +for+ attribute is derived.
|
||||
#
|
||||
# === Mixing with other form helpers
|
||||
#
|
||||
# While +form_with+ uses a FormBuilder object it's possible to mix and
|
||||
@ -690,6 +711,9 @@ def apply_form_for_options!(record, object, options) #:nodoc:
|
||||
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
|
||||
# end
|
||||
def form_with(model: nil, scope: nil, url: nil, format: nil, **options)
|
||||
options[:allow_method_names_outside_object] = true
|
||||
options[:skip_default_ids] = true
|
||||
|
||||
if model
|
||||
url ||= polymorphic_path(model, format: format)
|
||||
|
||||
@ -964,14 +988,14 @@ def fields_for(record_name, record_object = nil, options = {}, &block)
|
||||
# <%= fields :comment do |fields| %>
|
||||
# <%= fields.text_field :body %>
|
||||
# <% end %>
|
||||
# # => <input type="text" name="comment[body] id="comment_body">
|
||||
# # => <input type="text" name="comment[body]>
|
||||
#
|
||||
# # Using a model infers the scope and assigns field values:
|
||||
# <%= fields model: Comment.new(body: "full bodied") do |fields| %<
|
||||
# <%= fields.text_field :body %>
|
||||
# <% end %>
|
||||
# # =>
|
||||
# <input type="text" name="comment[body] id="comment_body" value="full bodied">
|
||||
# <input type="text" name="comment[body] value="full bodied">
|
||||
#
|
||||
# # Using +fields+ with +form_with+:
|
||||
# <%= form_with model: @post do |form| %>
|
||||
@ -986,6 +1010,16 @@ def fields_for(record_name, record_object = nil, options = {}, &block)
|
||||
# or model is yielded, so any generated field names are prefixed with
|
||||
# either the passed scope or the scope inferred from the <tt>:model</tt>.
|
||||
#
|
||||
# When using labels +fields+ requires setting the id on the field being
|
||||
# labelled:
|
||||
#
|
||||
# <%= fields :comment do |fields| %>
|
||||
# <%= fields.label :body %>
|
||||
# <%= fields.text_field :body, id: :comment_body %>
|
||||
# <% end %>
|
||||
#
|
||||
# See +label+ for more on how the +for+ attribute is derived.
|
||||
#
|
||||
# === Mixing with other form helpers
|
||||
#
|
||||
# While +form_with+ uses a FormBuilder object it's possible to mix and
|
||||
@ -1003,7 +1037,9 @@ def fields_for(record_name, record_object = nil, options = {}, &block)
|
||||
# to work with an object as a base, like
|
||||
# FormOptionHelper#collection_select and DateHelper#datetime_select.
|
||||
def fields(scope = nil, model: nil, **options, &block)
|
||||
# TODO: Remove when ids and classes are no longer output by default.
|
||||
options[:allow_method_names_outside_object] = true
|
||||
options[:skip_default_ids] = true
|
||||
|
||||
if model
|
||||
scope ||= model_name_from_record_or_class(model).param_key
|
||||
end
|
||||
@ -1469,7 +1505,7 @@ def range_field(object_name, method, options = {})
|
||||
private
|
||||
def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: false,
|
||||
skip_enforcing_utf8: false, **options)
|
||||
html_options = options.except(:index, :include_id, :builder).merge(html)
|
||||
html_options = options.slice(:id, :class, :multipart, :method, :data).merge(html)
|
||||
html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
|
||||
html_options[:enforce_utf8] = !skip_enforcing_utf8
|
||||
|
||||
@ -1603,7 +1639,7 @@ def to_model
|
||||
def initialize(object_name, object, template, options)
|
||||
@nested_child_index = {}
|
||||
@object_name, @object, @template, @options = object_name, object, template, options
|
||||
@default_options = @options ? @options.slice(:index, :namespace) : {}
|
||||
@default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {}
|
||||
|
||||
convert_to_legacy_options(@options)
|
||||
|
||||
@ -1888,10 +1924,11 @@ def fields_for(record_name, record_object = nil, fields_options = {}, &block)
|
||||
record_name = model_name_from_record_or_class(record_object).param_key
|
||||
end
|
||||
|
||||
object_name = @object_name
|
||||
index = if options.has_key?(:index)
|
||||
options[:index]
|
||||
elsif defined?(@auto_index)
|
||||
self.object_name = @object_name.to_s.sub(/\[\]$/, "")
|
||||
object_name = object_name.to_s.sub(/\[\]$/, "")
|
||||
@auto_index
|
||||
end
|
||||
|
||||
@ -1910,6 +1947,9 @@ def fields_for(record_name, record_object = nil, fields_options = {}, &block)
|
||||
|
||||
# See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method.
|
||||
def fields(scope = nil, model: nil, **options, &block)
|
||||
options[:allow_method_names_outside_object] = true
|
||||
options[:skip_default_ids] = true
|
||||
|
||||
convert_to_legacy_options(options)
|
||||
|
||||
fields_for(scope || model, model, **options, &block)
|
||||
@ -2268,10 +2308,6 @@ def convert_to_legacy_options(options)
|
||||
if options.key?(:skip_id)
|
||||
options[:include_id] = !options.delete(:skip_id)
|
||||
end
|
||||
|
||||
if options.key?(:local)
|
||||
options[:remote] = !options.delete(:local)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user