protected_attributes_continued 1.3.0 → 1.8.0

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
- SHA1:
3
- metadata.gz: 2eb844e472b4ede262323c067507b498ad29bd27
4
- data.tar.gz: a2c7241c8c82757901c5e065d39a0adbc8dfd5bb
2
+ SHA256:
3
+ metadata.gz: 3a53af38e43c5d8fee4bf8cb3f199422844d27b7104ac13e3c31b7bdc7af192a
4
+ data.tar.gz: 318cd88bd28f923e8ba90c5dc9e8e837cab4427501adde30b1797ab24234c96d
5
5
  SHA512:
6
- metadata.gz: 7d9e0f27404e0f676ed38fc118da71dbc1e9dfa682bb632de1eadc33a96299277793b017467b0f3746ebdbf3bfe80aba726399124536b035b63e5f8827562e6b
7
- data.tar.gz: 1ccfdcb731a28be930dee878c1d1d474ecb41a5f40636d96a899d6a8d26a09c8fde2ab403d98da73b1663f539df5ee2c1f48040be585932d474ce1d398c9e94b
6
+ metadata.gz: d9dcf4759ad7112b4b8d3191c28458ae8aa36503ae945fc481ca798e1c3e4f86bc815fc63da6d0dee616f88b70563c30e8d5a19da6ac26c05eecdf99172a2540
7
+ data.tar.gz: d3ffa567d9ce6896bb1ddd398a796eef5bedbf090dc08e8b00db56cdc4b132cc9776ed42b48a637382b1027dff2f40a419a8f7f4e965132ac996b21b00043e90
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2016 Guillermo Iguaran
1
+ Copyright (c) 2012-2017 Guillermo Iguaran
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # Protected Attributes Continued
2
+ <a href="https://badge.fury.io/rb/protected_attributes_continued" target="_blank"><img height="21" style='border:0px;height:21px;' border='0' src="https://badge.fury.io/rb/protected_attributes_continued.svg" alt="Gem Version"></a>
3
+ <a href='https://github.com/westonganger/protected_attributes_continued/actions' target='_blank'><img src="https://github.com/westonganger/protected_attributes_continued/workflows/Tests/badge.svg" style="max-width:100%;" height='21' style='border:0px;height:21px;' border='0' alt="CI Status"></a>
4
+ <a href='https://rubygems.org/gems/protected_attributes_continued' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://ruby-gem-downloads-badge.herokuapp.com/protected_attributes_continued?label=rubygems&type=total&total_label=downloads&color=brightgreen' border='0' alt='RubyGems Downloads' /></a>
2
5
 
