tableless_model 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +26 -2
- data/lib/activerecord/base/class_methods.rb +22 -12
- data/lib/tableless_model.rb +2 -0
- data/lib/tableless_model/version.rb +1 -1
- data/spec/encryption_spec.rb +35 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/tableless_model_spec.rb +1 -4
- metadata +6 -4
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Tableless Model is available as a Rubygem:
|
|
22
22
|
gem install tableless_model
|
23
23
|
```
|
24
24
|
|
25
|
-
|
25
|
+
## Usage
|
26
26
|
|
27
27
|
For example's sake, say we have these two models:
|
28
28
|
|
@@ -204,6 +204,24 @@ For boolean attributes (or also truthy/falsy ones) you can also make calls to sp
|
|
204
204
|
=> true
|
205
205
|
```
|
206
206
|
|
207
|
+
## Encryption
|
208
|
+
|
209
|
+
If for some reason you'd like to encrypt the data serialised with the tableless model, so that it cannot be read in clear when looking directly at the contents of the database, you can enable encryption by simply specifying an encryption key:
|
210
|
+
|
211
|
+
``` ruby
|
212
|
+
class SomeModel < ActiveRecord::Base
|
213
|
+
|
214
|
+
has_tableless :seo => EncryptedTablelessModel, :encryption_key => "a398bbfaac38c79e60a6e398efba8571"
|
215
|
+
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
In the database, the encrypted tableless model will look similar to this:
|
220
|
+
|
221
|
+
``` ruby
|
222
|
+
Fxq8TU8syHgWBk1ndGt6U5pXZDbDVs3+lLFcxWkvc3b9OONp02RBf+vkmwl2O5VIZpPVqkMiM3Y3zsv5B2N9sXP1eb7Erskq5T3A3oclHoiXvvPizbKbe0T+pulUdbd+GWka8UYHT1FE/vRNAb6o+F83plL6m8ctWTWafM/skqzVXing1FBqpK0Iv+9H8cK3rOjdxdaWT4RMqvRG//MAsAl8gBor2dIdwbg2iap9j42JYSqua8RlGuPKzr/I4dwSYYO1ldg+gDYHRXLIJ//law==--ohQLUAuE4RU+btUyOibx7g==
|
223
|
+
```
|
224
|
+
|
207
225
|
|
208
226
|
## Validations
|
209
227
|
|
@@ -266,7 +284,13 @@ x.valid?
|
|
266
284
|
|
267
285
|
## Change log
|
268
286
|
|
269
|
-
|
287
|
+
26.07.2011
|
288
|
+
- Added support for encryption
|
289
|
+
|
290
|
+
24.07.2011
|
291
|
+
- Added support for passing Proc/lamba when defining the default attribute of a value
|
292
|
+
- Added shortcuts to call getters/setters of attributes defined in a tableless model, from
|
293
|
+
its parent model directly
|
270
294
|
|
271
295
|
## License
|
272
296
|
|
@@ -14,42 +14,50 @@ module Base
|
|
14
14
|
#
|
15
15
|
# class Parent < ActiveRecord::Base
|
16
16
|
#
|
17
|
-
# has_tableless :settings
|
17
|
+
# has_tableless :settings => ParentSettings
|
18
18
|
#
|
19
19
|
# # or...
|
20
20
|
#
|
21
|
-
# has_tableless :settings => ParentSettings
|
21
|
+
# has_tableless :settings => ParentSettings, :encryption_key => "secret"
|
22
22
|
#
|
23
23
|
# end
|
24
24
|
#
|
25
25
|
#
|
26
26
|
# NOTE: the serialized column is expected to be of type string or text in the database
|
27
|
-
#
|
28
27
|
def has_tableless(column)
|
29
|
-
|
28
|
+
encryption_key = column.delete(:encryption_key)
|
29
|
+
|
30
|
+
column_name, class_type = column.to_a.flatten
|
30
31
|
|
31
32
|
@tableless_models ||= []
|
32
33
|
@tableless_models << column_name
|
33
34
|
|
34
35
|
|
35
|
-
# if only the column name is given, the tableless model's class is expected to have that name, classified, as class name
|
36
|
-
class_type = column.class == Hash ? column.collect{|k,v| v}.last : column.to_s.classify.constantize
|
37
|
-
|
38
|
-
|
39
36
|
# injecting in the parent object a getter and a setter for the
|
40
37
|
# attribute that will store an instance of a tableless model
|
41
38
|
class_eval do
|
42
39
|
|
43
40
|
# Telling AR that the column has to store an instance of the given tableless model in
|
44
|
-
# YAML serialized format
|
45
|
-
|
41
|
+
# YAML serialized format; if encryption is enabled, then serialisation/deserialisation will
|
42
|
+
# be handled when encrypting/decrypting, rather than automatically by ActiveRecord,
|
43
|
+
# otherwise the different object id would cause a different serialisation string each time
|
44
|
+
|
45
|
+
serialize column_name unless encryption_key
|
46
46
|
|
47
47
|
# Adding getter for the serialized column,
|
48
48
|
# making sure it always returns an instance of the specified tableless
|
49
49
|
# model and not just a normal hash or the value of the attribute in the database,
|
50
50
|
# which is plain text
|
51
51
|
define_method column_name.to_s do
|
52
|
-
|
52
|
+
serialised = read_attribute(column_name)
|
53
|
+
|
54
|
+
value = if encryption_key
|
55
|
+
serialised ? YAML::load(ActiveSupport::MessageEncryptor.new(encryption_key).decrypt(serialised)) : serialised
|
56
|
+
else
|
57
|
+
serialised || {}
|
58
|
+
end
|
59
|
+
|
60
|
+
instance = class_type.new(value)
|
53
61
|
|
54
62
|
instance.__owner_object = self
|
55
63
|
instance.__serialized_attribute = column_name
|
@@ -61,7 +69,9 @@ module Base
|
|
61
69
|
# making sure it always stores in it an instance of
|
62
70
|
# the specified tableless model (as the argument may also be a regular hash)
|
63
71
|
define_method "#{column_name.to_s}=" do |value|
|
64
|
-
|
72
|
+
v = class_type.new(value)
|
73
|
+
v = encryption_key ? ActiveSupport::MessageEncryptor.new(encryption_key).encrypt(YAML::dump(v)) : v
|
74
|
+
super v
|
65
75
|
end
|
66
76
|
end
|
67
77
|
end
|
data/lib/tableless_model.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class ModelSettings < ActiveRecord::TablelessModel
|
4
|
+
attribute :some_attribute, :default => "default value"
|
5
|
+
end
|
6
|
+
|
7
|
+
class SomeModel < ActiveRecord::Base
|
8
|
+
has_tableless :settings => ModelSettings, :encryption_key => "a398bbfaac38c79e60a6e398efba8571"
|
9
|
+
end
|
10
|
+
|
11
|
+
describe SomeModel do
|
12
|
+
context "when an encryption key has been specified for the tableless-based column" do
|
13
|
+
let(:mock_encryptor) { mock(ActiveSupport::MessageEncryptor).as_null_object }
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
ActiveSupport::MessageEncryptor.stub(:new).with("a398bbfaac38c79e60a6e398efba8571").and_return(mock_encryptor)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "encrypts a tableless-based attribute when writing its attribute" do
|
20
|
+
mock_encryptor.stub(:encrypt).and_return("encrypted...")
|
21
|
+
|
22
|
+
subject.settings = ModelSettings.new(:some_attribute => "non default value")
|
23
|
+
subject.read_attribute("settings").should == "encrypted..."
|
24
|
+
end
|
25
|
+
|
26
|
+
it "descripts a tableless-based attribute when reading its attribute" do
|
27
|
+
mock_result = { :some_attribute => "bla bla bla" }
|
28
|
+
|
29
|
+
subject.should_receive(:read_attribute).with(:settings).and_return("encrypted...")
|
30
|
+
mock_encryptor.stub(:decrypt).with("encrypted...").and_return("serialised...")
|
31
|
+
YAML.should_receive(:load).with("serialised...").and_return(mock_result)
|
32
|
+
subject.settings.should == mock_result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,3 +5,8 @@ require "active_record"
|
|
5
5
|
require "timecop"
|
6
6
|
require "tableless_model"
|
7
7
|
|
8
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
9
|
+
ActiveRecord::Base.connection.execute(" create table test_models (id integer, options varchar(50)) ")
|
10
|
+
ActiveRecord::Base.connection.execute(" create table some_models (id integer, settings varchar(50)) ")
|
11
|
+
|
12
|
+
|
@@ -1,8 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
4
|
-
ActiveRecord::Base.connection.execute(" create table test_models (id integer, options varchar(50)) ")
|
5
|
-
|
6
3
|
class ModelOptions < ActiveRecord::TablelessModel
|
7
4
|
attribute :no_default_value_no_type_attribute
|
8
5
|
attribute :no_default_value_typed_attribute, :type => :integer
|
@@ -112,7 +109,7 @@ describe TestModel do
|
|
112
109
|
end
|
113
110
|
end
|
114
111
|
end
|
115
|
-
|
112
|
+
|
116
113
|
describe "#options" do
|
117
114
|
it "is an instance of the tableless model" do
|
118
115
|
options.should be_instance_of ModelOptions
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tableless_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 9
|
10
|
+
version: 0.0.9
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Vito Botta
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-26 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- lib/tableless_model/class_methods.rb
|
111
111
|
- lib/tableless_model/instance_methods.rb
|
112
112
|
- lib/tableless_model/version.rb
|
113
|
+
- spec/encryption_spec.rb
|
113
114
|
- spec/spec_helper.rb
|
114
115
|
- spec/tableless_model_spec.rb
|
115
116
|
- tableless_model.gemspec
|
@@ -148,5 +149,6 @@ signing_key:
|
|
148
149
|
specification_version: 3
|
149
150
|
summary: A serialisable and validatable table-less model with support for associations, useful to store settings, options, etc in a serialized form in a parent object
|
150
151
|
test_files:
|
152
|
+
- spec/encryption_spec.rb
|
151
153
|
- spec/spec_helper.rb
|
152
154
|
- spec/tableless_model_spec.rb
|