mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #33718 from kddeisz/permit-list
Finish converting whitelist and blacklist references
This commit is contained in:
commit
068fe7dc90
19 changed files with 63 additions and 52 deletions
|
@ -5,8 +5,8 @@ require "active_support/core_ext/hash/slice"
|
||||||
|
|
||||||
module ActionController
|
module ActionController
|
||||||
# This module is deprecated in favor of +config.force_ssl+ in your environment
|
# This module is deprecated in favor of +config.force_ssl+ in your environment
|
||||||
# config file. This will ensure all communication to non-whitelisted endpoints
|
# config file. This will ensure all endpoints not explicitly marked otherwise
|
||||||
# served by your application occurs over HTTPS.
|
# will have all communication served over HTTPS.
|
||||||
module ForceSSL # :nodoc:
|
module ForceSSL # :nodoc:
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
include AbstractController::Callbacks
|
include AbstractController::Callbacks
|
||||||
|
|
|
@ -86,7 +86,7 @@ module ActionController
|
||||||
# Note: SSEs are not currently supported by IE. However, they are supported
|
# Note: SSEs are not currently supported by IE. However, they are supported
|
||||||
# by Chrome, Firefox, Opera, and Safari.
|
# by Chrome, Firefox, Opera, and Safari.
|
||||||
class SSE
|
class SSE
|
||||||
WHITELISTED_OPTIONS = %w( retry event id )
|
PERMITTED_OPTIONS = %w( retry event id )
|
||||||
|
|
||||||
def initialize(stream, options = {})
|
def initialize(stream, options = {})
|
||||||
@stream = stream
|
@stream = stream
|
||||||
|
@ -111,7 +111,7 @@ module ActionController
|
||||||
def perform_write(json, options)
|
def perform_write(json, options)
|
||||||
current_options = @options.merge(options).stringify_keys
|
current_options = @options.merge(options).stringify_keys
|
||||||
|
|
||||||
WHITELISTED_OPTIONS.each do |option_name|
|
PERMITTED_OPTIONS.each do |option_name|
|
||||||
if (option_value = current_options[option_name])
|
if (option_value = current_options[option_name])
|
||||||
@stream.write "#{option_name}: #{option_value}\n"
|
@stream.write "#{option_name}: #{option_value}\n"
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,7 @@ module ActionController #:nodoc:
|
||||||
# @people = Person.all
|
# @people = Person.all
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# That action implicitly responds to all formats, but formats can also be whitelisted:
|
# That action implicitly responds to all formats, but formats can also be explicitly enumerated:
|
||||||
#
|
#
|
||||||
# def index
|
# def index
|
||||||
# @people = Person.all
|
# @people = Person.all
|
||||||
|
|
|
@ -45,7 +45,7 @@ module ActionController #:nodoc:
|
||||||
# the same origin. Note however that any cross-origin third party domain
|
# the same origin. Note however that any cross-origin third party domain
|
||||||
# allowed via {CORS}[https://en.wikipedia.org/wiki/Cross-origin_resource_sharing]
|
# allowed via {CORS}[https://en.wikipedia.org/wiki/Cross-origin_resource_sharing]
|
||||||
# will also be able to create XHR requests. Be sure to check your
|
# will also be able to create XHR requests. Be sure to check your
|
||||||
# CORS whitelist before disabling forgery protection for XHR.
|
# CORS configuration before disabling forgery protection for XHR.
|
||||||
#
|
#
|
||||||
# CSRF protection is turned on with the <tt>protect_from_forgery</tt> method.
|
# CSRF protection is turned on with the <tt>protect_from_forgery</tt> method.
|
||||||
# By default <tt>protect_from_forgery</tt> protects your session with
|
# By default <tt>protect_from_forgery</tt> protects your session with
|
||||||
|
|
|
@ -58,7 +58,7 @@ module ActionController
|
||||||
|
|
||||||
# == Action Controller \Parameters
|
# == Action Controller \Parameters
|
||||||
#
|
#
|
||||||
# Allows you to choose which attributes should be whitelisted for mass updating
|
# Allows you to choose which attributes should be permitted for mass updating
|
||||||
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
||||||
# Provides two methods for this purpose: #require and #permit. The former is
|
# Provides two methods for this purpose: #require and #permit. The former is
|
||||||
# used to mark parameters as required. The latter is used to set the parameter
|
# used to mark parameters as required. The latter is used to set the parameter
|
||||||
|
@ -505,7 +505,7 @@ module ActionController
|
||||||
#
|
#
|
||||||
# Note that if you use +permit+ in a key that points to a hash,
|
# Note that if you use +permit+ in a key that points to a hash,
|
||||||
# it won't allow all the hash. You also need to specify which
|
# it won't allow all the hash. You also need to specify which
|
||||||
# attributes inside the hash should be whitelisted.
|
# attributes inside the hash should be permitted.
|
||||||
#
|
#
|
||||||
# params = ActionController::Parameters.new({
|
# params = ActionController::Parameters.new({
|
||||||
# person: {
|
# person: {
|
||||||
|
@ -997,8 +997,8 @@ module ActionController
|
||||||
#
|
#
|
||||||
# It provides an interface for protecting attributes from end-user
|
# It provides an interface for protecting attributes from end-user
|
||||||
# assignment. This makes Action Controller parameters forbidden
|
# assignment. This makes Action Controller parameters forbidden
|
||||||
# to be used in Active Model mass assignment until they have been
|
# to be used in Active Model mass assignment until they have been explicitly
|
||||||
# whitelisted.
|
# enumerated.
|
||||||
#
|
#
|
||||||
# In addition, parameters can be marked as required and flow through a
|
# In addition, parameters can be marked as required and flow through a
|
||||||
# predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
|
# predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
|
||||||
|
@ -1034,7 +1034,7 @@ module ActionController
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
|
# In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
|
||||||
# will need to specify which nested attributes should be whitelisted. You might want
|
# will need to specify which nested attributes should be permitted. You might want
|
||||||
# to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
|
# to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
|
||||||
#
|
#
|
||||||
# class Person
|
# class Person
|
||||||
|
@ -1052,7 +1052,7 @@ module ActionController
|
||||||
# private
|
# private
|
||||||
#
|
#
|
||||||
# def person_params
|
# def person_params
|
||||||
# # It's mandatory to specify the nested attributes that should be whitelisted.
|
# # It's mandatory to specify the nested attributes that should be permitted.
|
||||||
# # If you use `permit` with just the key that points to the nested attributes hash,
|
# # If you use `permit` with just the key that points to the nested attributes hash,
|
||||||
# # it will return an empty hash.
|
# # it will return an empty hash.
|
||||||
# params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
|
# params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
|
||||||
|
|
|
@ -85,10 +85,7 @@ module ActionDispatch
|
||||||
if variant.all? { |v| v.is_a?(Symbol) }
|
if variant.all? { |v| v.is_a?(Symbol) }
|
||||||
@variant = ActiveSupport::ArrayInquirer.new(variant)
|
@variant = ActiveSupport::ArrayInquirer.new(variant)
|
||||||
else
|
else
|
||||||
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \
|
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols."
|
||||||
"For security reasons, never directly set the variant to a user-provided value, " \
|
|
||||||
"like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
|
|
||||||
"then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -553,10 +553,10 @@ module ActionDispatch
|
||||||
#
|
#
|
||||||
# match 'json_only', constraints: { format: 'json' }, via: :get
|
# match 'json_only', constraints: { format: 'json' }, via: :get
|
||||||
#
|
#
|
||||||
# class Whitelist
|
# class PermitList
|
||||||
# def matches?(request) request.remote_ip == '1.2.3.4' end
|
# def matches?(request) request.remote_ip == '1.2.3.4' end
|
||||||
# end
|
# end
|
||||||
# match 'path', to: 'c#a', constraints: Whitelist.new, via: :get
|
# match 'path', to: 'c#a', constraints: PermitList.new, via: :get
|
||||||
#
|
#
|
||||||
# See <tt>Scoping#constraints</tt> for more examples with its scope
|
# See <tt>Scoping#constraints</tt> for more examples with its scope
|
||||||
# equivalent.
|
# equivalent.
|
||||||
|
|
|
@ -20,7 +20,7 @@ class AlwaysPermittedParametersTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "permits parameters that are whitelisted" do
|
test "allows both explicitly listed and always-permitted parameters" do
|
||||||
params = ActionController::Parameters.new(
|
params = ActionController::Parameters.new(
|
||||||
book: { pages: 65 },
|
book: { pages: 65 },
|
||||||
format: "json")
|
format: "json")
|
||||||
|
|
|
@ -10,7 +10,7 @@ module ActionView
|
||||||
# These helper methods extend Action View making them callable within your template files.
|
# These helper methods extend Action View making them callable within your template files.
|
||||||
module SanitizeHelper
|
module SanitizeHelper
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
# Sanitizes HTML input, stripping all tags and attributes that aren't whitelisted.
|
# Sanitizes HTML input, stripping all but known-safe tags and attributes.
|
||||||
#
|
#
|
||||||
# It also strips href/src attributes with unsafe protocols like
|
# It also strips href/src attributes with unsafe protocols like
|
||||||
# <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
|
# <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
|
||||||
|
@ -40,7 +40,7 @@ module ActionView
|
||||||
#
|
#
|
||||||
# <%= sanitize @comment.body %>
|
# <%= sanitize @comment.body %>
|
||||||
#
|
#
|
||||||
# Providing custom whitelisted tags and attributes:
|
# Providing custom lists of permitted tags and attributes:
|
||||||
#
|
#
|
||||||
# <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
|
# <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
|
||||||
#
|
#
|
||||||
|
|
|
@ -14,7 +14,17 @@ module ActionView
|
||||||
class_attribute :erb_implementation, default: Erubi
|
class_attribute :erb_implementation, default: Erubi
|
||||||
|
|
||||||
# Do not escape templates of these mime types.
|
# Do not escape templates of these mime types.
|
||||||
class_attribute :escape_whitelist, default: ["text/plain"]
|
class_attribute :escape_ignore_list, default: ["text/plain"]
|
||||||
|
|
||||||
|
[self, singleton_class].each do |base|
|
||||||
|
base.send(:alias_method, :escape_whitelist, :escape_ignore_list)
|
||||||
|
base.send(:alias_method, :escape_whitelist=, :escape_ignore_list=)
|
||||||
|
|
||||||
|
base.deprecate(
|
||||||
|
escape_whitelist: "use #escape_ignore_list instead",
|
||||||
|
:escape_whitelist= => "use #escape_ignore_list= instead"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
|
ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
|
||||||
|
|
||||||
|
@ -47,7 +57,7 @@ module ActionView
|
||||||
|
|
||||||
self.class.erb_implementation.new(
|
self.class.erb_implementation.new(
|
||||||
erb,
|
erb,
|
||||||
escape: (self.class.escape_whitelist.include? template.type),
|
escape: (self.class.escape_ignore_list.include? template.type),
|
||||||
trim: (self.class.erb_trim_mode == "-")
|
trim: (self.class.erb_trim_mode == "-")
|
||||||
).src
|
).src
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,18 +24,20 @@ module ActiveJob
|
||||||
module Arguments
|
module Arguments
|
||||||
extend self
|
extend self
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
TYPE_WHITELIST = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ]
|
PERMITTED_TYPES = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ]
|
||||||
|
|
||||||
# Serializes a set of arguments. Whitelisted types are returned
|
# Serializes a set of arguments. Intrinsic types that can safely be
|
||||||
# as-is. Arrays/Hashes are serialized element by element.
|
# serialized without mutation are returned as-is. Arrays/Hashes are
|
||||||
# All other types are serialized using GlobalID.
|
# serialized element by element. All other types are serialized using
|
||||||
|
# GlobalID.
|
||||||
def serialize(arguments)
|
def serialize(arguments)
|
||||||
arguments.map { |argument| serialize_argument(argument) }
|
arguments.map { |argument| serialize_argument(argument) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Deserializes a set of arguments. Whitelisted types are returned
|
# Deserializes a set of arguments. Instrinsic types that can safely be
|
||||||
# as-is. Arrays/Hashes are deserialized element by element.
|
# deserialized without mutation are returned as-is. Arrays/Hashes are
|
||||||
# All other types are deserialized using GlobalID.
|
# deserialized element by element. All other types are deserialized using
|
||||||
|
# GlobalID.
|
||||||
def deserialize(arguments)
|
def deserialize(arguments)
|
||||||
arguments.map { |argument| deserialize_argument(argument) }
|
arguments.map { |argument| deserialize_argument(argument) }
|
||||||
rescue
|
rescue
|
||||||
|
@ -64,7 +66,7 @@ module ActiveJob
|
||||||
|
|
||||||
def serialize_argument(argument)
|
def serialize_argument(argument)
|
||||||
case argument
|
case argument
|
||||||
when *TYPE_WHITELIST
|
when *PERMITTED_TYPES
|
||||||
argument
|
argument
|
||||||
when GlobalID::Identification
|
when GlobalID::Identification
|
||||||
convert_to_global_id_hash(argument)
|
convert_to_global_id_hash(argument)
|
||||||
|
@ -88,7 +90,7 @@ module ActiveJob
|
||||||
case argument
|
case argument
|
||||||
when String
|
when String
|
||||||
GlobalID::Locator.locate(argument) || argument
|
GlobalID::Locator.locate(argument) || argument
|
||||||
when *TYPE_WHITELIST
|
when *PERMITTED_TYPES
|
||||||
argument
|
argument
|
||||||
when Array
|
when Array
|
||||||
argument.map { |arg| deserialize_argument(arg) }
|
argument.map { |arg| deserialize_argument(arg) }
|
||||||
|
|
|
@ -31,7 +31,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
||||||
|
|
||||||
class GeneratedAttributeMethods < Module #:nodoc:
|
class GeneratedAttributeMethods < Module #:nodoc:
|
||||||
include Mutex_m
|
include Mutex_m
|
||||||
|
@ -123,7 +123,7 @@ module ActiveRecord
|
||||||
# A class method is 'dangerous' if it is already (re)defined by Active Record, but
|
# A class method is 'dangerous' if it is already (re)defined by Active Record, but
|
||||||
# not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
|
# not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
|
||||||
def dangerous_class_method?(method_name)
|
def dangerous_class_method?(method_name)
|
||||||
BLACKLISTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
|
RESTRICTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
|
||||||
end
|
end
|
||||||
|
|
||||||
def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
|
def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
|
||||||
|
@ -167,12 +167,14 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Regexp whitelist. Matches the following:
|
# Regexp for column names (with or without a table name prefix). Matches
|
||||||
|
# the following:
|
||||||
# "#{table_name}.#{column_name}"
|
# "#{table_name}.#{column_name}"
|
||||||
# "#{column_name}"
|
# "#{column_name}"
|
||||||
COLUMN_NAME_WHITELIST = /\A(?:\w+\.)?\w+\z/i
|
COLUMN_NAME = /\A(?:\w+\.)?\w+\z/i
|
||||||
|
|
||||||
# Regexp whitelist. Matches the following:
|
# Regexp for column names with order (with or without a table name
|
||||||
|
# prefix, with or without various order modifiers). Matches the following:
|
||||||
# "#{table_name}.#{column_name}"
|
# "#{table_name}.#{column_name}"
|
||||||
# "#{table_name}.#{column_name} #{direction}"
|
# "#{table_name}.#{column_name} #{direction}"
|
||||||
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
||||||
|
@ -181,7 +183,7 @@ module ActiveRecord
|
||||||
# "#{column_name} #{direction}"
|
# "#{column_name} #{direction}"
|
||||||
# "#{column_name} #{direction} NULLS FIRST"
|
# "#{column_name} #{direction} NULLS FIRST"
|
||||||
# "#{column_name} NULLS LAST"
|
# "#{column_name} NULLS LAST"
|
||||||
COLUMN_NAME_ORDER_WHITELIST = /
|
COLUMN_NAME_WITH_ORDER = /
|
||||||
\A
|
\A
|
||||||
(?:\w+\.)?
|
(?:\w+\.)?
|
||||||
\w+
|
\w+
|
||||||
|
@ -190,12 +192,12 @@ module ActiveRecord
|
||||||
\z
|
\z
|
||||||
/ix
|
/ix
|
||||||
|
|
||||||
def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
|
def disallow_raw_sql!(args, permit: COLUMN_NAME) # :nodoc:
|
||||||
unexpected = args.reject do |arg|
|
unexpected = args.reject do |arg|
|
||||||
arg.kind_of?(Arel::Node) ||
|
arg.kind_of?(Arel::Node) ||
|
||||||
arg.is_a?(Arel::Nodes::SqlLiteral) ||
|
arg.is_a?(Arel::Nodes::SqlLiteral) ||
|
||||||
arg.is_a?(Arel::Attributes::Attribute) ||
|
arg.is_a?(Arel::Attributes::Attribute) ||
|
||||||
arg.to_s.split(/\s*,\s*/).all? { |part| whitelist.match?(part) }
|
arg.to_s.split(/\s*,\s*/).all? { |part| permit.match?(part) }
|
||||||
end
|
end
|
||||||
|
|
||||||
return if unexpected.none?
|
return if unexpected.none?
|
||||||
|
|
|
@ -190,7 +190,7 @@ module ActiveRecord
|
||||||
relation = apply_join_dependency
|
relation = apply_join_dependency
|
||||||
relation.pluck(*column_names)
|
relation.pluck(*column_names)
|
||||||
else
|
else
|
||||||
enforce_raw_sql_whitelist(column_names)
|
disallow_raw_sql!(column_names)
|
||||||
relation = spawn
|
relation = spawn
|
||||||
relation.select_values = column_names.map { |cn|
|
relation.select_values = column_names.map { |cn|
|
||||||
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
@klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
|
||||||
|
|
|
@ -1133,9 +1133,9 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
order_args.flatten!
|
order_args.flatten!
|
||||||
|
|
||||||
@klass.enforce_raw_sql_whitelist(
|
@klass.disallow_raw_sql!(
|
||||||
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
order_args.flat_map { |a| a.is_a?(Hash) ? a.keys : a },
|
||||||
whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
|
permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER
|
||||||
)
|
)
|
||||||
|
|
||||||
validate_order_args(order_args)
|
validate_order_args(order_args)
|
||||||
|
|
|
@ -61,8 +61,8 @@ module ActiveRecord
|
||||||
# # => "id ASC"
|
# # => "id ASC"
|
||||||
def sanitize_sql_for_order(condition)
|
def sanitize_sql_for_order(condition)
|
||||||
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
||||||
enforce_raw_sql_whitelist([condition.first],
|
disallow_raw_sql!([condition.first],
|
||||||
whitelist: AttributeMethods::ClassMethods::COLUMN_NAME_ORDER_WHITELIST
|
permit: AttributeMethods::ClassMethods::COLUMN_NAME_WITH_ORDER
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ensure we aren't dealing with a subclass of String that might
|
# Ensure we aren't dealing with a subclass of String that might
|
||||||
|
|
|
@ -40,7 +40,7 @@ if ActiveRecord::Base.connection.supports_explain?
|
||||||
assert_equal binds, queries[0][1]
|
assert_equal binds, queries[0][1]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_collects_nothing_if_the_statement_is_not_whitelisted
|
def test_collects_nothing_if_the_statement_is_not_explainable
|
||||||
SUBSCRIBER.finish(nil, nil, name: "SQL", sql: "SHOW max_identifier_length")
|
SUBSCRIBER.finish(nil, nil, name: "SQL", sql: "SHOW max_identifier_length")
|
||||||
assert_empty queries
|
assert_empty queries
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ require "models/post"
|
||||||
require "models/comment"
|
require "models/comment"
|
||||||
|
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
module DelegationWhitelistTests
|
module ArrayDelegationTests
|
||||||
ARRAY_DELEGATES = [
|
ARRAY_DELEGATES = [
|
||||||
:+, :-, :|, :&, :[], :shuffle,
|
:+, :-, :|, :&, :[], :shuffle,
|
||||||
:all?, :collect, :compact, :detect, :each, :each_cons, :each_with_index,
|
:all?, :collect, :compact, :detect, :each, :each_cons, :each_with_index,
|
||||||
|
@ -38,7 +38,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class DelegationAssociationTest < ActiveRecord::TestCase
|
class DelegationAssociationTest < ActiveRecord::TestCase
|
||||||
include DelegationWhitelistTests
|
include ArrayDelegationTests
|
||||||
include DeprecatedArelDelegationTests
|
include DeprecatedArelDelegationTests
|
||||||
|
|
||||||
def target
|
def target
|
||||||
|
@ -47,7 +47,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class DelegationRelationTest < ActiveRecord::TestCase
|
class DelegationRelationTest < ActiveRecord::TestCase
|
||||||
include DelegationWhitelistTests
|
include ArrayDelegationTests
|
||||||
include DeprecatedArelDelegationTests
|
include DeprecatedArelDelegationTests
|
||||||
|
|
||||||
def target
|
def target
|
||||||
|
|
|
@ -324,7 +324,7 @@ class FakeKlass
|
||||||
table[name]
|
table[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
def enforce_raw_sql_whitelist(*args)
|
def disallow_raw_sql!(*args)
|
||||||
# noop
|
# noop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,12 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_migration_with_table_having_from_in_title
|
def test_add_migration_with_table_having_from_in_title
|
||||||
migration = "add_email_address_to_blacklisted_from_campaign"
|
migration = "add_email_address_to_excluded_from_campaign"
|
||||||
run_generator [migration, "email_address:string"]
|
run_generator [migration, "email_address:string"]
|
||||||
|
|
||||||
assert_migration "db/migrate/#{migration}.rb" do |content|
|
assert_migration "db/migrate/#{migration}.rb" do |content|
|
||||||
assert_method :change, content do |change|
|
assert_method :change, content do |change|
|
||||||
assert_match(/add_column :blacklisted_from_campaigns, :email_address, :string/, change)
|
assert_match(/add_column :excluded_from_campaigns, :email_address, :string/, change)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue