attr_encodable 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +143 -0
- data/lib/attr_encodable.rb +132 -0
- data/spec/attr_encodable_spec.rb +193 -0
- metadata +101 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Flip Sasser
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
attr_encodable
|
2
|
+
=
|
3
|
+
|
4
|
+
Never override `as_json` again! **attr_encodable** adds attribute black- or white-listing for ActiveRecord serialization, as well as default serialization options. This is especially useful for protecting private attributes when building a public API.
|
5
|
+
|
6
|
+
Install
|
7
|
+
==
|
8
|
+
|
9
|
+
Install using Rubygems:
|
10
|
+
|
11
|
+
gem install attr_encodable
|
12
|
+
|
13
|
+
Install using Bundler:
|
14
|
+
|
15
|
+
gem 'attr_encodable'
|
16
|
+
|
17
|
+
Install in Rails 2.x (in your environment.rb file)
|
18
|
+
|
19
|
+
config.gem 'attr_encodable'
|
20
|
+
|
21
|
+
Usage
|
22
|
+
==
|
23
|
+
|
24
|
+
White-listing
|
25
|
+
===
|
26
|
+
|
27
|
+
You can whitelist or blacklist attributes for serialization using the `attr_encodable` and `attr_unencodable` class methods. Let's look at an example. For this example, we'll use the following classes:
|
28
|
+
|
29
|
+
class User < ActiveRecord::Base
|
30
|
+
has_many :permissions
|
31
|
+
validates_presence_of :email, :password
|
32
|
+
|
33
|
+
def foobar
|
34
|
+
"baz"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Permission < ActiveRecord::Base
|
39
|
+
belongs_to :user
|
40
|
+
validates_presence_of :name, :user
|
41
|
+
|
42
|
+
def hello
|
43
|
+
"World!"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
... with the following schema:
|
48
|
+
|
49
|
+
create_table :permissions, :force => true do |t|
|
50
|
+
t.belongs_to :user
|
51
|
+
t.string :name
|
52
|
+
end
|
53
|
+
|
54
|
+
create_table :users, :force => true do |t|
|
55
|
+
t.string :login, :limit => 48
|
56
|
+
t.string :email, :limit => 128
|
57
|
+
t.string :name, :limit => 32
|
58
|
+
t.string :password, :limit => 60
|
59
|
+
t.boolean :admin, :default => false
|
60
|
+
end
|
61
|
+
|
62
|
+
Let's make a user and try encoding them:
|
63
|
+
|
64
|
+
@user = User.create(:name => "Flip", :email => "flip@x451.com", :password => "awesomesauce", :admin => true)
|
65
|
+
=> #<User id: 1, login: nil, email: "flip@x451.com", name: "Flip", password: "awesomesauce", admin: true>
|
66
|
+
@user.to_json
|
67
|
+
=> {"name":"Flip","admin":true,"id":1,"password":"awesomesauce","login":null,"email":"flip@x451.com"}
|
68
|
+
|
69
|
+
Trouble is, we don't want their admin status OR their password coming through in our API. So why not protect their information a little bit?
|
70
|
+
|
71
|
+
User.attr_encodable :id, :name, :login, :email
|
72
|
+
@user.to_json
|
73
|
+
=> {"name":"Flip","id":1,"login":null,"email":"flip@x451.com"}
|
74
|
+
|
75
|
+
Ah, that's so much better! Now whenever we encode a user instance we'll be showing only some default information.
|
76
|
+
|
77
|
+
`attr_unencodable` is similar, except that it bans an attribute. Following along with the example above, if we then called `attr_unencodable`, we could
|
78
|
+
restrict our user's information even more. Let's say I don't want my e-mail getting out:
|
79
|
+
|
80
|
+
User.attr_unencodable :email
|
81
|
+
@user.to_json
|
82
|
+
=> {"name":"Flip","id":1,"login":null}
|
83
|
+
|
84
|
+
Alright! Now you can't see my e-mail. Sucker.
|
85
|
+
|
86
|
+
Default `:include` and `:method` options
|
87
|
+
===
|
88
|
+
|
89
|
+
`to_json` isn't just concerned with attributes. It also supports `:include`, which includes a relationship with `to_json` called on **it**, as well `:methods`, which adds the result of calling methods on the instance as well.
|
90
|
+
|
91
|
+
Let's try it out.
|
92
|
+
|
93
|
+
User.attr_encodable :foobar
|
94
|
+
@user.to_json
|
95
|
+
=> {"name":"Flip","foobar":"baz","id":1,"login":null}
|
96
|
+
|
97
|
+
With includes, our example might look like this:
|
98
|
+
|
99
|
+
class User < ActiveRecord::Base
|
100
|
+
attr_encodable :id, :name, :login, :permissions
|
101
|
+
has_many :permissions
|
102
|
+
end
|
103
|
+
|
104
|
+
@user.to_json
|
105
|
+
=> {"name":"Flip","foobar":"baz","id":1,"login":null,"permissions":[]}
|
106
|
+
|
107
|
+
Neato! And of course, when `:permissions` is serialized, it will take into account any `attr_encodable` settings the Permissions class has!
|
108
|
+
|
109
|
+
Renaming Attributes
|
110
|
+
===
|
111
|
+
|
112
|
+
Sometimes you don't want an attribute to come out in JSON named what it's named in the database. There are two options you can pursue here.
|
113
|
+
|
114
|
+
Prefix it!
|
115
|
+
====
|
116
|
+
|
117
|
+
**attr_encodable** supports prefixing of attribute names. Just pass an options hash onto the end of the method with a :prefix key and you're good to go. Example:
|
118
|
+
|
119
|
+
class User < ActiveRecord::Base
|
120
|
+
attr_encodable :ed, :prefix => :i_will_hunt
|
121
|
+
end
|
122
|
+
|
123
|
+
@user.to_json
|
124
|
+
=> {"i_will_hunt_ed":true}
|
125
|
+
|
126
|
+
Rename it completely!
|
127
|
+
====
|
128
|
+
|
129
|
+
If you don't want to prefix, just rename the whole damn thing:
|
130
|
+
|
131
|
+
class User < ActiveRecord::Base
|
132
|
+
attr_encodable :admin => :superuser
|
133
|
+
end
|
134
|
+
|
135
|
+
@user.to_json
|
136
|
+
#=> {"superuser":true}
|
137
|
+
|
138
|
+
Renaming and prefixing work for any `:include` and `:methods` arguments you pass in as well!
|
139
|
+
|
140
|
+
Okay, that's all. Thanks for stopping by.
|
141
|
+
|
142
|
+
Copyright © 2011 Flip Sasser
|
143
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Encodable
|
4
|
+
module ClassMethods
|
5
|
+
def attr_encodable(*attributes)
|
6
|
+
prefix = begin
|
7
|
+
if attributes.last.is_a?(Hash)
|
8
|
+
attributes.last.assert_valid_keys(:prefix)
|
9
|
+
prefix = attributes.extract_options![:prefix]
|
10
|
+
end
|
11
|
+
rescue ArgumentError
|
12
|
+
end
|
13
|
+
unless @encodable_whitelist_started
|
14
|
+
# Since we're white-listing, make sure we black-list every attribute to begin with
|
15
|
+
unencodable_attributes.push *column_names.map(&:to_sym)
|
16
|
+
@encodable_whitelist_started = true
|
17
|
+
end
|
18
|
+
stash_encodable_attribute = lambda {|method, value|
|
19
|
+
if prefix
|
20
|
+
value = "#{prefix}_#{value}"
|
21
|
+
end
|
22
|
+
method = method.to_sym
|
23
|
+
value = value.to_sym
|
24
|
+
renamed_encoded_attributes.merge!({method => value}) if method != value
|
25
|
+
# Un-black-list any attribute we white-listed
|
26
|
+
unencodable_attributes.delete method
|
27
|
+
default_attributes.push method
|
28
|
+
}
|
29
|
+
attributes.each do |attribute|
|
30
|
+
if attribute.is_a?(Hash)
|
31
|
+
attribute.each do |method, value|
|
32
|
+
stash_encodable_attribute.call(method, value)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
stash_encodable_attribute.call(attribute, attribute)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def attr_unencodable(*attributes)
|
41
|
+
unencodable_attributes.push *attributes.map(&:to_sym)
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_attributes
|
45
|
+
@default_attributes ||= begin
|
46
|
+
default_attributes = []
|
47
|
+
superk = superclass
|
48
|
+
while superk.respond_to?(:default_attributes)
|
49
|
+
default_attributes.push(*superk.default_attributes)
|
50
|
+
superk = superk.superclass
|
51
|
+
end
|
52
|
+
default_attributes
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def renamed_encoded_attributes
|
57
|
+
@renamed_encoded_attributes ||= begin
|
58
|
+
renamed_encoded_attributes = {}
|
59
|
+
superk = superclass
|
60
|
+
while superk.respond_to?(:renamed_encoded_attributes)
|
61
|
+
renamed_encoded_attributes.merge!(superk.renamed_encoded_attributes)
|
62
|
+
superk = superk.superclass
|
63
|
+
end
|
64
|
+
renamed_encoded_attributes
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def unencodable_attributes
|
69
|
+
@unencodable_attributes ||= begin
|
70
|
+
unencodable_attributes = []
|
71
|
+
superk = superclass
|
72
|
+
while superk.respond_to?(:unencodable_attributes)
|
73
|
+
unencodable_attributes.push(*superk.unencodable_attributes)
|
74
|
+
superk = superk.superclass
|
75
|
+
end
|
76
|
+
unencodable_attributes
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module InstanceMethods
|
82
|
+
def serializable_hash(options = {})
|
83
|
+
if options && options[:only]
|
84
|
+
# We DON'T want to fuck with :only and :except showing up in the same call. This is a disaster.
|
85
|
+
super
|
86
|
+
else
|
87
|
+
options ||= {}
|
88
|
+
original_except = if options[:except]
|
89
|
+
options[:except] = Array(options[:except]).map(&:to_sym)
|
90
|
+
else
|
91
|
+
options[:except] = []
|
92
|
+
end
|
93
|
+
# This is a little bit confusing. ActiveRecord's default behavior is to apply the :except arguments you pass
|
94
|
+
# in to any :include options UNLESS it's overridden on the :include option. In the event that we have some
|
95
|
+
# *default* excepts that come from Encodable, we want to ignore those and pass only whatever the original
|
96
|
+
# :except options from the user were on down to the :include guys.
|
97
|
+
inherited_except = original_except - self.class.default_attributes
|
98
|
+
case options[:include]
|
99
|
+
when Array, Symbol
|
100
|
+
# Convert includes arrays or singleton symbols into a hash with our original_except scope
|
101
|
+
includes = Array(options[:include])
|
102
|
+
options[:include] = Hash[*includes.map{|association| [association, {:except => inherited_except}]}.flatten]
|
103
|
+
else
|
104
|
+
options[:include] ||= {}
|
105
|
+
end
|
106
|
+
# Exclude the black-list
|
107
|
+
options[:except].push *self.class.unencodable_attributes
|
108
|
+
# Include any default :include or :methods arguments that were passed in earlier
|
109
|
+
self.class.default_attributes.each do |attribute, as|
|
110
|
+
if association = self.class.reflect_on_association(attribute)
|
111
|
+
options[:include][attribute] = {:except => inherited_except}
|
112
|
+
elsif respond_to?(attribute) && !self.class.column_names.include?(attribute.to_s)
|
113
|
+
options[:methods] ||= Array(options[:methods]).compact
|
114
|
+
options[:methods].push attribute
|
115
|
+
end
|
116
|
+
end
|
117
|
+
as_json = super(options)
|
118
|
+
unless self.class.renamed_encoded_attributes.empty?
|
119
|
+
self.class.renamed_encoded_attributes.each do |attribute, as|
|
120
|
+
as_json[as.to_s] = as_json.delete(attribute) || as_json.delete(attribute.to_s)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
as_json
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
if defined? ActiveRecord::Base
|
130
|
+
ActiveRecord::Base.extend Encodable::ClassMethods
|
131
|
+
ActiveRecord::Base.send(:include, Encodable::InstanceMethods)
|
132
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require "lib/attr_encodable"
|
2
|
+
|
3
|
+
describe Encodable do
|
4
|
+
it "should automatically extend ActiveRecord::Base" do
|
5
|
+
ActiveRecord::Base.should respond_to(:attr_encodable)
|
6
|
+
ActiveRecord::Base.should respond_to(:attr_unencodable)
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
ActiveRecord::Base.include_root_in_json = false
|
11
|
+
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:', :pool => 5, :timeout => 5000})
|
12
|
+
class ::Permission < ActiveRecord::Base; belongs_to :user; def hello; "World!"; end; end
|
13
|
+
class ::User < ActiveRecord::Base; has_many :permissions; def foobar; "baz"; end; end
|
14
|
+
silence_stream(STDOUT) do
|
15
|
+
ActiveRecord::Schema.define do
|
16
|
+
create_table :permissions, :force => true do |t|
|
17
|
+
t.belongs_to :user
|
18
|
+
t.string :name
|
19
|
+
end
|
20
|
+
create_table :users, :force => true do |t|
|
21
|
+
t.string "login", :limit => 48
|
22
|
+
t.string "email", :limit => 128
|
23
|
+
t.string "first_name", :limit => 32
|
24
|
+
t.string "last_name", :limit => 32
|
25
|
+
t.string "encrypted_password", :limit => 60
|
26
|
+
t.boolean "developer", :default => false
|
27
|
+
t.boolean "admin", :default => false
|
28
|
+
t.boolean "password_set", :default => true
|
29
|
+
t.boolean "verified", :default => false
|
30
|
+
t.datetime "created_at"
|
31
|
+
t.datetime "updated_at"
|
32
|
+
t.integer "notifications"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@user = User.create({
|
37
|
+
:login => "flipsasser",
|
38
|
+
:first_name => "flip",
|
39
|
+
:last_name => "sasser",
|
40
|
+
:email => "flip@foobar.com",
|
41
|
+
:encrypted_password => ActiveSupport::SecureRandom.hex(30),
|
42
|
+
:developer => true,
|
43
|
+
:admin => true,
|
44
|
+
:password_set => true,
|
45
|
+
:verified => true,
|
46
|
+
:notifications => 7
|
47
|
+
})
|
48
|
+
@user.permissions.create(:name => "create_blog_posts")
|
49
|
+
@user.permissions.create(:name => "edit_blog_posts")
|
50
|
+
# Reset the options for each test
|
51
|
+
[Permission, User].each do |klass|
|
52
|
+
|
53
|
+
klass.class_eval do
|
54
|
+
@default_attributes = nil
|
55
|
+
@encodable_whitelist_started = nil
|
56
|
+
@renamed_encoded_attributes = nil
|
57
|
+
@unencodable_attributes = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should favor whitelisting to blacklisting" do
|
63
|
+
User.unencodable_attributes.should == []
|
64
|
+
User.attr_unencodable 'foo', 'bar', 'baz'
|
65
|
+
User.unencodable_attributes.should == [:foo, :bar, :baz]
|
66
|
+
User.attr_encodable :id, :first_name
|
67
|
+
User.unencodable_attributes.map(&:to_s).should == ['foo', 'bar', 'baz'] + User.column_names - ['id', 'first_name']
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "at the parent model level" do
|
71
|
+
it "should not mess with to_json unless when attr_encodable and attr_unencodable are not set" do
|
72
|
+
@user.as_json == @user.attributes
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not mess with :include options" do
|
76
|
+
@user.as_json(:include => :permissions) == @user.attributes.merge(:permissions => @user.permissions.as_json)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should not mess with :methods options" do
|
80
|
+
@user.as_json(:methods => :foobar) == @user.attributes.merge(:foobar => "baz")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should allow me to whitelist attributes" do
|
84
|
+
User.attr_encodable :login, :first_name, :last_name
|
85
|
+
@user.as_json.should == @user.attributes.slice('login', 'first_name', 'last_name')
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should allow me to blacklist attributes" do
|
89
|
+
User.attr_unencodable :login, :first_name, :last_name
|
90
|
+
@user.as_json.should == @user.attributes.except('login', 'first_name', 'last_name')
|
91
|
+
end
|
92
|
+
|
93
|
+
# Of note is the INSANITY of ActiveRecord in that it applies :only / :except to :include as well. Which is
|
94
|
+
# obviously insane. Similarly, it doesn't allow :methods to come along when :only is specified. Good god, what
|
95
|
+
# a shame.
|
96
|
+
it "should allow me to whitelist attributes without messing with :include" do
|
97
|
+
User.attr_encodable :login, :first_name, :last_name
|
98
|
+
@user.as_json(:include => :permissions).should == @user.attributes.slice('login', 'first_name', 'last_name').merge(:permissions => @user.permissions.as_json)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should allow me to blacklist attributes without messing with :include and :methods" do
|
102
|
+
User.attr_unencodable :login, :first_name, :last_name
|
103
|
+
@user.as_json(:include => :permissions, :methods => :foobar).should == @user.attributes.except('login', 'first_name', 'last_name').merge(:permissions => @user.permissions.as_json, :foobar => "baz")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should not screw with :include if it's a hash" do
|
107
|
+
User.attr_unencodable :login, :first_name, :last_name
|
108
|
+
@user.as_json(:include => {:permissions => {:methods => :hello, :except => :id}}, :methods => :foobar).should == @user.attributes.except('login', 'first_name', 'last_name').merge(:permissions => @user.permissions.as_json(:methods => :hello, :except => :id), :foobar => "baz")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "at the child model level when the paren model has attr_encodable set" do
|
113
|
+
before :each do
|
114
|
+
User.attr_encodable :login, :first_name, :last_name
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should not mess with to_json unless when attr_encodable and attr_unencodable are not set on the child, but are on the parent" do
|
118
|
+
@user.permissions.as_json == @user.permissions.map(&:attributes)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not mess with :include options" do
|
122
|
+
# This is testing that the implicit ban on the :id attribute from User.attr_encodable is not
|
123
|
+
# applying to serialization of permissions
|
124
|
+
@user.as_json(:include => :permissions)[:permissions].first['id'].should_not be_nil
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should inherit any attr_encodable options from the child model" do
|
128
|
+
User.attr_encodable :id
|
129
|
+
Permission.attr_encodable :name
|
130
|
+
as_json = @user.as_json(:include => :permissions)
|
131
|
+
as_json[:permissions].first['id'].should be_nil
|
132
|
+
as_json['id'].should_not be_nil
|
133
|
+
end
|
134
|
+
|
135
|
+
# it "should allow me to whitelist attributes" do
|
136
|
+
# User.attr_encodable :login, :first_name, :last_name
|
137
|
+
# @user.as_json.should == @user.attributes.slice('login', 'first_name', 'last_name')
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# it "should allow me to blacklist attributes" do
|
141
|
+
# User.attr_unencodable :login, :first_name, :last_name
|
142
|
+
# @user.as_json.should == @user.attributes.except('login', 'first_name', 'last_name')
|
143
|
+
# end
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should let me specify automatic includes as well as attributes" do
|
147
|
+
User.attr_encodable :login, :first_name, :id, :permissions
|
148
|
+
@user.as_json.should == @user.attributes.slice('login', 'first_name', 'id').merge(:permissions => @user.permissions.as_json)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should let me specify methods as well as attributes" do
|
152
|
+
User.attr_encodable :login, :first_name, :id, :foobar
|
153
|
+
@user.as_json.should == @user.attributes.slice('login', 'first_name', 'id').merge(:foobar => "baz")
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "reassigning" do
|
157
|
+
it "should let me reassign attributes" do
|
158
|
+
User.attr_encodable :id => :identifier
|
159
|
+
@user.as_json.should == {'identifier' => @user.id}
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should let me reassign attributes alongside regular attributes" do
|
163
|
+
User.attr_encodable :login, :last_name, :id => :identifier
|
164
|
+
@user.as_json.should == {'identifier' => 1, 'login' => 'flipsasser', 'last_name' => 'sasser'}
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should let me reassign multiple attributes with one delcaration" do
|
168
|
+
User.attr_encodable :id => :identifier, :first_name => :foobar
|
169
|
+
@user.as_json.should == {'identifier' => 1, 'foobar' => 'flip'}
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should let me reassign :methods" do
|
173
|
+
User.attr_encodable :foobar => :w00t
|
174
|
+
@user.as_json.should == {'w00t' => 'baz'}
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should let me reassign :include" do
|
178
|
+
User.attr_encodable :permissions => :deez_permissions
|
179
|
+
@user.as_json.should == {'deez_permissions' => @user.permissions.as_json}
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should let me specify a prefix to a set of attr_encodable's" do
|
183
|
+
User.attr_encodable :id, :first_name, :foobar, :permissions, :prefix => :t
|
184
|
+
@user.as_json.should == {'t_id' => @user.id, 't_first_name' => @user.first_name, 't_foobar' => 'baz', 't_permissions' => @user.permissions.as_json}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should propagate down subclasses as well" do
|
189
|
+
User.attr_encodable :name
|
190
|
+
class SubUser < User; end
|
191
|
+
SubUser.unencodable_attributes.should == User.unencodable_attributes
|
192
|
+
end
|
193
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attr_encodable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Flip Sasser
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-07-15 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rcov
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 41
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 9
|
33
|
+
- 9
|
34
|
+
version: 0.9.9
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 0
|
49
|
+
version: "2.0"
|
50
|
+
type: :development
|
51
|
+
version_requirements: *id002
|
52
|
+
description: "\n attr_encodable enables you to set up defaults for what is included or excluded when you serialize an ActiveRecord object. This is especially useful for protecting private attributes when building a public API.\n "
|
53
|
+
email: flip@x451.com
|
54
|
+
executables: []
|
55
|
+
|
56
|
+
extensions: []
|
57
|
+
|
58
|
+
extra_rdoc_files:
|
59
|
+
- LICENSE
|
60
|
+
- README.md
|
61
|
+
files:
|
62
|
+
- LICENSE
|
63
|
+
- README.md
|
64
|
+
- lib/attr_encodable.rb
|
65
|
+
- spec/attr_encodable_spec.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/Plinq/attr_encodable
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.6.2
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: An attribute black- or white-list for ActiveRecord serialization
|
100
|
+
test_files:
|
101
|
+
- spec/attr_encodable_spec.rb
|