mcfly 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -89,9 +89,14 @@ TODO: discuss using `current_user` method in `ApplicationController`. Also, sett
89
89
 
90
90
  TODO
91
91
 
92
- ## Limitations
92
+ ## Limitations/Requirements
93
93
 
94
- Currently, Mcfly only works with PostgreSQL databases.
94
+ Currently, Mcfly only works with PostgreSQL databases. The following
95
+ line must be added to the `postgresql.conf` file. Mcfly uses the
96
+ PostgreSQL session variable `mcfly.whodunnit` to store the current
97
+ user id.
98
+
99
+ custom_variable_classes = 'mcfly'
95
100
 
96
101
  ## History
97
102
 
data/lib/mcfly.rb CHANGED
@@ -12,6 +12,9 @@ module Mcfly
12
12
  # with models directly.
13
13
  def self.whodunnit=(value)
14
14
  mcfly_store[:whodunnit] = value
15
+
16
+ sval = value.try(:id) || -1
17
+ ActiveRecord::Base.connection.execute("SET mcfly.whodunnit = #{sval};")
15
18
  end
16
19
 
17
20
  def self.whodunnit
@@ -2,12 +2,18 @@ CREATE OR REPLACE FUNCTION "%{table}_delete" ()
2
2
  RETURNS TRIGGER
3
3
  AS $$
4
4
 
5
+ DECLARE
6
+ whodunnit int;
7
+
5
8
  BEGIN
6
9
  IF OLD.obsoleted_dt <> 'infinity' THEN
7
10
  RAISE EXCEPTION 'can not delete old row version';
8
11
  END IF;
9
12
 
10
- UPDATE "%{table}" SET "obsoleted_dt" = 'now()' WHERE id = OLD.id;
13
+ SHOW mcfly.whodunnit INTO whodunnit;
14
+
15
+ UPDATE "%{table}"
16
+ SET "obsoleted_dt" = 'now()', "o_user_id" = whodunnit WHERE id = OLD.id;
11
17
 
12
18
  RETURN NULL; -- the row is not actually deleted
13
19
  END;
@@ -32,11 +32,14 @@ module McFly
32
32
  # obsoleted_dt.
33
33
 
34
34
  send :include, InstanceMethods
35
- after_initialize :record_init
35
+ before_validation :record_validation
36
+
36
37
  # FIXME: :created_dt should also be readonly. However, we set
37
38
  # it for debugging purposes. Should consider making this
38
- # readonly once we're in production.
39
- attr_readonly :group_id, :obsoleted_dt, :user_id
39
+ # readonly once we're in production. Also, :user_id should be
40
+ # read-only. We should only set whodunnit and let PostgreSQL
41
+ # set it.
42
+ attr_readonly :group_id, :obsoleted_dt, :o_user_id #, :user_id
40
43
  end
41
44
 
42
45
  def mcfly_lookup(name, options = {}, &block)
@@ -78,11 +81,12 @@ module McFly
78
81
  end
79
82
 
80
83
  module InstanceMethods
81
- def record_init
82
- # Set obsoleted_dt to non NIL to ensure constraints are properly
83
- # constructed
84
- self.obsoleted_dt = 'infinity' unless self.obsoleted_dt
85
- self.user_id ||= Mcfly.whodunnit.try(:id)
84
+ def record_validation
85
+ if self.changed?
86
+ self.user_id = Mcfly.whodunnit.try(:id)
87
+ self.obsoleted_dt ||= 'infinity'
88
+ end
89
+
86
90
  end
87
91
  end
88
92
 
@@ -25,3 +25,8 @@ $$ LANGUAGE plpgsql;
25
25
  DROP TRIGGER IF EXISTS %{table}_insert ON %{table};
26
26
  CREATE TRIGGER "%{table}_insert" BEFORE INSERT ON "%{table}" FOR EACH ROW
27
27
  EXECUTE PROCEDURE "%{table}_insert"();
28
+
29
+ -- Add constraint to make sure o_user_id is set iff obsoleted_dt is
30
+ -- not infinity (i.e. object is obsoleted).
31
+ ALTER TABLE "%{table}" ADD CONSTRAINT check_o_user
32
+ CHECK ((obsoleted_dt = 'Infinity') = (o_user_id IS NULL));
@@ -14,6 +14,7 @@ class McFlyMigration < ActiveRecord::Migration
14
14
  t.timestamp :created_dt, null: false
15
15
  t.timestamp :obsoleted_dt, null: false
16
16
  t.references :user, null: false
17
+ t.references :o_user
17
18
  block.call(t)
18
19
  }
19
20
 
@@ -13,6 +13,7 @@ BEGIN
13
13
  -- ignored. This is used by DELETE.
14
14
  IF NEW.obsoleted_dt <> 'infinity' THEN