3
- [![Build Status](https://api.travis-ci.org/westonganger/protected_attributes_continued.svg?branch=master)](https://travis-ci.org/westonganger/protected_attributes_continued)
6
+ > This is the community continued version of [`protected_attributes`](https://github.com/rails/protected_attributes) for Rails 5+. The Rails team dropped this feature and switched to `strong_parameters`. However some applications simply cannot be upgraded or the reduced granularity in params management is a non-issue. To continue supporting this feature going forward we continue the work here.
4
7
 
5
- This is the community continued version of `protected_attributes`. It works with Rails 5 only and I recommend you only use it to support legacy portions of your application that you do not want to upgrade. Note that this feature was dropped by the Rails team and switched to strong_parameters because of security issues, just so you understand your risks. This is in use successfully in some of my Rails 5 apps in which security like this is a non-issue. For people who would like to continue using this feature in their Rails 5 apps lets continue the work here.
6
-
7
- Protect attributes from mass-assignment in Active Record models.
8
-
9
- 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
+ Protect attributes from mass-assignment in Active Record models. This gem adds the class methods `attr_accessible` and `attr_protected` to declare white or black lists of attributes.
10
9
 
11
10
 
12
11
  ## Installation
@@ -97,11 +96,64 @@ config.active_record.mass_assignment_sanitizer = :strict
97
96
 
98
97
  Any protected attributes violation raises `ActiveModel::MassAssignmentSecurity::Error` then.
99
98
 
99
+ ## Contributing
100
+
101
+ For quicker feedback during gem development or debugging feel free to use the provided `rake console` task. It is defined within the [`Rakefile`](./Rakefile).
102
+
103
+ We test multiple versions of `Rails` using the `appraisal` gem. Please use the following steps to test using `appraisal`.
104
+
105
+ 1. `bundle exec appraisal install`
106
+ 2. `bundle exec appraisal rake test`
100
107
 
101
- # Credits
108
+ ## Credits
102
109
 
103
- Created and Maintained by [Weston Ganger - @westonganger](https://github.com/westonganger)
110
+ Created & Maintained by [Weston Ganger](https://westonganger.com) - [@westonganger](https://github.com/westonganger)
104
111
 
105
- Originally forked from the dead/unmaintained `protected_attributes` gem by the Rails team.
112
+ Originally forked from the dead/unmaintained [`protected_attributes`](https://github.com/rails/protected_attributes) gem by the Rails team.
106
113
 
107
- <a href='https://ko-fi.com/A5071NK' target='_blank'><img height='32' style='border:0px;height:32px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=a' border='0' alt='Buy Me a Coffee' /></a>
114
+ ## A Simple and Similar strong_params Alternative
115
+
116
+ While I do utilize this gem in some legacy projects. The latest approach I have adopted is similar to this gem but only utilizes Rails built-in `strong_params` which is a much more future proof way of doing things. The following is an example implementation.
117
+
118
+ ```ruby
119
+ ### Model
120
+ class Post < ActiveRecord::Base
121
+ has_many :comments
122
+
123
+ accepts_nested_attributes_for :comments, allow_destroy: true
124
+
125
+ def self.strong_params(params)
126
+ params.permit(:post).permit(*PERMITTED_ATTRIBUTES)
127
+ end
128
+
129
+ PERMITTED_PARAMETERS = [
130
+ :id,
131
+ :name,
132
+ :content,
133
+ :published_at,
134
+ {
135
+ comments_attributes: Comment::PERMITTED_PARAMETERS,
136
+ }
137
+ ].freeze
138
+
139
+ end
140
+
141
+ ### Controller
142
+ class PostsController < ApplicationController
143
+ def create
144
+ @post = Post.new(Post.strong_params(params))
145
+
146
+ @post.save
147
+
148
+ respond_with @post
149
+ end
150
+
151
+ def update
152
+ @post = Post.find(params[:id])
153
+
154
+ @post.update(Post.strong_params(params))
155
+
156
+ respond_with @post
157
+ end
158
+ end
159
+ ```
@@ -7,6 +7,7 @@ require "active_record/mass_assignment_security/nested_attributes"
7
7
  require "active_record/mass_assignment_security/persistence"
8
8
  require "active_record/mass_assignment_security/reflection"
9
9
  require "active_record/mass_assignment_security/relation"
10
+ require "active_record/mass_assignment_security/association_relation"
10
11
  require "active_record/mass_assignment_security/validations"
11
12
  require "active_record/mass_assignment_security/associations"
12
13
  require "active_record/mass_assignment_security/inheritance"
@@ -0,0 +1,33 @@
1
+ module ActiveRecord
2
+ class AssociationRelation
3
+ undef :new
4
+ undef :create
5
+ undef :create!
6
+
7
+ def build(attributes = nil, options = {}, &block)
8
+ if ActiveRecord::VERSION::STRING.to_f < 5.2
9
+ scoping { @association.build(attributes, options, &block) }
10
+ else
11
+ @association.build(attributes, options, &block)
12
+ end
13
+ end
14
+ alias new build
15
+
16
+ def create(attributes = nil, options = {}, &block)
17
+ if ActiveRecord::VERSION::STRING.to_f < 5.2
18
+ scoping { @association.create(attributes, options, &block) }
19
+ else
20
+ @association.create(attributes, options, &block)
21
+ end
22
+ end
23
+
24
+ def create!(attributes = nil, options = {}, &block)
25
+ if ActiveRecord::VERSION::STRING.to_f < 5.2
26
+ scoping { @association.create!(attributes, options, &block) }
27
+ else
28
+ @association.create!(attributes, options, &block)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -1,3 +1,5 @@
1
+ ### Original Rails Code - https://github.com/rails/rails/tree/master/activerecord/lib/active_record/associations
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class Association
@@ -5,11 +7,11 @@ module ActiveRecord
5
7
 
6
8
  def build_record(attributes, options)
7
9
  reflection.build_association(attributes, options) do |record|
8
- attributes = create_scope.except(*(record.changed - [reflection.foreign_key]))
10
+ the_scope = (ActiveRecord::VERSION::STRING.to_f >= 5.2 ? scope_for_create : create_scope)
11
+ attributes = the_scope.except(*(record.changed - [reflection.foreign_key]))
9
12
  record.assign_attributes(attributes, without_protection: true)
10
13
  end
11
14
  end
12
-
13
15
  private :build_record
14
16
  end
15
17
 
@@ -52,7 +54,6 @@ module ActiveRecord
52
54
  end
53
55
  end
54
56
  end
55
-
56
57
  private :create_record
57
58
  end
58
59
 
@@ -75,26 +76,41 @@ module ActiveRecord
75
76
  end
76
77
 
77
78
  module ThroughAssociation
78
- undef :build_record if respond_to?(:build_record, false)
79
+ ### Cant use respond_to?(method, true) because its a module instead of a class
80
+ undef :build_record if self.private_instance_methods.include?(:build_record)
81
+ def build_record(attributes, options={})
82
+ inverse = source_reflection.inverse_of
83
+ target = through_association.target
79
84
 
80
- private
85
+ if inverse && target && !target.is_a?(Array)
86
+ attributes[inverse.foreign_key] = target.id
87
+ end
81
88
 
82
- def build_record(attributes, options={})
83
- inverse = source_reflection.inverse_of
84
- target = through_association.target
89
+ super(attributes, options)
90
+ end
91
+ private :build_record
92
+ end
85
93
 
86
- if inverse && target && !target.is_a?(Array)
87
- attributes[inverse.foreign_key] = target.id
94
+ class HasManyThroughAssociation
95
+ if ActiveRecord.version >= Gem::Version.new('5.2.3')
96
+ undef :build_through_record
97
+ def build_through_record(record)
98
+ @through_records[record.object_id] ||= begin
99
+ ensure_mutable
100
+
101
+ attributes = through_scope_attributes
102
+ attributes[source_reflection.name] = record
103
+ attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
104
+
105
+ # Pass in `without_protection: true` here because `options_for_through_record`
106
+ # was removed in https://github.com/rails/rails/pull/35799
107
+ through_association.build(attributes, without_protection: true)
88
108
  end
89
-
90
- super(attributes, options)
91
109
  end
92
- end
110
+ private :build_through_record
111
+ end
93
112
 
94
- class HasManyThroughAssociation
95
113
  undef :build_record
96
- undef :options_for_through_record if respond_to?(:options_for_through_record, false)
97
-
98
114
  def build_record(attributes, options = {})
99
115
  ensure_not_nested
100
116
 
@@ -113,6 +129,7 @@ module ActiveRecord
113
129
  end
114
130
  private :build_record
115
131
 
132
+ undef :options_for_through_record if respond_to?(:options_for_through_record, true)
116
133
  def options_for_through_record
117
134
  [through_scope_attributes, without_protection: true]
118
135
  end
@@ -12,9 +12,17 @@ module ActiveRecord
12
12
 
13
13
  # The primary key and inheritance column can never be set by mass-assignment for security reasons.
14
14
  def attributes_protected_by_default
15
- default = [ primary_key, inheritance_column ]
16
- default << 'id' unless primary_key.eql? 'id'
17
- default
15
+ begin
16
+ default = [primary_key, inheritance_column]
17
+
18
+ if !primary_key.eql?('id')
19
+ default << 'id'
20
+ end
21
+ rescue ActiveRecord::NoDatabaseError
22
+ default = []
23
+ end
24
+
25
+ return default
18
26
  end
19
27
  end
20
28
 
@@ -3,6 +3,7 @@ module ActiveRecord
3
3
  module Core
4
4
 
5
5
  def initialize(attributes = nil, options = {})
6
+ @new_record = true
6
7
  self.class.define_attribute_methods
7
8
  @attributes = self.class._default_attributes.deep_dup
8
9
 
@@ -4,20 +4,41 @@ module ActiveRecord
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  module ClassMethods
7
-
7
+
8
8
  private
9
9
 
10
10
  # Detect the subclass from the inheritance column of attrs. If the inheritance column value
11
11
  # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
12
- # If this is a StrongParameters hash, and access to inheritance_column is not permitted,
13
- # this will ignore the inheritance column and return nil
14
- def subclass_from_attributes?(attrs)
12
+ def subclass_from_attributes(attrs)
15
13
  active_authorizer[:default].deny?(inheritance_column) ? nil : super
16
14
  end
15
+ end
16
+ end
17
+ end
18
+ end
17
19
 
18
- # Support Active Record <= 4.0.3, which uses the old method signature.
19
- def subclass_from_attrs(attrs)
20
- active_authorizer[:default].deny?(inheritance_column) ? nil : super
20
+ module ActiveRecord
21
+ module Inheritance
22
+ module ClassMethods
23
+ undef :new
24
+
25
+ def new(attributes = nil, options = {}, &block)
26
+ if abstract_class? || self == Base
27
+ raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
28
+ end
29
+
30
+ if has_attribute?(inheritance_column)
31
+ subclass = subclass_from_attributes(attributes)
32
+
33
+ if respond_to?(:column_defaults) && subclass.nil? && base_class == self
34
+ subclass = subclass_from_attributes(column_defaults)
35
+ end
36
+ end
37
+
38
+ if subclass && subclass != self
39
+ subclass.new(attributes, options, &block)
40
+ else
41
+ super
21
42
  end
22
43
  end
23
44
  end
@@ -15,7 +15,11 @@ module ActiveRecord
15
15
 
16
16
  attr_names.each do |association_name|
17
17
  if reflection = reflect_on_association(association_name)
18
- reflection.autosave = true
18
+ if ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 0
19
+ reflection.options[:autosave] = true
20
+ else
21
+ reflection.autosave = true
22
+ end
19
23
  add_autosave_association_callbacks(reflection)
20
24
 
21
25
  nested_attributes_options = self.nested_attributes_options.dup
@@ -24,7 +28,7 @@ module ActiveRecord
24
28
 
25
29
  type = (reflection.collection? ? :collection : :one_to_one)
26
30
 
27
- generated_methods_module = generated_association_methods
31
+ generated_methods_module = (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 0) ? generated_feature_methods : generated_association_methods
28
32
 
29
33
  # def pirate_attributes=(attributes)
30
34
  # assign_nested_attributes_for_one_to_one_association(:pirate, attributes, mass_assignment_options)
@@ -50,10 +54,16 @@ module ActiveRecord
50
54
 
51
55
  def assign_nested_attributes_for_one_to_one_association(association_name, attributes, assignment_opts = {})
52
56
  options = self.nested_attributes_options[association_name]
57
+
58
+ if attributes.class.name == 'ActionController::Parameters'
59
+ attributes = attributes.to_unsafe_h
60
+ elsif !attributes.is_a?(Hash) && !attributes.is_a?(Array)
61
+ raise ArgumentError, "ActionController::Parameters or Hash or Array expected, got #{attributes.class.name} (#{attributes.inspect})"
62
+ end
63
+
53
64
  attributes = attributes.with_indifferent_access
54
65
 
55
- if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) &&
56
- (options[:update_only] || record.id.to_s == attributes['id'].to_s)
66
+ if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) && (options[:update_only] || record.id.to_s == attributes['id'].to_s)
57
67
  assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy], assignment_opts) unless call_reject_if(association_name, attributes)
58
68
 
59
69
  elsif attributes['id'].present? && !assignment_opts[:without_protection]
@@ -112,6 +122,12 @@ module ActiveRecord
112
122
  end
113
123
 
114
124
  attributes_collection.each do |attributes|
125
+ if attributes.class.name == 'ActionController::Parameters'
126
+ attributes = attributes.to_unsafe_h
127
+ elsif !attributes.is_a?(Hash) && !attributes.is_a?(Array)
128
+ raise ArgumentError, "ActionController::Parameters or Hash or Array expected, got #{attributes.class.name} (#{attributes.inspect})"
129
+ end
130
+
115
131
  attributes = attributes.with_indifferent_access
116
132
 
117
133
  if attributes['id'].blank?
@@ -1,5 +1,8 @@
1
1
  module ActiveRecord
2
2
  class Relation
3
+ undef :new
4
+ undef :create
5
+ undef :create!
3
6
  undef :first_or_create
4
7
  undef :first_or_create!
5
8
  undef :first_or_initialize
@@ -7,6 +10,32 @@ module ActiveRecord
7
10
  undef :find_or_create_by
8
11
  undef :find_or_create_by!
9
12
 
13
+ def new(attributes = nil, options = {}, &block)
14
+ attrs = respond_to?(:values_for_create) ? values_for_create(attributes) : attributes
15
+
16
+ scoping { klass.new(attrs, options, &block) }
17
+ end
18
+
19
+ def create(attributes = nil, options = {}, &block)
20
+ if attributes.is_a?(Array)
21
+ attributes.collect { |attr| create(attr, options, &block) }
22
+ else
23
+ attrs = respond_to?(:values_for_create) ? values_for_create(attributes) : attributes
24
+
25
+ scoping { klass.create(attrs, options, &block) }
26
+ end
27
+ end
28
+
29
+ def create!(attributes = nil, options = {}, &block)
30
+ if attributes.is_a?(Array)
31
+ attributes.collect { |attr| create!(attr, options, &block) }
32
+ else
33
+ attrs = respond_to?(:values_for_create) ? values_for_create(attributes) : attributes
34
+
35
+ scoping { klass.create!(attrs, options, &block) }
36
+ end
37
+ end
38
+
10
39
  # Tries to load the first record; if it fails, then <tt>create</tt> is called with the same arguments as this method.
11
40
  #
12
41
  # Expects arguments in the same format as +Base.create+.
@@ -1,3 +1,3 @@
1
1
  module ProtectedAttributes
2
- VERSION = "1.3.0"
2
+ VERSION = "1.8.0".freeze
3
3
  end
metadata CHANGED
@@ -1,87 +1,87 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protected_attributes_continued
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Weston Ganger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-05 00:00:00.000000000 Z
11
+ date: 2021-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '5.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '5.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: actionpack
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '5.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: railties
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '5.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '5.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: sqlite3
70
+ name: mocha
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 1.4.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 1.4.0
83
83
  - !ruby/object:Gem::Dependency
84
- name: mocha
84
+ name: appraisal
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -96,7 +96,7 @@ dependencies:
96
96
  version: '0'
97
97
  description: Protect attributes from mass assignment
98
98
  email:
99
- - westonganger@gmail.com
99
+ - weston@westonganger.com
100
100
  executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
@@ -108,6 +108,7 @@ files:
108
108
  - lib/active_model/mass_assignment_security/permission_set.rb
109
109
  - lib/active_model/mass_assignment_security/sanitizer.rb
110
110
  - lib/active_record/mass_assignment_security.rb
111
+ - lib/active_record/mass_assignment_security/association_relation.rb
111
112
  - lib/active_record/mass_assignment_security/associations.rb
112
113
  - lib/active_record/mass_assignment_security/attribute_assignment.rb
113
114
  - lib/active_record/mass_assignment_security/core.rb
@@ -140,8 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
141
  - !ruby/object:Gem::Version
141
142
  version: '0'
142
143
  requirements: []
143
- rubyforge_project:
144
- rubygems_version: 2.6.8
144
+ rubygems_version: 3.1.2
145
145
  signing_key:
146
146
  specification_version: 4
147
147
  summary: Protect attributes from mass assignment in Active Record models