alfred 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +4 -1
- data/README.textile +120 -0
- data/alfred.gemspec +3 -2
- data/lib/alfred.rb +1 -2
- data/lib/alfred/mass_assignment_security.rb +150 -0
- data/lib/alfred/orm/active_record.rb +30 -1
- data/lib/alfred/version.rb +1 -1
- metadata +51 -15
- data/.rvmrc +0 -1
- data/lib/alfred/models.rb +0 -53
data/.travis.yml
CHANGED
data/README.textile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
h1. Alfred - the unobtrusive butler who takes care of the uninvited guests "!https://secure.travis-ci.org/parcydo/alfred.png?branch=master!":http://travis-ci.org/parcydo/alfred
|
2
|
+
|
3
|
+
Travis is an attempt to create an open-source, distributed build system for the Ruby community that:
|
4
|
+
|
5
|
+
1. allows open-source projects to register their repository and have their test-suites run on demand
|
6
|
+
2. allows users to contribute build capacities by connecting a VM that runs a build agent somewhere on their underused servers
|
7
|
+
|
8
|
+
h2. Contact
|
9
|
+
* "Github":http://github.com/parcydo
|
10
|
+
* "Twitter":http://twitter.com/parcydo
|
11
|
+
|
12
|
+
h2. Documentation
|
13
|
+
|
14
|
+
* "Wiki":http://github.com/parcydo/alfred/wiki
|
15
|
+
* "YARD":http://rdoc.info/github/parcydo/alfred
|
16
|
+
|
17
|
+
h2. Preview
|
18
|
+
|
19
|
+
h3. Without Alfred, and with much mess:
|
20
|
+
|
21
|
+
<pre>
|
22
|
+
# app/models/user.rb
|
23
|
+
class User < ActiveRecord::Base
|
24
|
+
attr_accessible :email, :password, :password_confirmation
|
25
|
+
attr_accessible :email, :password, :password_confirmation, :username, as: :admin
|
26
|
+
attr_accessible :email, :password, :password_confirmation, :username, as: :on_create
|
27
|
+
end
|
28
|
+
</pre>
|
29
|
+
|
30
|
+
Have to use a special role:
|
31
|
+
|
32
|
+
<pre>
|
33
|
+
# app/controllers/users_controlelr.rb
|
34
|
+
class UsersController < ApplicationController
|
35
|
+
def create
|
36
|
+
@user = User.create(params[:user], as: :on_create)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
</pre>
|
40
|
+
|
41
|
+
h3. With Alfred and no hassles:
|
42
|
+
|
43
|
+
<pre>
|
44
|
+
# app/models/user.rb
|
45
|
+
class User < ActiveRecord::Base
|
46
|
+
alfred_accessible :email, :password
|
47
|
+
alfred_accessible :username, as: :admin
|
48
|
+
alfred_accessible :username, on: :create
|
49
|
+
end
|
50
|
+
</pre>
|
51
|
+
|
52
|
+
Nothing special here:
|
53
|
+
|
54
|
+
<pre>
|
55
|
+
# app/controllers/users_controlelr.rb
|
56
|
+
class UsersController < ApplicationController
|
57
|
+
def create
|
58
|
+
@user = User.create(params[:user])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
</pre>
|
62
|
+
|
63
|
+
h2. Usage
|
64
|
+
|
65
|
+
alfred_accessible and alfred_protected behaves just like attr_accessible and attr_protected on steroids.
|
66
|
+
|
67
|
+
h3. accessible and protected
|
68
|
+
|
69
|
+
<pre>
|
70
|
+
class User < ActiveRecord::Base
|
71
|
+
alfred_accessible :a, :b
|
72
|
+
alfred_protected :c, :d
|
73
|
+
end
|
74
|
+
</pre>
|
75
|
+
|
76
|
+
h3. roles
|
77
|
+
|
78
|
+
Custom inherits from default role:
|
79
|
+
|
80
|
+
<pre>
|
81
|
+
class User < ActiveRecord::Base
|
82
|
+
alfred_accessible :a, :b
|
83
|
+
alfred_accessible :c, :d, as: :custom
|
84
|
+
end
|
85
|
+
</pre>
|
86
|
+
|
87
|
+
h3. custom inheritance
|
88
|
+
|
89
|
+
<pre>
|
90
|
+
class User < ActiveRecord::Base
|
91
|
+
alfred_accessible :a, :b
|
92
|
+
alfred_accessible :c, :d, as: :custom
|
93
|
+
alfred_accessible :e, :f, as: :custom2, inherit: :custom
|
94
|
+
end
|
95
|
+
</pre>
|
96
|
+
|
97
|
+
h3. events
|
98
|
+
|
99
|
+
<pre>
|
100
|
+
class User < ActiveRecord::Base
|
101
|
+
alfred_accessible :a, :b
|
102
|
+
alfred_accessible :c, :d, on: :create
|
103
|
+
alfred_accessible :e, :f, on: :update
|
104
|
+
end
|
105
|
+
</pre>
|
106
|
+
|
107
|
+
h3. passwords
|
108
|
+
|
109
|
+
password_confirmation will automatically added by default.
|
110
|
+
|
111
|
+
<pre>
|
112
|
+
class User < ActiveRecord::Base
|
113
|
+
alfred_accessible :password
|
114
|
+
end
|
115
|
+
</pre>
|
116
|
+
|
117
|
+
h2. Requirements
|
118
|
+
|
119
|
+
* Ruby 1.9.2 (Ruby 1.9.1 is not supported).
|
120
|
+
* Rails 3.1.x (Rails 3.0.x is not supported).
|
data/alfred.gemspec
CHANGED
@@ -13,7 +13,8 @@ Gem::Specification.new do |s|
|
|
13
13
|
|
14
14
|
s.rubyforge_project = "alfred"
|
15
15
|
|
16
|
-
s.add_dependency "rails", "
|
16
|
+
s.add_dependency "rails", ">= 3.1.0"
|
17
|
+
s.add_development_dependency "activemodel"
|
17
18
|
s.add_development_dependency "activerecord"
|
18
19
|
s.add_development_dependency "rr"
|
19
20
|
s.add_development_dependency "rspec"
|
@@ -22,4 +23,4 @@ Gem::Specification.new do |s|
|
|
22
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
24
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
25
|
s.require_paths = ["lib"]
|
25
|
-
end
|
26
|
+
end
|
data/lib/alfred.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'rails'
|
2
2
|
|
3
3
|
module Alfred
|
4
|
-
autoload :Models, 'alfred/models'
|
5
|
-
|
6
4
|
# Automaticly add password_confirmation if password exists.
|
7
5
|
mattr_accessor :auto_password_confirmation
|
8
6
|
@@auto_password_confirmation = true
|
@@ -15,4 +13,5 @@ module Alfred
|
|
15
13
|
end
|
16
14
|
|
17
15
|
require 'alfred/engine'
|
16
|
+
require 'alfred/mass_assignment_security'
|
18
17
|
require 'alfred/orm/active_record' if defined?(ActiveRecord)
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Alfred
|
4
|
+
module ActiveModel
|
5
|
+
module MassAssignmentSecurity
|
6
|
+
module ClassMethods
|
7
|
+
# Attributes named in this macro are protected from mass-assignment
|
8
|
+
# whenever attributes are sanitized before assignment. A role for the
|
9
|
+
# attributes is optional, if no role is provided then :default is used.
|
10
|
+
# A role can be defined by using the :as option.
|
11
|
+
#
|
12
|
+
# Mass-assignment to these attributes will simply be ignored, to assign
|
13
|
+
# to them you can use direct writer methods. This is meant to protect
|
14
|
+
# sensitive attributes from being overwritten by malicious users
|
15
|
+
# tampering with URLs or forms. Example:
|
16
|
+
#
|
17
|
+
# class Customer
|
18
|
+
# include ActiveModel::MassAssignmentSecurity
|
19
|
+
# extend Alfred::ActiveModel::MassAssignmentSecurity
|
20
|
+
#
|
21
|
+
# attr_accessor :name, :credit_rating
|
22
|
+
#
|
23
|
+
# alfred_protected :credit_rating
|
24
|
+
# alfred_protected :last_login, as: :trainee
|
25
|
+
#
|
26
|
+
# def assign_attributes(values, options = {})
|
27
|
+
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
28
|
+
# send("#{k}=", v)
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# When using the :default role :
|
34
|
+
#
|
35
|
+
# customer = Customer.new
|
36
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
|
37
|
+
# customer.name # => "Daniel"
|
38
|
+
# customer.credit_rating # => nil
|
39
|
+
# customer.last_login # => nil
|
40
|
+
#
|
41
|
+
# customer.credit_rating = "Average"
|
42
|
+
# customer.credit_rating # => "Average"
|
43
|
+
#
|
44
|
+
# And using the :admin role :
|
45
|
+
#
|
46
|
+
# customer = Customer.new
|
47
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :trainee)
|
48
|
+
# customer.name # => "Daniel"
|
49
|
+
# customer.credit_rating # => "Excellent"
|
50
|
+
# customer.last_login # => nil
|
51
|
+
#
|
52
|
+
# To start from an all-closed default and enable attributes as needed,
|
53
|
+
# have a look at +alfred_accessible+.
|
54
|
+
#
|
55
|
+
# Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_protected+
|
56
|
+
# to sanitize attributes won't provide sufficient protection.
|
57
|
+
def alfred_protected(*args)
|
58
|
+
alfred(:protected, *args)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Specifies a white list of model attributes that can be set via
|
62
|
+
# mass-assignment.
|
63
|
+
#
|
64
|
+
# Like +alfred_protected+, a role for the attributes is optional,
|
65
|
+
# if no role is provided then :default is used. A role can be defined by
|
66
|
+
# using the :as option.
|
67
|
+
#
|
68
|
+
# This is the opposite of the +alfred_protected+ macro: Mass-assignment
|
69
|
+
# will only set attributes in this list, to assign to the rest of
|
70
|
+
# attributes you can use direct writer methods. This is meant to protect
|
71
|
+
# sensitive attributes from being overwritten by malicious users
|
72
|
+
# tampering with URLs or forms. If you'd rather start from an all-open
|
73
|
+
# default and restrict attributes as needed, have a look at
|
74
|
+
# +alfred_protected+.
|
75
|
+
#
|
76
|
+
# class Customer
|
77
|
+
# include ActiveModel::MassAssignmentSecurity
|
78
|
+
# extend Alfred::ActiveModel::MassAssignmentSecurity
|
79
|
+
#
|
80
|
+
# attr_accessor :name, :credit_rating
|
81
|
+
#
|
82
|
+
# alfred_accessible :name
|
83
|
+
# alfred_accessible :credit_rating, as: :admin
|
84
|
+
#
|
85
|
+
# def assign_attributes(values, options = {})
|
86
|
+
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
87
|
+
# send("#{k}=", v)
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# When using the :default role :
|
93
|
+
#
|
94
|
+
# customer = Customer.new
|
95
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :default)
|
96
|
+
# customer.name # => "Daniel"
|
97
|
+
# customer.credit_rating # => nil
|
98
|
+
#
|
99
|
+
# customer.credit_rating = "Average"
|
100
|
+
# customer.credit_rating # => "Average"
|
101
|
+
#
|
102
|
+
# And using the :admin role :
|
103
|
+
#
|
104
|
+
# customer = Customer.new
|
105
|
+
# customer.assign_attributes({ name: "Daniel", credit_rating: "Excellent", last_login: 1.day.ago }, as: :admin)
|
106
|
+
# customer.name # => "Daniel"
|
107
|
+
# customer.credit_rating # => "Excellent"
|
108
|
+
#
|
109
|
+
# Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +alfred_accessible+
|
110
|
+
# to sanitize attributes won't provide sufficient protection.
|
111
|
+
def alfred_accessible(*args)
|
112
|
+
alfred(:accessible, *args)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def alfred(method, *args)
|
117
|
+
options = args.extract_options!
|
118
|
+
|
119
|
+
if args.include?(:password) && Alfred.auto_password_confirmation
|
120
|
+
args = args + [:password_confirmation]
|
121
|
+
end
|
122
|
+
|
123
|
+
[nil, :create, :update].each do |action|
|
124
|
+
if options[:on]
|
125
|
+
next unless options[:on] == action
|
126
|
+
end
|
127
|
+
|
128
|
+
action_args = args.dup
|
129
|
+
|
130
|
+
role = (options[:as] || :default).to_s
|
131
|
+
role << "_#{action}" if action
|
132
|
+
role = role.to_sym
|
133
|
+
|
134
|
+
action_args = action_args + [{ as: role }]
|
135
|
+
|
136
|
+
action_args = action_args + send("#{method}_attributes", role).to_a.compact.reject { |s| s.blank? }
|
137
|
+
|
138
|
+
send("attr_#{method}", *action_args)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
include ClassMethods
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
module ActiveModel::MassAssignmentSecurity::ClassMethods
|
149
|
+
include Alfred::ActiveModel::MassAssignmentSecurity
|
150
|
+
end
|
@@ -1,3 +1,32 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
|
3
|
-
|
3
|
+
module Alfred
|
4
|
+
module ActiveRecord
|
5
|
+
module Base
|
6
|
+
def assign_attributes(new_attributes, options = {})
|
7
|
+
role = (options[:as] || :default).to_s
|
8
|
+
role << "_#{options[:action]}" if options[:action]
|
9
|
+
|
10
|
+
options[:as] = role.to_sym
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(attributes = nil, options = {})
|
16
|
+
options[:action] = :create
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_attributes(attributes, options = {})
|
22
|
+
options[:action] = :update
|
23
|
+
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class ActiveRecord::Base
|
31
|
+
include Alfred::ActiveRecord::Base
|
32
|
+
end
|
data/lib/alfred/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alfred
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,43 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-04-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 3.1.0
|
21
|
+
version: 3.1.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.1.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activemodel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
25
46
|
- !ruby/object:Gem::Dependency
|
26
47
|
name: activerecord
|
27
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
28
49
|
none: false
|
29
50
|
requirements:
|
30
51
|
- - ! '>='
|
@@ -32,10 +53,15 @@ dependencies:
|
|
32
53
|
version: '0'
|
33
54
|
type: :development
|
34
55
|
prerelease: false
|
35
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
36
62
|
- !ruby/object:Gem::Dependency
|
37
63
|
name: rr
|
38
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
39
65
|
none: false
|
40
66
|
requirements:
|
41
67
|
- - ! '>='
|
@@ -43,10 +69,15 @@ dependencies:
|
|
43
69
|
version: '0'
|
44
70
|
type: :development
|
45
71
|
prerelease: false
|
46
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
47
78
|
- !ruby/object:Gem::Dependency
|
48
79
|
name: rspec
|
49
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
50
81
|
none: false
|
51
82
|
requirements:
|
52
83
|
- - ! '>='
|
@@ -54,7 +85,12 @@ dependencies:
|
|
54
85
|
version: '0'
|
55
86
|
type: :development
|
56
87
|
prerelease: false
|
57
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
58
94
|
description: Alfred provides better attr_accessor handling on your application.
|
59
95
|
email:
|
60
96
|
- daniel.spangenberg@parcydo.com
|
@@ -64,16 +100,16 @@ extra_rdoc_files: []
|
|
64
100
|
files:
|
65
101
|
- .gitignore
|
66
102
|
- .rspec
|
67
|
-
- .rvmrc
|
68
103
|
- .travis.yml
|
69
104
|
- Gemfile
|
105
|
+
- README.textile
|
70
106
|
- Rakefile
|
71
107
|
- alfred.gemspec
|
72
108
|
- lib/alfred.rb
|
73
109
|
- lib/alfred/engine.rb
|
74
110
|
- lib/alfred/generators/alfred/install_generator.rb
|
75
111
|
- lib/alfred/generators/templates/alfred.rb
|
76
|
-
- lib/alfred/
|
112
|
+
- lib/alfred/mass_assignment_security.rb
|
77
113
|
- lib/alfred/orm/active_record.rb
|
78
114
|
- lib/alfred/version.rb
|
79
115
|
- spec/models_spec.rb
|
@@ -98,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
134
|
version: '0'
|
99
135
|
requirements: []
|
100
136
|
rubyforge_project: alfred
|
101
|
-
rubygems_version: 1.8.
|
137
|
+
rubygems_version: 1.8.21
|
102
138
|
signing_key:
|
103
139
|
specification_version: 3
|
104
140
|
summary: Alfred is the unobtrusive butler who takes care of the uninvited guests.
|
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm 1.9.2@alfred --create
|
data/lib/alfred/models.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
module Alfred
|
2
|
-
module Models
|
3
|
-
def alfred_accessible(*args)
|
4
|
-
alfred(:accessible, *args)
|
5
|
-
end
|
6
|
-
|
7
|
-
def alfred_protected(*args)
|
8
|
-
alfred(:protected, *args)
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def alfred(method, *args)
|
14
|
-
options = args.extract_options!
|
15
|
-
|
16
|
-
if options[:as]
|
17
|
-
if method == :accessible
|
18
|
-
args = args + accessible_attributes(options[:inherit] || :default).to_a
|
19
|
-
else
|
20
|
-
args = args + protected_attributes(options[:inherit] || :default).to_a
|
21
|
-
end
|
22
|
-
args = args + [{ as: options[:as] }]
|
23
|
-
end
|
24
|
-
|
25
|
-
if args.include?(:password) && Alfred.auto_password_confirmation
|
26
|
-
args = args + [:password_confirmation]
|
27
|
-
end
|
28
|
-
|
29
|
-
if options[:on] && [:create, :update].include?(options[:on])
|
30
|
-
if options[:on] == :create
|
31
|
-
before = :before_create
|
32
|
-
else
|
33
|
-
before = :before_update
|
34
|
-
end
|
35
|
-
if method == :accessible
|
36
|
-
self.class.send(:define_method, before) do
|
37
|
-
attr_accessible(*args)
|
38
|
-
end
|
39
|
-
else
|
40
|
-
self.class.send(:define_method, before) do
|
41
|
-
attr_protected(*args)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
else
|
45
|
-
if method == :accessible
|
46
|
-
attr_accessible(*args)
|
47
|
-
else
|
48
|
-
attr_protected(*args)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|