lib/vestal_versions.rb in laserlemon-vestal_versions-0.3.0 vs lib/vestal_versions.rb in laserlemon-vestal_versions-0.4.1
- old
+ new
@@ -6,71 +6,82 @@
base.extend ClassMethods
end
module ClassMethods
def versioned
- has_many :versions, :as => :versioned, :order => 'versions.number', :dependent => :destroy, :autosave => true do
- def current
- first(:conditions => {:number => versioned.version})
- end
-
+ has_many :versions, :as => :versioned, :order => 'versions.number ASC', :dependent => :destroy do
def at(value)
case value
when Version: value
- when Symbol: send(value)
- when Numeric: first(:conditions => {:number => value.floor})
- when Date, Time: last(:conditions => ['versions.created_at <= ?', value.to_time])
+ when Numeric: find_by_number(value.floor)
+ when Symbol: respond_to?(value) ? send(value) : nil
+ when Date, Time: last(:conditions => ['versions.created_at <= ?', value.to_time.in_time_zone])
end
end
def between(from_value, to_value)
- from, to = at(from_value), at(to_value)
- return [] unless [from, to].all?{|v| v.is_a?(Version) }
+ from, to = number_at(from_value), number_at(to_value)
+ return [] if from.nil? || to.nil? || (from == to)
all(
- :conditions => {:number => ([from, to].min.number..[from, to].max.number)},
+ :conditions => {:number => Range.new(*[from, to].sort)},
:order => "versions.number #{(from > to) ? 'DESC' : 'ASC'}"
)
end
+
+ private
+
+ def number_at(value)
+ case value
+ when Version: value.number
+ when Numeric: value.floor
+ when Symbol, Date, Time: at(value).try(:number)
+ end
+ end
end
- before_save :build_version
+ after_save :create_version, :if => :needs_version?
include InstanceMethods
end
end
module InstanceMethods
- def build_version
- @version = nil
- versions.reload
- unless changes.blank?
- if versions.empty?
- if new_record?
- versions.build(:changes => attributes)
- else
- reverted_attributes = attributes.inject({}){|h,(k,v)| h.update(k => (changed.include?(k) ? changes[k].first : v)) }
- version_timestamp = (try(:updated_at) || try(:created_at))
- versions.build(:changes => reverted_attributes, :created_at => version_timestamp)
- end
- end
- versions.build(:changes => changes) unless new_record?
+ private
+
+ def needs_version?
+ !changed.empty?
+ end
+
+ def create_version
+ if versions.empty?
+ versions.create(:changes => attributes, :number => 1)
+ else
+ @version = nil
+ versions.create(:changes => changes, :number => (version.to_i + 1))
end
+
+ @version = nil
end
+ public
+
def version
@version ||= versions.maximum(:number)
end
def revert_to(value)
chain = versions.between(version, value)
return version unless chain.size > 1
+
new_version, backward = chain.last.number, (chain.first > chain.last)
backward ? chain.pop : chain.shift
+
chain.each do |version|
- version.changes.each do |attribute, change|
+ version.changes.except('updated_at', 'updated_on').each do |attribute, change|
write_attribute(attribute, backward ? change.first : change.last)
end
end
+
@version = new_version
end
def revert_to!(value)
revert_to(value) && save