mass_assignment 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +21 -38
- data/lib/mass_assignment.rb +2 -2
- data/test/test_helper.rb +2 -6
- metadata +4 -5
- data/rails/init.rb +0 -1
data/README.textile
CHANGED
@@ -8,17 +8,22 @@ h3. What It Is
|
|
8
8
|
|
9
9
|
A robust mass assignment method with a small and obvious syntax.
|
10
10
|
|
11
|
+
h4. The Traditional Approach
|
12
|
+
|
11
13
|
The normal mass assignment protection comes from attr_protected and attr_accessible. There are a few problems with this approach:
|
12
14
|
|
13
|
-
* Often never implemented
|
14
|
-
*
|
15
|
-
*
|
15
|
+
* *Often never implemented*, leaving a wide-open system. Rails blogs are full of dire warnings about forgetting your attr_protected.
|
16
|
+
* Once implemented, *easy to forget* when adding new attributes, leading to *bugs* (in an attr_accessible system) or *security holes* (in an attr_protected system).
|
17
|
+
* Restricts coding syntax. You can't easily use update_attributes() or attributes= because *your whitelist/blacklist gets in your own way*.
|
18
|
+
* Not contextual. The *list of allowed attributes can't change* to accomodate different user permissions or situations.
|
19
|
+
|
20
|
+
h4. The MassAssignment Approach
|
16
21
|
|
17
|
-
This plugin's solution is to let you specify an obvious list of allowed attributes when you mass assign attributes.
|
22
|
+
This plugin's solution is to let you specify an obvious and explicit list of allowed attributes when you mass assign attributes.
|
18
23
|
|
19
|
-
* The list of allowed attributes is in your controller at calltime, so it's easier to remember and update (it's not a hidden, magical system).
|
20
|
-
* The list of allowed attributes is optional, so it doesn't get in your way.
|
21
|
-
*
|
24
|
+
* The list of allowed attributes is in your controller at calltime, so it's *easier to remember and update* (it's not a hidden, magical system).
|
25
|
+
* The list of allowed attributes is optional, so it *doesn't get in your way*. You can use update_attributes() and attributes= for your own code again.
|
26
|
+
* Assignment *permissions are enforced by the controller*, where permissions belong. You can evaluate the current user or current situation and write the whitelist on the fly.
|
22
27
|
|
23
28
|
And as a bonus, permission plugins have a much easier time of things. The list of allowed attributes may be pulled from a permissions table without any awkward User.current class or thread variables.
|
24
29
|
|
@@ -40,20 +45,11 @@ Let's take a very plausible situation where you would want three separate lists
|
|
40
45
|
|
41
46
|
def update
|
42
47
|
@user = User.find(params[:id])
|
43
|
-
# username
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
class Admin::UsersController < ApplicationController
|
51
|
-
before_filter :admin_required
|
52
|
-
|
53
|
-
def update
|
54
|
-
@user = User.find(params[:id])
|
55
|
-
# admins, on the other hand, may change the username as needed, but may not set passwords
|
56
|
-
@user.assign(:params[:user], [:username, :email])
|
48
|
+
if admin? # admins may edit username and email but not password
|
49
|
+
@user.assign(params[:user], [:username, :email])
|
50
|
+
else # username isn't editable
|
51
|
+
@user.assign(params[:user], [:email, :password, :password_confirmation])
|
52
|
+
end
|
57
53
|
@user.save!
|
58
54
|
...
|
59
55
|
end
|
@@ -64,13 +60,13 @@ If you don't always want to set attribute lists, you may use the mass_assignment
|
|
64
60
|
|
65
61
|
<pre><code>
|
66
62
|
class User < ActiveRecord::Base
|
67
|
-
# The boring usage. You
|
63
|
+
# The boring usage. You're better off passing attributes to assign() in the controller.
|
68
64
|
mass_assignment_policy :only => [:email, :username]
|
69
|
-
|
65
|
+
|
70
66
|
# More interesting. No id fields!
|
71
67
|
mass_assignment_policy :except => /_id$/
|
72
68
|
end
|
73
|
-
|
69
|
+
|
74
70
|
# Hardcore. Disables mass assignment globally unless overridden!
|
75
71
|
ActiveRecord::Base.mass_assignment_policy :except => :all
|
76
72
|
</code></pre>
|
@@ -85,7 +81,7 @@ Nested assignment is supported by passing hashes and arrays for the whitelist.
|
|
85
81
|
class Pirate < ActiveRecord::Base
|
86
82
|
accepts_nested_attributes_for :ships
|
87
83
|
end
|
88
|
-
|
84
|
+
|
89
85
|
class PiratesController < ApplicationController
|
90
86
|
def update
|
91
87
|
@pirate = Pirate.find(params[:id])
|
@@ -114,16 +110,3 @@ Sometimes nested assignment isn't completely appropriate but you still need to a
|
|
114
110
|
</code></pre>
|
115
111
|
|
116
112
|
The major benefit here is that the block won't yield unless the params exist, so you don't need to check 'if params[:ship] && params[:ship][:pirate]'.
|
117
|
-
|
118
|
-
h3. Feedback
|
119
|
-
|
120
|
-
I can think of a couple alternate implementations for this API. Consider:
|
121
|
-
|
122
|
-
@user.assign(params[:user], [:username, :email])
|
123
|
-
|
124
|
-
vs
|
125
|
-
|
126
|
-
@user.assign(params[:user], :only => [:username, :email])
|
127
|
-
@user.assign(params[:user], :except => [:admin])
|
128
|
-
|
129
|
-
I personally prefer the former because I think that blacklists are inherently less safe than whitelists, with no compensating advantage. But I'd love to hear some other use cases and get feedback on this! Fork this repo and send pull requests or just contact me (github.com/cainlevy). Let's talk.
|
data/lib/mass_assignment.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'test/unit'
|
3
|
-
gem 'rails', '3.0.
|
3
|
+
gem 'rails', '3.0.7'
|
4
4
|
require 'active_support'
|
5
5
|
require 'active_support/test_case'
|
6
6
|
require 'active_record'
|
7
|
-
|
8
|
-
PLUGIN_ROOT = File.dirname(__FILE__) + '/../'
|
9
|
-
ActiveSupport::Dependencies.autoload_paths << File.join(PLUGIN_ROOT, 'lib')
|
10
|
-
require 'rails/init'
|
11
|
-
|
7
|
+
require 'mass_assignment'
|
12
8
|
require 'mocha'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mass_assignment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Lance Ivy
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-16 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -45,7 +45,6 @@ files:
|
|
45
45
|
- LICENSE
|
46
46
|
- README.textile
|
47
47
|
- Rakefile
|
48
|
-
- rails/init.rb
|
49
48
|
- test/test_helper.rb
|
50
49
|
- test/mass_assignment_test.rb
|
51
50
|
has_rdoc: true
|
data/rails/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ActiveRecord::Base.class_eval do include MassAssignment end
|