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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tableless_model (0.0.7)
4
+ tableless_model (0.0.9)
5
5
  validatable
6
6
 
7
7
  GEM
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
- == Usage
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
- 24.07.2011 - Added support for passing Proc/lamba when defining the default attribute of a value
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
- column_name = column.class == Hash ? column.collect{|k,v| k}.first.to_sym : column
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
- serialize column_name
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
- instance = class_type.new(read_attribute(column_name.to_sym) || {})
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
- super class_type.new(value)
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
@@ -1,6 +1,8 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
 
3
3
  require "validatable"
4
+ require "active_record"
5
+ require "active_support"
4
6
  require "activerecord/base/class_methods"
5
7
  require "activerecord/base/instance_methods"
6
8
  require "tableless_model/class_methods"
@@ -1,3 +1,3 @@
1
1
  module TablelessModel
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -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: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 8
10
- version: 0.0.8
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-24 00:00:00 +01:00
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