protected_attributes 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 395ab272536df136e316a89087b094b773f6be7b
4
- data.tar.gz: 279387fed8cec2a444b8a279c64d78aa6c3d876e
3
+ metadata.gz: aac372473a095a28495278d6c7d42f0322bc8dc4
4
+ data.tar.gz: 64888dd76e4cb9a56254e5a4efefe967524f0017
5
5
  SHA512:
6
- metadata.gz: a034a1aae746c4d3c942e96d8201010fc5654ae4487547b64a67fee0f2e907321978d6af68050b34fc033e01598d2e579b661e03ae4f5d19d20253f7d3316db8
7
- data.tar.gz: d114248044437b7da5d9760d07468b9d4670aeaff2654c0042d3f76e1c16fa1305016d8d5680402351a72dd17b6e067ede82e3696614f22021d54fcc532d792f
6
+ metadata.gz: f7f64b3eba28e34e6e2dd95c54e2988070268257688b628107f2fea3a096aa35c1e6d9333d1f1334aba703d2afd625ca48abad43fddd64362c487d5e636b6207
7
+ data.tar.gz: b04a19963ae3b9715dcc16dbcab2202dc7a80ee520b3adc2f9f48a9e34848910ec02cccbda9174b811216370e414696e81716586b841fb4a1e4b98dec3f96046
data/README.md CHANGED
@@ -1,30 +1,26 @@
1
- # ProtectedAttributes
1
+ # Protected Attributes
2
2
 
