Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.

Commit 3019080

Browse files
committed
Fix Rails 5.2.x new/create arguments error
1 parent ec0bd16 commit 3019080

File tree

3 files changed

+102
-5
lines changed

3 files changed

+102
-5
lines changed

README.md

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Protected Attributes Continued
22
<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://travis-ci.org/westonganger/protected_attributes_continued' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://api.travis-ci.org/westonganger/protected_attributes_continued.svg?branch=master' border='0' alt='Build Status' /></a>
34
<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>
45

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+
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. If you are looking for a similar approach see my [recommended alternative](https://github.com/westonganger/protected_attributes_continued#a-better-alternative)
67

78
Protect attributes from mass-assignment in Active Record models.
89

@@ -98,10 +99,49 @@ config.active_record.mass_assignment_sanitizer = :strict
9899
Any protected attributes violation raises `ActiveModel::MassAssignmentSecurity::Error` then.
99100

100101

101-
# Credits
102+
## Contributing
102103

103-
Created and Maintained by [Weston Ganger - @westonganger](https://github.com/westonganger)
104+
We use the `appraisal` gem for testing multiple versions of `Rails`. Please use the following steps to test using `appraisal`.
105+
106+
1. `bundle exec appraisal install`
107+
2. `bundle exec appraisal rake test`
108+
109+
## Credits
110+
111+
Created & Maintained by [Weston Ganger](https://westonganger.com) - [@westonganger](https://github.com/westonganger)
104112

105113
Originally forked from the dead/unmaintained `protected_attributes` gem by the Rails team.
106114

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>
115+
## A Better Alternative
116+
117+
While I do utilize this gem in some legacy projects I have adopted an alternative approach that is similar to this gem but only utilizes Rails built-in `strong_params` which is a much more future proof way of doing things. See the following example for how to implement.
118+
119+
```ruby
120+
class Post < ActiveRecord::Base
121+
122+
def self.strong_params(params)
123+
params.permit(:post).permit(:name, :content, :published_at)
124+
end
125+
126+
end
127+
128+
class PostsController < ApplicationController
129+
130+
def create
131+
@post = Post.new
132+
133+
@post.assign_attributes(Post.strong_params(params))
134+
135+
respond_with @post
136+
end
137+
138+
def update
139+
@post = Post.find(params[:id])
140+
141+
@post.update(Post.strong_params(params))
142+
143+
respond_with @post
144+
end
145+
146+
end
147+
```

lib/active_record/mass_assignment_security/inheritance.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module Inheritance
44
extend ActiveSupport::Concern
55

66
module ClassMethods
7-
7+
88
private
99

1010
# Detect the subclass from the inheritance column of attrs. If the inheritance column value
@@ -16,3 +16,31 @@ def subclass_from_attributes(attrs)
1616
end
1717
end
1818
end
19+
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
42+
end
43+
end
44+
end
45+
end
46+
end

lib/active_record/mass_assignment_security/relation.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,41 @@
11
module ActiveRecord
22
class Relation
3+
undef :new
4+
undef :create
5+
undef :create!
36
undef :first_or_create
47
undef :first_or_create!
58
undef :first_or_initialize
69
undef :find_or_initialize_by
710
undef :find_or_create_by
811
undef :find_or_create_by!
912

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+
1039
# Tries to load the first record; if it fails, then <tt>create</tt> is called with the same arguments as this method.
1140
#
1241
# Expects arguments in the same format as +Base.create+.

0 commit comments

Comments
 (0)