lib/active_metadata/base.rb in active_metadata-0.2.2 vs lib/active_metadata/base.rb in active_metadata-0.2.3
- old
+ new
@@ -1,15 +1,16 @@
module ActiveMetadata
CONFIG = File.exists?('config/active_metadata.yml') ? YAML.load_file('config/active_metadata.yml')[Rails.env] : {}
CONFIG['cache_expires_in'] ||= 60
-
+
## Define ModelMethods
module Base
-
+
require 'paperclip'
require "active_metadata/persistence/persistence"
+ require "active_metadata/helpers"
def self.included(klass)
klass.class_eval do
extend Config
end
@@ -17,28 +18,30 @@
module Config
def acts_as_metadata *args
after_save :save_history
-
+
class_variable_set("@@metadata_id_from", args.empty? ? nil : args[0][:metadata_id_from])
include ActiveMetadata::Base::InstanceMethods
- include ActiveMetadata::Persistence
-
+ include ActiveMetadata::Persistence
+
end
end
module InstanceMethods
-
+
+ include ActiveMetadata::Helpers
+
def self.included(klass)
- [:notes,:attachments,:history].each do |item|
- klass.send(:define_method,"#{item.to_s}_cache_key".to_sym) do |field|
- "#{Rails.env}/active_metadata/#{item.to_s}/#{self.class}/#{metadata_id}/#{field}/"
- end
- end
+ [:notes, :attachments, :history].each do |item|
+ klass.send(:define_method, "#{item.to_s}_cache_key".to_sym) do |field|
+ "#{Rails.env}/active_metadata/#{item.to_s}/#{self.class}/#{metadata_id}/#{field}/"
+ end
+ end
end
def metadata_id
metadata_id_from = self.class.class_variable_get("@@metadata_id_from")
return self.id if metadata_id_from.nil?
@@ -46,19 +49,73 @@
metadata_id_from.each do |item|
receiver = receiver.send item
end
receiver.id
end
-
+
def current_user_id
if User.respond_to?(:current) && !User.current.nil?
- User.current.id
+ User.current.id
else
nil
- end
- end
-
+ end
+ end
+
+ # Resolve concurrency using the passed timestamps and the active_metadata histories
+ # To be called from controller before updating the model. Params that contains a conflict are removed from the params list.
+ # Returns 2 values containing the the deleted params with the related history:
+ # [{:key => [passed_value,history]}]
+ #
+ # first result is the WARNINGS array: conflict appears on a field not touched by the user that submit the value
+ # first result is the FATALS Array : if the conflict appears on a field modified by the user that submit the value
+ # an empty array is returned by default
+ def manage_concurrency(params, timestamp)
+ warnings = []
+ fatals = []
+
+ # scan params
+ params.each do |key, val|
+ # ensure the query order
+ histories = history_for key.to_sym, "created_at DESC"
+ latest_history = histories.first
+
+ # if form timestamp is subsequent the history last change go on
+ # if history does not exists yet go on
+ next if latest_history.nil? || timestamp > latest_history.created_at
+
+ #if the timestamp is previous of the last history change
+ if timestamp < latest_history.created_at
+ #remove the key from the update process
+ params.delete key
+
+ # We have a conflict.
+ # Check if the actual submission has been modified
+ histories.each do |h|
+ # Looking for the value that was loaded by the user. First history with a ts that is younger than the form ts
+ next if timestamp > h.created_at
+
+ # History stores values as strings so any boolean is stored as "0" or "1"
+ # We need to translate the params passed for a safer comparison.
+ if self.column_for_attribute(key).type == :boolean
+ b_val = to_bool(h.value)
+ end
+
+ if [h.value, b_val].include? val
+ warnings << {key => [val, h]}
+ else
+ fatals << {key => [val, h]}
+ end
+ end
+
+ end
+
+ end
+
+ return warnings, fatals
+ end
+
end # InstanceMethods
+
end
end
::ActiveRecord::Base.send :include, ActiveMetadata::Base