3
3
  [![Build Status](https://api.travis-ci.org/rails/protected_attributes.svg?branch=master)](https://travis-ci.org/rails/protected_attributes)
4
4
 
5
- Protect attributes from mass-assignment in ActiveRecord models.
5
+ Protect attributes from mass-assignment in Active Record models.
6
6
 
7
- This plugin adds `attr_accessible` and `attr_protected` in your models.
7
+ This plugin adds the class methods `attr_accessible` and `attr_protected` to your models to be able to declare white or black lists of attributes.
8
8
 
9
- Note: This plugin will be officially supported until the release of Rails 5.0
9
+ Note: This plugin will be officially supported until the release of Rails 5.0.
10
10
 
11
11
  ## Installation
12
12
 
13
- Add this line to your application's Gemfile:
13
+ Add this line to your application's `Gemfile`:
14
14
 
15
15
  gem 'protected_attributes'
16
16
 
17
17
  And then execute:
18
18
 
19
- $ bundle
20
-
21
- Or install it yourself as:
22
-
23
- $ gem install protected_attributes
19
+ bundle install
24
20
 
25
21
  ## Usage
26
22
 
27
- Mass assignment security provides an interface for protecting attributes from end-user assignment. This plugin provides two class methods in your Active Record class to control access to your attributes. The `attr_protected` method takes a list of attributes that will not be accessible for mass-assignment.
23
+ Mass assignment security provides an interface for protecting attributes from end-user injection. This plugin provides two class methods in Active Record classes to control access to their attributes. The `attr_protected` method takes a list of attributes that will be ignored in mass-assignment.
28
24
 
29
25
  For example:
30
26
  ```ruby
@@ -35,12 +31,15 @@ attr_protected :admin
35
31
  ```ruby
36
32
  attr_protected :last_login, :as => :admin
37
33
  ```
38
- A much better way, because it follows the whitelist-principle, is the `attr_accessible` method. It is the exact opposite of `attr_protected`, because it takes a list of attributes that will be accessible. All other attributes will be protected. This way you won’t forget to protect attributes when adding new ones in the course of development. Here is an example:
34
+ A much better way, because it follows the whitelist-principle, is the `attr_accessible` method. It is the exact opposite of `attr_protected`, because it takes a list of attributes that will be mass-assigned if present. Any other attributes will be ignored. This way you won’t forget to protect attributes when adding new ones in the course of development. Here is an example:
35
+
39
36
  ```ruby
40
37
  attr_accessible :name
41
38
  attr_accessible :name, :is_admin, :as => :admin
42
39
  ```
40
+
43
41
  If you want to set a protected attribute, you will to have to assign it individually:
42
+
44
43
  ```ruby
45
44
  params[:user] # => {:name => "owned", :is_admin => true}
46
45
  @user = User.new(params[:user])
@@ -48,12 +47,15 @@ params[:user] # => {:name => "owned", :is_admin => true}
48
47
  @user.is_admin = true
49
48
  @user.is_admin # => true
50
49
  ```
50
+
51
51
  When assigning attributes in Active Record using `attributes=` the `:default` role will be used. To assign attributes using different roles you should use `assign_attributes` which accepts an optional `:as` options parameter. If no `:as` option is provided then the `:default` role will be used.
52
+
52
53
  You can also bypass mass-assignment security by using the `:without_protection` option. Here is an example:
54
+
53
55
  ```ruby
54
56
  @user = User.new
55
57
 
56
- @user.assign_attributes({ :name => 'Josh', :is_admin => true })
58
+ @user.assign_attributes(:name => 'Josh', :is_admin => true)
57
59
  @user.name # => Josh
58
60
  @user.is_admin # => false
59
61
 
@@ -65,7 +67,9 @@ You can also bypass mass-assignment security by using the `:without_protection`
65
67
  @user.name # => Josh
66
68
  @user.is_admin # => true
67
69
  ```
70
+
68
71
  In a similar way, `new`, `create`, `create!`, `update_attributes` and `update_attributes!` methods all respect mass-assignment security and accept either `:as` or `:without_protection` options. For example:
72
+
69
73
  ```ruby
70
74
  @user = User.new({ :name => 'Sebastian', :is_admin => true }, :as => :admin)
71
75
  @user.name # => Sebastian
@@ -75,17 +79,21 @@ In a similar way, `new`, `create`, `create!`, `update_attributes` and `update_at
75
79
  @user.name # => Sebastian
76
80
  @user.is_admin # => true
77
81
  ```
82
+
78
83
  By default the gem will create an empty whitelist of attributes available for mass-assignment for all models in your app.
84
+
79
85
  As such, your models will need to explicitly whitelist or blacklist accessible parameters by using an `attr_accessible` or `attr_protected` declaration. This technique is best applied at the start of a new project. However, for an existing project with a thorough set of functional tests, it should be straightforward and relatively quick to use this application config option; run your tests, and expose each attribute (via `attr_accessible` or `attr_protected`), as dictated by your failing test.
80
86
 
81
87
  This option can be turned off using a configuration option:
88
+
82
89
  ```ruby
83
90
  config.active_record.whitelist_attributes = false
84
91
  ```
85
92
 
86
- For more complex permissions, mass-assignment security may be handled outside the model by extending a non-ActiveRecord class, such as a controller, with this behavior.
93
+ For more complex permissions, mass-assignment security may be handled outside the model by extending a non-Active Record class, such as a controller, with this behavior.
87
94
 
88
95
  For example, a logged-in user may need to assign additional attributes depending on their role:
96
+
89
97
  ```ruby
90
98
  class AccountsController < ApplicationController
91
99
  include ActiveModel::MassAssignmentSecurity
@@ -110,14 +118,13 @@ end
110
118
 
111
119
  ### Errors
112
120
 
113
- By default, errors will not be raised if the user passes attributes in the params hash which are not allowed to be updated.
114
- If you want the functionality where exceptions (`ActiveModel::MassAssignmentSecurity::Error`) are raised. Add to your config
115
- the strict flag:
121
+ By default, attributes in the params hash which are not allowed to be updated are just ignored. If you prefer an exception to be raised configure:
116
122
 
117
123
  ```ruby
118
124
  config.active_record.mass_assignment_sanitizer = :strict
119
125
  ```
120
126
 
127
+ Any protected attributes violation raises `ActiveModel::MassAssignmentSecurity::Error` then.
121
128
 
122
129
  ## Contributing
123
130
 
@@ -5,6 +5,8 @@ require 'action_controller/metal/params_wrapper'
5
5
  module ActionController
6
6
  module ParamsWrapper
7
7
  class Options # :nodoc:
8
+ undef :include
9
+
8
10
  def include
9
11
  return super if @include_set
10
12
 
@@ -348,11 +348,11 @@ module ActiveModel
348
348
  protected
349
349
 
350
350
  def sanitize_for_mass_assignment(attributes, role = nil) #:nodoc:
351
- unless _uses_mass_assignment_security
351
+ if _uses_mass_assignment_security
352
+ _mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(role))
353
+ else
352
354
  sanitize_forbidden_attributes(attributes)
353
355
  end
354
-
355
- _mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(role))
356
356
  end
357
357
 
358
358
  def mass_assignment_authorizer(role) #:nodoc:
@@ -19,7 +19,6 @@ class ActiveRecord::Base
19
19
  include ActiveRecord::MassAssignmentSecurity::Core
20
20
  include ActiveRecord::MassAssignmentSecurity::AttributeAssignment
21
21
  include ActiveRecord::MassAssignmentSecurity::Persistence
22
- include ActiveRecord::MassAssignmentSecurity::Relation
23
22
  include ActiveRecord::MassAssignmentSecurity::Validations
24
23
  include ActiveRecord::MassAssignmentSecurity::NestedAttributes
25
24
  include ActiveRecord::MassAssignmentSecurity::Inheritance
@@ -1,6 +1,8 @@
1
1
  module ActiveRecord
2
2
  module Associations
3
3
  class Association
4
+ undef :build_record
5
+
4
6
  def build_record(attributes, options)
5
7
  reflection.build_association(attributes, options) do |record|
6
8
  attributes = create_scope.except(*(record.changed - [reflection.foreign_key]))
@@ -12,6 +14,10 @@ module ActiveRecord
12
14
  end
13
15
 
14
16
  class CollectionAssociation
17
+ undef :build
18
+ undef :create
19
+ undef :create!
20
+
15
21
  def build(attributes = {}, options = {}, &block)
16
22
  if attributes.is_a?(Array)
17
23
  attributes.collect { |attr| build(attr, options, &block) }
@@ -51,6 +57,9 @@ module ActiveRecord
51
57
  end
52
58
 
53
59
  class CollectionProxy
60
+ undef :create
61
+ undef :create!
62
+
54
63
  def build(attributes = {}, options = {}, &block)
55
64
  @association.build(attributes, options, &block)
56
65
  end
@@ -66,6 +75,7 @@ module ActiveRecord
66
75
  end
67
76
 
68
77
  module ThroughAssociation
78
+ undef :build_record if respond_to?(:build_record, false)
69
79
 
70
80
  private
71
81
 
@@ -82,6 +92,9 @@ module ActiveRecord
82
92
  end
83
93
 
84
94
  class HasManyThroughAssociation
95
+ undef :build_record
96
+ undef :options_for_through_record
97
+
85
98
  def build_record(attributes, options = {})
86
99
  ensure_not_nested
87
100
 
@@ -107,6 +120,10 @@ module ActiveRecord
107
120
  end
108
121
 
109
122
  class SingularAssociation
123
+ undef :create
124
+ undef :create!
125
+ undef :build
126
+
110
127
  def create(attributes = {}, options = {}, &block)
111
128
  create_record(attributes, options, &block)
112
129
  end
@@ -2,12 +2,16 @@ module ActiveRecord
2
2
  module Reflection
3
3
  if defined?(AbstractReflection)
4
4
  class AbstractReflection
5
+ undef :build_association
6
+
5
7
  def build_association(*options, &block)
6
8
  klass.new(*options, &block)
7
9
  end
8
10
  end
9
11
  else
10
12
  class AssociationReflection
13
+ undef :build_association
14
+
11
15
  def build_association(*options, &block)
12
16
  klass.new(*options, &block)
13
17
  end
@@ -1,46 +1,75 @@
1
1
  module ActiveRecord
2
- module MassAssignmentSecurity
3
- module Relation
4
- # Tries to load the first record; if it fails, then <tt>create</tt> is called with the same arguments as this method.
5
- #
6
- # Expects arguments in the same format as +Base.create+.
7
- #
8
- # ==== Examples
9
- # # Find the first user named Penélope or create a new one.
10
- # User.where(:first_name => 'Penélope').first_or_create
11
- # # => <User id: 1, first_name: 'Penélope', last_name: nil>
12
- #
13
- # # Find the first user named Penélope or create a new one.
14
- # # We already have one so the existing record will be returned.
15
- # User.where(:first_name => 'Penélope').first_or_create
16
- # # => <User id: 1, first_name: 'Penélope', last_name: nil>
17
- #
18
- # # Find the first user named Scarlett or create a new one with a particular last name.
19
- # User.where(:first_name => 'Scarlett').first_or_create(:last_name => 'Johansson')
20
- # # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
21
- #
22
- # # Find the first user named Scarlett or create a new one with a different last name.
23
- # # We already have one so the existing record will be returned.
24
- # User.where(:first_name => 'Scarlett').first_or_create do |user|
25
- # user.last_name = "O'Hara"
26
- # end
27
- # # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
28
- def first_or_create(attributes = nil, options = {}, &block)
29
- first || create(attributes, options, &block)
30
- end
2
+ class Relation
3
+ undef :first_or_create
4
+ undef :first_or_create!
5
+ undef :first_or_initialize
6
+ undef :find_or_initialize_by
7
+ undef :find_or_create_by
8
+ undef :find_or_create_by!
31
9
 
32
- # Like <tt>first_or_create</tt> but calls <tt>create!</tt> so an exception is raised if the created record is invalid.
33
- #
34
- # Expects arguments in the same format as <tt>Base.create!</tt>.
35
- def first_or_create!(attributes = nil, options = {}, &block)
36
- first || create!(attributes, options, &block)
37
- end
10
+ # Tries to load the first record; if it fails, then <tt>create</tt> is called with the same arguments as this method.
11
+ #
12
+ # Expects arguments in the same format as +Base.create+.
13
+ #
14
+ # ==== Examples
15
+ # # Find the first user named Penélope or create a new one.
16
+ # User.where(:first_name => 'Penélope').first_or_create
17
+ # # => <User id: 1, first_name: 'Penélope', last_name: nil>
18
+ #
19
+ # # Find the first user named Penélope or create a new one.
20
+ # # We already have one so the existing record will be returned.
21
+ # User.where(:first_name => 'Penélope').first_or_create
22
+ # # => <User id: 1, first_name: 'Penélope', last_name: nil>
23
+ #
24
+ # # Find the first user named Scarlett or create a new one with a particular last name.
25
+ # User.where(:first_name => 'Scarlett').first_or_create(:last_name => 'Johansson')
26
+ # # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
27
+ #
28
+ # # Find the first user named Scarlett or create a new one with a different last name.
29
+ # # We already have one so the existing record will be returned.
30
+ # User.where(:first_name => 'Scarlett').first_or_create do |user|
31
+ # user.last_name = "O'Hara"
32
+ # end
33
+ # # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
34
+ def first_or_create(attributes = nil, options = {}, &block)
35
+ first || create(attributes, options, &block)
36
+ end
37
+
38
+ # Like <tt>first_or_create</tt> but calls <tt>create!</tt> so an exception is raised if the created record is invalid.
39
+ #
40
+ # Expects arguments in the same format as <tt>Base.create!</tt>.
41
+ def first_or_create!(attributes = nil, options = {}, &block)
42
+ first || create!(attributes, options, &block)
43
+ end
44
+
45
+ # Like <tt>first_or_create</tt> but calls <tt>new</tt> instead of <tt>create</tt>.
46
+ #
47
+ # Expects arguments in the same format as <tt>Base.new</tt>.
48
+ def first_or_initialize(attributes = nil, options = {}, &block)
49
+ first || new(attributes, options, &block)
50
+ end
51
+
52
+ def find_or_initialize_by(attributes, options = {}, &block)
53
+ find_by(attributes) || new(attributes, options, &block)
54
+ end
55
+
56
+ def find_or_create_by(attributes, options = {}, &block)
57
+ find_by(attributes) || create(attributes, options, &block)
58
+ end
59
+
60
+ def find_or_create_by!(attributes, options = {}, &block)
61
+ find_by(attributes) || create!(attributes, options, &block)
62
+ end
63
+ end
64
+
65
+ module QueryMethods
66
+ protected
38
67
 
39
- # Like <tt>first_or_create</tt> but calls <tt>new</tt> instead of <tt>create</tt>.
40
- #
41
- # Expects arguments in the same format as <tt>Base.new</tt>.
42
- def first_or_initialize(attributes = nil, &block)
43
- first || new(attributes, options, &block)
68
+ def sanitize_forbidden_attributes(attributes) #:nodoc:
69
+ if !model._uses_mass_assignment_security
70
+ sanitize_for_mass_assignment(attributes)
71
+ else
72
+ attributes
44
73
  end
45
74
  end
46
75
  end
@@ -1,5 +1,4 @@
1
1
  require "active_model/mass_assignment_security"
2
- require "protected_attributes/railtie" if defined? Rails::Railtie
3
2
  require "protected_attributes/version"
4
3
 
5
4
  ActiveSupport.on_load :active_record do
@@ -1,3 +1,3 @@
1
1
  module ProtectedAttributes
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protected_attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-22 00:00:00.000000000 Z
11
+ date: 2015-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -142,7 +142,6 @@ files:
142
142
  - lib/active_record/mass_assignment_security/relation.rb
143
143
  - lib/active_record/mass_assignment_security/validations.rb
144
144
  - lib/protected_attributes.rb
145
- - lib/protected_attributes/railtie.rb
146
145
  - lib/protected_attributes/version.rb
147
146
  homepage: https://github.com/rails/protected_attributes
148
147
  licenses:
@@ -164,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
163
  version: '0'
165
164
  requirements: []
166
165
  rubyforge_project:
167
- rubygems_version: 2.4.5
166
+ rubygems_version: 2.4.7
168
167
  signing_key:
169
168
  specification_version: 4
170
169
  summary: Protect attributes from mass assignment in Active Record models
@@ -1,16 +0,0 @@
1
- module ProtectedAttributes
2
- class Railtie < ::Rails::Railtie
3
- config.before_configuration do |app|
4
- config.action_controller.permit_all_parameters = true
5
- config.active_record.whitelist_attributes = true if config.respond_to?(:active_record)
6
- end
7
-
8
- initializer "protected_attributes.active_record", :before => "active_record.set_configs" do |app|
9
- ActiveSupport.on_load :active_record do
10
- if app.config.respond_to?(:active_record) && app.config.active_record.delete(:whitelist_attributes)
11
- attr_accessible(nil)
12
- end
13
- end
14
- end
15
- end
16
- end