Remove allow_mass_assignment_of matcher (#1430)
This commit is contained in:
parent
e746f2e370
commit
33e1a1abbe
|
@ -26,7 +26,6 @@ require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher'
|
||||||
require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
|
require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
|
||||||
require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
|
require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
|
||||||
require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
|
require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
|
||||||
require 'shoulda/matchers/active_model/allow_mass_assignment_of_matcher'
|
|
||||||
require 'shoulda/matchers/active_model/errors'
|
require 'shoulda/matchers/active_model/errors'
|
||||||
require 'shoulda/matchers/active_model/have_secure_password_matcher'
|
require 'shoulda/matchers/active_model/have_secure_password_matcher'
|
||||||
|
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
module Shoulda
|
|
||||||
module Matchers
|
|
||||||
module ActiveModel
|
|
||||||
# The `allow_mass_assignment_of` matcher tests usage of Rails 3's
|
|
||||||
# `attr_accessible` and `attr_protected` macros, asserting that an
|
|
||||||
# attribute in your model is contained in either the whitelist or
|
|
||||||
# blacklist and thus can or cannot be set via mass assignment.
|
|
||||||
#
|
|
||||||
# class Post
|
|
||||||
# include ActiveModel::Model
|
|
||||||
# include ActiveModel::MassAssignmentSecurity
|
|
||||||
# attr_accessor :title
|
|
||||||
#
|
|
||||||
# attr_accessible :title
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# class User
|
|
||||||
# include ActiveModel::Model
|
|
||||||
# include ActiveModel::MassAssignmentSecurity
|
|
||||||
# attr_accessor :encrypted_password
|
|
||||||
#
|
|
||||||
# attr_protected :encrypted_password
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # RSpec
|
|
||||||
# RSpec.describe Post, type: :model do
|
|
||||||
# it { should allow_mass_assignment_of(:title) }
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# RSpec.describe User, type: :model do
|
|
||||||
# it { should_not allow_mass_assignment_of(:encrypted_password) }
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # Minitest (Shoulda)
|
|
||||||
# class PostTest < ActiveSupport::TestCase
|
|
||||||
# should allow_mass_assignment_of(:title)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# class UserTest < ActiveSupport::TestCase
|
|
||||||
# should_not allow_mass_assignment_of(:encrypted_password)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# #### Optional qualifiers
|
|
||||||
#
|
|
||||||
# ##### as
|
|
||||||
#
|
|
||||||
# Use `as` if your mass-assignment rules apply only under a certain role
|
|
||||||
# *(Rails >= 3.1 only)*.
|
|
||||||
#
|
|
||||||
# class Post
|
|
||||||
# include ActiveModel::Model
|
|
||||||
# include ActiveModel::MassAssignmentSecurity
|
|
||||||
# attr_accessor :title
|
|
||||||
#
|
|
||||||
# attr_accessible :title, as: :admin
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # RSpec
|
|
||||||
# RSpec.describe Post, type: :model do
|
|
||||||
# it { should allow_mass_assignment_of(:title).as(:admin) }
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # Minitest (Shoulda)
|
|
||||||
# class PostTest < ActiveSupport::TestCase
|
|
||||||
# should allow_mass_assignment_of(:title).as(:admin)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# @return [AllowMassAssignmentOfMatcher]
|
|
||||||
#
|
|
||||||
def allow_mass_assignment_of(value)
|
|
||||||
AllowMassAssignmentOfMatcher.new(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
# @private
|
|
||||||
class AllowMassAssignmentOfMatcher
|
|
||||||
attr_reader :failure_message, :failure_message_when_negated
|
|
||||||
|
|
||||||
def initialize(attribute)
|
|
||||||
@attribute = attribute.to_s
|
|
||||||
@options = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def as(role)
|
|
||||||
@options[:role] = role
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
def matches?(subject)
|
|
||||||
@subject = subject
|
|
||||||
if attr_mass_assignable?
|
|
||||||
if whitelisting?
|
|
||||||
@failure_message_when_negated = "#{@attribute} was made "\
|
|
||||||
'accessible'
|
|
||||||
elsif protected_attributes.empty?
|
|
||||||
@failure_message_when_negated = 'no attributes were protected'
|
|
||||||
else
|
|
||||||
@failure_message_when_negated =
|
|
||||||
"#{class_name} is protecting " <<
|
|
||||||
"#{protected_attributes.to_a.to_sentence}, " <<
|
|
||||||
"but not #{@attribute}."
|
|
||||||
end
|
|
||||||
true
|
|
||||||
else
|
|
||||||
@failure_message =
|
|
||||||
if whitelisting?
|
|
||||||
"Expected #{@attribute} to be accessible"
|
|
||||||
else
|
|
||||||
"Did not expect #{@attribute} to be protected"
|
|
||||||
end
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def description
|
|
||||||
[base_description, role_description].compact.join(' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def base_description
|
|
||||||
"allow mass assignment of #{@attribute}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def role_description
|
|
||||||
if role != :default
|
|
||||||
"as #{role}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def role
|
|
||||||
@options[:role] || :default
|
|
||||||
end
|
|
||||||
|
|
||||||
def protected_attributes
|
|
||||||
@_protected_attributes ||= (@subject.class.protected_attributes || [])
|
|
||||||
end
|
|
||||||
|
|
||||||
def accessible_attributes
|
|
||||||
@_accessible_attributes ||=
|
|
||||||
(@subject.class.accessible_attributes || [])
|
|
||||||
end
|
|
||||||
|
|
||||||
def whitelisting?
|
|
||||||
authorizer.is_a?(::ActiveModel::MassAssignmentSecurity::WhiteList)
|
|
||||||
end
|
|
||||||
|
|
||||||
def attr_mass_assignable?
|
|
||||||
!authorizer.deny?(@attribute)
|
|
||||||
end
|
|
||||||
|
|
||||||
def authorizer
|
|
||||||
@subject.class.active_authorizer[role]
|
|
||||||
end
|
|
||||||
|
|
||||||
def class_name
|
|
||||||
@subject.class.name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,123 +0,0 @@
|
||||||
require 'unit_spec_helper'
|
|
||||||
|
|
||||||
describe Shoulda::Matchers::ActiveModel::AllowMassAssignmentOfMatcher, type: :model do
|
|
||||||
if action_pack_lt_5?
|
|
||||||
context '#description' do
|
|
||||||
context 'without a role' do
|
|
||||||
it 'includes the attribute name' do
|
|
||||||
expect(described_class.new(:attr).description).
|
|
||||||
to eq 'allow mass assignment of attr'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if active_model_3_1?
|
|
||||||
context 'with a role' do
|
|
||||||
it 'includes the attribute name and the role' do
|
|
||||||
expect(described_class.new(:attr).as(:admin).description).
|
|
||||||
to eq 'allow mass assignment of attr as admin'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'an attribute that is blacklisted from mass-assignment' do
|
|
||||||
it 'rejects being mass-assignable' do
|
|
||||||
model = define_model(:example, blacklisted: :string) do
|
|
||||||
attr_protected :blacklisted
|
|
||||||
end.new
|
|
||||||
|
|
||||||
expect(model).not_to allow_mass_assignment_of(:blacklisted)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'an attribute that is not whitelisted for mass-assignment' do
|
|
||||||
it 'rejects being mass-assignable' do
|
|
||||||
model = define_model(
|
|
||||||
:example,
|
|
||||||
not_whitelisted: :string,
|
|
||||||
whitelisted: :string,
|
|
||||||
) do
|
|
||||||
attr_accessible :whitelisted
|
|
||||||
end.new
|
|
||||||
|
|
||||||
expect(model).not_to allow_mass_assignment_of(:not_whitelisted)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'an attribute that is whitelisted for mass-assignment' do
|
|
||||||
it 'accepts being mass-assignable' do
|
|
||||||
expect(define_model(:example, whitelisted: :string) do
|
|
||||||
attr_accessible :whitelisted
|
|
||||||
end.new).to allow_mass_assignment_of(:whitelisted)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'an attribute not included in the mass-assignment blacklist' do
|
|
||||||
it 'accepts being mass-assignable' do
|
|
||||||
model = define_model(
|
|
||||||
:example,
|
|
||||||
not_blacklisted: :string,
|
|
||||||
blacklisted: :string,
|
|
||||||
) do
|
|
||||||
attr_protected :blacklisted
|
|
||||||
end.new
|
|
||||||
|
|
||||||
expect(model).to allow_mass_assignment_of(:not_blacklisted)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unless active_model_3_2? || active_model_4_0?
|
|
||||||
context 'an attribute on a class with no protected attributes' do
|
|
||||||
it 'accepts being mass-assignable' do
|
|
||||||
expect(no_protected_attributes).to allow_mass_assignment_of(:attr)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'assigns a negative failure message' do
|
|
||||||
matcher = allow_mass_assignment_of(:attr)
|
|
||||||
|
|
||||||
expect(matcher.matches?(no_protected_attributes)).to eq true
|
|
||||||
|
|
||||||
expect(matcher.failure_message_when_negated).not_to be_nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def no_protected_attributes
|
|
||||||
define_model(:example, attr: :string).new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'an attribute on a class with all protected attributes' do
|
|
||||||
it 'rejects being mass-assignable' do
|
|
||||||
expect(all_protected_attributes).not_to allow_mass_assignment_of(:attr)
|
|
||||||
end
|
|
||||||
|
|
||||||
def all_protected_attributes
|
|
||||||
define_model(:example, attr: :string) do
|
|
||||||
attr_accessible nil
|
|
||||||
end.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if active_model_3_1?
|
|
||||||
context 'an attribute included in the mass-assignment whitelist for admin role only' do
|
|
||||||
it 'rejects being mass-assignable' do
|
|
||||||
expect(mass_assignable_as_admin).not_to allow_mass_assignment_of(:attr)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'accepts being mass-assignable for admin' do
|
|
||||||
expect(mass_assignable_as_admin).to allow_mass_assignment_of(:attr).as(:admin)
|
|
||||||
end
|
|
||||||
|
|
||||||
def mass_assignable_as_admin
|
|
||||||
define_model(:example, attr: :string) do
|
|
||||||
attr_accessible :attr, as: :admin
|
|
||||||
end.new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def define_model(name, columns, &block)
|
|
||||||
super(name, columns, whitelist_attributes: false, &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue