From a83623ff9ca562c2d30a940193deeb229a3a1401 Mon Sep 17 00:00:00 2001 From: Jan-Hettich Date: Sun, 27 Jul 2014 15:33:13 -0700 Subject: [PATCH 1/3] commented method update_base for applying update to base_record.ext_id using update! instead of raw sql --- app/services/crud/delete.rb | 5 +++++ app/services/crud/update.rb | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/app/services/crud/delete.rb b/app/services/crud/delete.rb index cf828ce..edc295b 100644 --- a/app/services/crud/delete.rb +++ b/app/services/crud/delete.rb @@ -5,6 +5,11 @@ def initialize(base_record) super(base_record, {deleted: true}) end + def update_base(params) + params.merge deleted: true + super params + end + def sql_update(ext_record) "update #{base_record.class.table_name} " \ "set ext_id = #{ext_record['id']}, deleted = true " \ diff --git a/app/services/crud/update.rb b/app/services/crud/update.rb index 74fd485..133b436 100644 --- a/app/services/crud/update.rb +++ b/app/services/crud/update.rb @@ -14,11 +14,16 @@ def call current_attributes.except!(:id, :created_at, :updated_at) updated_attributes = parameters.reverse_merge(current_attributes) ext_record = extension_resource_factory.create!(updated_attributes) + #update_base ext_id: ext_record['id'] ActiveRecord::Base.connection.execute sql_update(ext_record) base_record.reload end end + def update_base(params) + base_record.update! params + end + def sql_update(ext_record) "update #{base_record.class.table_name} " \ "set ext_id = #{ext_record['id']} " \ From de1e8b97d7b1144268b2d6c5023882fccdcfb0df Mon Sep 17 00:00:00 2001 From: Jan-Hettich Date: Tue, 29 Jul 2014 13:57:17 -0700 Subject: [PATCH 2/3] use active record update! instead of sql to update the base record; eliminated method_missing, which was causing an issue, because activerecord itself uses method_missing while copying attributes during update; temporarily got tests passing by implementing title and description methods explicitly in the Topic class; however, this will be replaced in future by meta-programming to add the methods from the extension class into the base class. --- app/models/concerns/atomic_base.rb | 14 +------------ app/models/concerns/atomic_extension.rb | 3 +-- app/models/topic.rb | 8 ++++++++ app/services/crud/delete.rb | 11 ----------- app/services/crud/update.rb | 26 ++++++++----------------- spec/db_integration/topic_spec.rb | 9 +++++---- 6 files changed, 23 insertions(+), 48 deletions(-) diff --git a/app/models/concerns/atomic_base.rb b/app/models/concerns/atomic_base.rb index e279e7e..e2c1d5d 100644 --- a/app/models/concerns/atomic_base.rb +++ b/app/models/concerns/atomic_base.rb @@ -12,12 +12,7 @@ module AtomicBase # atomic record extension class (contains the real data) -- ExtTopic def self.atomic_record_extension "Ext#{self}" - end - - # extension table -- :ext_topics - def self.extension_table - atomic_record_extension.constantize.table_name - end + end has_many :versions, ->{ order "id DESC"}, class_name: atomic_record_extension, foreign_key: :uuid @@ -27,13 +22,6 @@ def self.extension_table end - # delegate method calls to extension class - def method_missing(method, *args, &block) - self.data.send method, *args - rescue NoMethodError - super - end - # created returns created_at for the base def created self.created_at diff --git a/app/models/concerns/atomic_extension.rb b/app/models/concerns/atomic_extension.rb index 1145a21..380d72a 100644 --- a/app/models/concerns/atomic_extension.rb +++ b/app/models/concerns/atomic_extension.rb @@ -9,8 +9,7 @@ module AtomicExtension # atomic record base class -- Topic def self.atomic_record_base - atomic_record_extension = self.to_s - atomic_record_extension.gsub(/\AExt/, '') + self.to_s.gsub(/\AExt/, '') end belongs_to :base, class_name: atomic_record_base, foreign_key: :uuid diff --git a/app/models/topic.rb b/app/models/topic.rb index d4309cc..4c792da 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -1,4 +1,12 @@ class Topic < ActiveRecord::Base include AtomicBase + def title + data.title + end + + def description + data.description + end + end diff --git a/app/services/crud/delete.rb b/app/services/crud/delete.rb index edc295b..20ebeb1 100644 --- a/app/services/crud/delete.rb +++ b/app/services/crud/delete.rb @@ -5,16 +5,5 @@ def initialize(base_record) super(base_record, {deleted: true}) end - def update_base(params) - params.merge deleted: true - super params - end - - def sql_update(ext_record) - "update #{base_record.class.table_name} " \ - "set ext_id = #{ext_record['id']}, deleted = true " \ - "where uuid = '#{base_record.uuid}'" - end - end end diff --git a/app/services/crud/update.rb b/app/services/crud/update.rb index 133b436..4f9c330 100644 --- a/app/services/crud/update.rb +++ b/app/services/crud/update.rb @@ -9,26 +9,16 @@ def initialize(base_record, parameters) end def call - ActiveRecord::Base.transaction do - current_attributes = base_record.data.attributes.symbolize_keys - current_attributes.except!(:id, :created_at, :updated_at) - updated_attributes = parameters.reverse_merge(current_attributes) - ext_record = extension_resource_factory.create!(updated_attributes) - #update_base ext_id: ext_record['id'] - ActiveRecord::Base.connection.execute sql_update(ext_record) - base_record.reload + transaction_factory.transaction do + ext_params = base_record.data.attributes.symbolize_keys + ext_params.except!(:id, :deleted, :created_at, :updated_at) + ext_params.merge! parameters + new_ext = extension_resource_factory.create!(ext_params) + base_params = {ext_id: new_ext['id'], deleted: new_ext['deleted']} + base_record.update! base_params + base_record end end - def update_base(params) - base_record.update! params - end - - def sql_update(ext_record) - "update #{base_record.class.table_name} " \ - "set ext_id = #{ext_record['id']} " \ - "where uuid = '#{base_record.uuid}'" - end - end end \ No newline at end of file diff --git a/spec/db_integration/topic_spec.rb b/spec/db_integration/topic_spec.rb index b953c89..9b7dea1 100644 --- a/spec/db_integration/topic_spec.rb +++ b/spec/db_integration/topic_spec.rb @@ -2,12 +2,13 @@ describe Topic do - it 'has the right extension class' do + it 'has the right extension class name' do expect(Topic.atomic_record_extension).to eq("ExtTopic") end it 'has the right extension table' do - expect(Topic.extension_table).to eq("ext_topics") + expect(Topic.atomic_record_extension.constantize.table_name).to \ + eq("ext_topics") end it 'returns the count of topics' do @@ -70,8 +71,8 @@ end it 'has the new title and description' do - expect(updated_topic.title).to eq("new title") - expect(updated_topic.description).to eq("new description") + expect(updated_topic.data.title).to eq("new title") + expect(updated_topic.data.description).to eq("new description") end it "reports 'created' as creation time of the original record" do From 2031eb7af6c1cf380ab164dd9f9d0bc58d644245 Mon Sep 17 00:00:00 2001 From: Jan-Hettich Date: Wed, 30 Jul 2014 17:22:40 -0700 Subject: [PATCH 3/3] add forwarding methods for data columns using metaprogramming --- app/models/concerns/atomic_base.rb | 10 ++++++++++ app/models/topic.rb | 8 -------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/models/concerns/atomic_base.rb b/app/models/concerns/atomic_base.rb index e2c1d5d..3fee9c7 100644 --- a/app/models/concerns/atomic_base.rb +++ b/app/models/concerns/atomic_base.rb @@ -20,6 +20,16 @@ def self.atomic_record_extension default_scope {includes(:data).where(deleted: false)} + # create forwarding accessors for the data columns + extension_class = atomic_record_extension.constantize + data_cols = extension_class.column_names - %w(id deleted uuid created_at update_at) + code = "" + data_cols.each do |col| + code << "def #{col}; data.#{col} end\n" + code << "def #{col}=(value); data.#{col} = value; end\n" + end + class_eval code + end # created returns created_at for the base diff --git a/app/models/topic.rb b/app/models/topic.rb index 4c792da..d4309cc 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -1,12 +1,4 @@ class Topic < ActiveRecord::Base include AtomicBase - def title - data.title - end - - def description - data.description - end - end