15
15
  OLD.obsoleted_dt = NEW.obsoleted_dt;
16
+ OLD.o_user_id = NEW.o_user_id;
16
17
  return OLD;
17
18
  END IF;
18
19
 
@@ -5,6 +5,7 @@ DECLARE
5
5
  rec "%{table}";
6
6
  new_id INT4;
7
7
  now timestamp;
8
+ whodunnit int;
8
9
 
9
10
  BEGIN
10
11
  IF OLD.obsoleted_dt <> 'infinity' THEN
@@ -15,6 +16,7 @@ BEGIN
15
16
  -- obsoleted. We return the OLD row so that other field updates are
16
17
  -- ignored. This is used by DELETE.
17
18
  IF NEW.obsoleted_dt <> 'infinity' THEN
19
+ OLD.o_user_id = NEW.o_user_id;
18
20
  OLD.obsoleted_dt = NEW.obsoleted_dt;
19
21
  return OLD;
20
22
  END IF;
@@ -31,7 +33,8 @@ BEGIN
31
33
 
32
34
  rec.id = new_id;
33
35
  rec.group_id = NEW.id;
34
-
36
+ rec.o_user_id = NEW.user_id;
37
+
35
38
  -- FIXME: The following IF/ELSE handles cases where created_dt is
36
39
  -- sent in on update. This is only useful for debugging. Consider
37
40
  -- removing the surronding IF (and ELSE part) for production
data/lib/mcfly/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mcfly
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -18,6 +18,7 @@ ActiveRecord::Schema.define(:version => 2) do
18
18
  t.datetime "created_dt", :null => false
19
19
  t.datetime "obsoleted_dt", :null => false
20
20
  t.integer "user_id", :null => false
21
+ t.integer "o_user_id"
21
22
  t.integer "security_instrument_id", :null => false
22
23
  t.decimal "coupon", :null => false
23
24
  t.integer "settlement_mm", :null => false
@@ -30,6 +31,7 @@ ActiveRecord::Schema.define(:version => 2) do
30
31
  t.datetime "created_dt", :null => false
31
32
  t.datetime "obsoleted_dt", :null => false
32
33
  t.integer "user_id", :null => false
34
+ t.integer "o_user_id"
33
35
  t.string "name", :null => false
34
36
  t.string "settlement_class", :limit => 1, :null => false
35
37
  end
data/spec/model_spec.rb CHANGED
@@ -182,7 +182,7 @@ describe "Mcfly" do
182
182
 
183
183
  it "should be able to delete objects" do
184
184
  si = SecurityInstrument.find_by_name("FN Fix-30 Cash")
185
- dt = DateTime.now
185
+ dt = '2010-01-01 08:00 PST8PDT'
186
186
 
187
187
  mp = MarketPrice.lookup_si(dt, si)
188
188
  mp.obsoleted_dt.should == Float::INFINITY
@@ -203,4 +203,37 @@ describe "Mcfly" do
203
203
  }.should raise_error(ActiveRecord::StatementInvalid)
204
204
  end
205
205
 
206
+ it "whodunnit should set user/o_user on CRUD" do
207
+ Mcfly.whodunnit = TestUser.new(20)
208
+
209
+ si = SecurityInstrument.find_by_name("FN Fix-30 Cash")
210
+ dt = '2010-01-01 08:00 PST8PDT'
211
+
212
+ sleep 1.seconds
213
+
214
+ mp = MarketPrice.lookup_si(dt, si)
215
+ mp.user_id.should == 10
216
+
217
+ mp.price = 123
218
+ mp.save!
219
+
220
+ # old version should still have original creator user
221
+ mp = MarketPrice.lookup_si(dt, si)
222
+ mp.user_id.should == 10
223
+ mp.o_user_id.should == 20
224
+
225
+ # new version should have new creator
226
+ mp = MarketPrice.lookup_si('infinity', si)
227
+ mp.user_id.should == 20
228
+ mp.o_user_id.should == nil
229
+
230
+ rid = mp.id
231
+
232
+ Mcfly.whodunnit = TestUser.new(30)
233
+
234
+ mp.delete
235
+ mp = MarketPrice.find(rid)
236
+ mp.o_user_id.should == 30
237
+ end
238
+
206
239
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mcfly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-05 00:00:00.000000000 Z
12
+ date: 2013-06-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -148,7 +148,6 @@ files:
148
148
  - spec/dummy/db/schema.rb
149
149
  - spec/dummy/lib/assets/.gitkeep
150
150
  - spec/dummy/log/.gitkeep
151
- - spec/dummy/log/development.log
152
151
  - spec/dummy/public/404.html
153
152
  - spec/dummy/public/422.html
154
153
  - spec/dummy/public/500.html