Module: Cms::Behaviors::Versioning::InstanceMethods
- Defined in:
- lib/cms/behaviors/versioning.rb
Instance Method Summary collapse
- #as_of_draft_version ⇒ Object
-
#as_of_version(version) ⇒ ContentBlock
Find a Content Block as of a specific version.
-
#build_new_version ⇒ Object
Build a new version of this record and associate it with this record.
- #build_new_version_and_add_to_versions_list_for_saving ⇒ Object
-
#create_or_update ⇒ Object
ActiveRecord 3.0.0 call chain ActiveRecord 3 now uses basic inheritence rather than alias_method_chain.
- #current_version ⇒ Object
- #default_version_comment ⇒ Object
- #different_from_last_draft? ⇒ Boolean
- #draft ⇒ Object
- #draft_attributes ⇒ Object
- #draft_version? ⇒ Boolean
- #find_version(number) ⇒ Object
- #initialize_version ⇒ Object
- #live_version ⇒ Object
- #live_version? ⇒ Boolean
- #publish_if_needed ⇒ Object
- #revert ⇒ Object
- #revert_to(version) ⇒ Object
- #revert_to_without_save(version) ⇒ Object
-
#save!(perform_validations = true) ⇒ Object
def save(perform_validations=true) transaction do #logger.info “.….
-
#update_latest_version ⇒ Object
Used in migrations and as a callback.
- #version_comment ⇒ Object
- #version_comment=(version_comment) ⇒ Object
Instance Method Details
#as_of_draft_version ⇒ Object
319 320 321 |
# File 'lib/cms/behaviors/versioning.rb', line 319 def as_of_draft_version build_object_from_version(draft) end |
#as_of_version(version) ⇒ ContentBlock
Find a Content Block as of a specific version.
327 328 329 330 331 |
# File 'lib/cms/behaviors/versioning.rb', line 327 def as_of_version(version) v = find_version(version) raise ActiveRecord::RecordNotFound.new("version #{version.inspect} does not exist for <#{self.class}:#{id}>") unless v build_object_from_version(v) end |
#build_new_version ⇒ Object
Build a new version of this record and associate it with this record.
Called as a before_create in order to correctly allow any other associations to be saved correctly. Called explicitly during update, where it will just define the new_version to be saved.
212 213 214 215 |
# File 'lib/cms/behaviors/versioning.rb', line 212 def build_new_version @new_version = build_new_version_and_add_to_versions_list_for_saving logger.debug {"New version of #{self.class}::Version is #{@new_version.attributes}"} end |
#build_new_version_and_add_to_versions_list_for_saving ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/cms/behaviors/versioning.rb', line 118 def build_new_version_and_add_to_versions_list_for_saving # First get the values from the draft attrs = draft_attributes # Now overwrite all values (self.class.versioned_columns - %w( version )).each do |col| attrs[col] = send(col) end attrs[:version_comment] = @version_comment || default_version_comment @version_comment = nil new_version = versions.build(attrs) new_version.version = new_record? ? 1 : (draft.version.to_i + 1) after_build_new_version(new_version) if respond_to?(:after_build_new_version) new_version end |
#create_or_update ⇒ Object
ActiveRecord 3.0.0 call chain ActiveRecord 3 now uses basic inheritence rather than alias_method_chain. The order in which ActiveRecord::Base includes methods (at the bottom of activerecord) repeatedly overrides save/save! with chains of ‘super’
Callstack order as observed
-
ActiveRecord::Base#save - The original method called by client
AR::Transactions#save
AR::Dirty#save
AR::Validations#save
ActiveRecord::Persistence#save
ActiveRecord::Persistence#create_or_update
AR::Callbacks#create_or_update (runs :save callbacks)
This aliases the original ActiveRecord::Base.save method, in order to change how calling save works. It should do the following things:
-
If the record is unchanged, no save is performed, but true is returned. (Skipping after_save callbacks)
-
If its an update, a new version is created and that is saved.
-
If new record, its version is set to 1, and its published if needed.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/cms/behaviors/versioning.rb', line 183 def create_or_update logger.debug {"#{self.class}#create_or_update called. Published = #{!!publish_on_save}"} self.skip_callbacks = false unless different_from_last_draft? logger.debug {"No difference between this version and last. Skipping save"} self.skip_callbacks = true return true end logger.debug {"Saving #{self.class} #{self.attributes}"} if new_record? self.version = 1 # This should call ActiveRecord::Callbacks#create_or_update, which will correctly trigger the :save callback_chain saved_correctly = super changed_attributes.clear else logger.debug {"#{self.class}#update"} # Because we are 'skipping' the normal ActiveRecord update here, we must manually call the save callback chain. run_callbacks :save do saved_correctly = @new_version.save end end publish_if_needed return saved_correctly end |
#current_version ⇒ Object
311 312 313 |
# File 'lib/cms/behaviors/versioning.rb', line 311 def current_version find_version(self.version) end |
#default_version_comment ⇒ Object
142 143 144 145 146 147 148 |
# File 'lib/cms/behaviors/versioning.rb', line 142 def default_version_comment if new_record? "Created" else "Changed #{(changes.keys - %w[ version created_by_id updated_by_id ]).sort.join(', ')}" end end |
#different_from_last_draft? ⇒ Boolean
363 364 365 366 367 368 369 370 371 |
# File 'lib/cms/behaviors/versioning.rb', line 363 def different_from_last_draft? return true if self.changed? last_draft = self.draft return true unless last_draft (self.class.versioned_columns - %w( version )).each do |col| return true if self.send(col) != last_draft.send(col) end return false end |
#draft ⇒ Object
295 296 297 |
# File 'lib/cms/behaviors/versioning.rb', line 295 def draft versions.first(:order => "version desc") end |
#draft_attributes ⇒ Object
135 136 137 138 139 140 |
# File 'lib/cms/behaviors/versioning.rb', line 135 def draft_attributes # When there is no draft, we'll just copy the attributes from this object # Otherwise we need to use the draft d = new_record? ? self : draft self.class.versioned_columns.inject({}) { |attrs, col| attrs[col] = d.send(col); attrs } end |
#draft_version? ⇒ Boolean
299 300 301 |
# File 'lib/cms/behaviors/versioning.rb', line 299 def draft_version? version == draft.version end |
#find_version(number) ⇒ Object
315 316 317 |
# File 'lib/cms/behaviors/versioning.rb', line 315 def find_version(number) versions.first(:conditions => {:version => number}) end |
#initialize_version ⇒ Object
104 105 106 |
# File 'lib/cms/behaviors/versioning.rb', line 104 def initialize_version self.version = 1 if new_record? end |
#live_version ⇒ Object
303 304 305 |
# File 'lib/cms/behaviors/versioning.rb', line 303 def live_version find_version(self.class.find(id).version) end |
#live_version? ⇒ Boolean
307 308 309 |
# File 'lib/cms/behaviors/versioning.rb', line 307 def live_version? version == self.class.find(id).version end |
#publish_if_needed ⇒ Object
150 151 152 153 154 155 156 157 |
# File 'lib/cms/behaviors/versioning.rb', line 150 def publish_if_needed logger.debug { "#{self.class}#publish_if_needed. publish? = '#{!!@publish_on_save}'"} if @publish_on_save publish @publish_on_save = nil end end |
#revert ⇒ Object
333 334 335 336 |
# File 'lib/cms/behaviors/versioning.rb', line 333 def revert draft_version = draft.version revert_to(draft_version - 1) unless draft_version == 1 end |
#revert_to(version) ⇒ Object
349 350 351 352 |
# File 'lib/cms/behaviors/versioning.rb', line 349 def revert_to(version) revert_to_without_save(version) save end |
#revert_to_without_save(version) ⇒ Object
338 339 340 341 342 343 344 345 346 347 |
# File 'lib/cms/behaviors/versioning.rb', line 338 def revert_to_without_save(version) raise "Version parameter missing" if version.blank? self.revert_to_version = find_version(version) raise "Could not find version #{version}" unless revert_to_version (self.class.versioned_columns - ["version"]).each do |a| send("#{a}=", revert_to_version.send(a)) end self.version_comment = "Reverted to version #{version}" self end |
#save!(perform_validations = true) ⇒ Object
def save(perform_validations=true)
transaction do
#logger.info "..... Calling valid?"
return false unless !perform_validations || valid?
if different_from_last_draft?
#logger.info "..... Changes => #{changes.inspect}"
else
#logger.info "..... No Changes"
return true
end
#logger.info "..... Calling before_save"
return false if callback(:before_save) == false
if new_record?
#logger.info "..... Calling before_create"
return false if callback(:before_create) == false
else
#logger.info "..... Calling before_update"
return false if callback(:before_update) == false
end
#logger.info "..... Calling build_new_version"
new_version = build_new_version
#logger.info "..... Is new version valid? #{new_version.valid?}"
if new_record?
self.version = 1
#logger.info "..... Calling create_without_callbacks"
if result = create_without_callbacks
#logger.info "..... Calling after_create"
if callback(:after_create) != false
#logger.info "..... Calling after_save"
callback(:after_save)
end
if @publish_on_save
publish
@publish_on_save = nil
end
changed_attributes.clear
end
result
elsif new_version
#logger.info "..... Calling save"
if result = new_version.save
#logger.info "..... Calling after_save"
if callback(:after_update) != false
#logger.info "..... Calling after_update"
callback(:after_save)
end
if @publish_on_save
publish
@publish_on_save = nil
end
changed_attributes.clear
end
result
end
true
end
end
291 292 293 |
# File 'lib/cms/behaviors/versioning.rb', line 291 def save!(perform_validations=true) save(:validate=>perform_validations) || raise(ActiveRecord::RecordNotSaved.new(errors.)) end |
#update_latest_version ⇒ Object
Used in migrations and as a callback.
109 110 111 112 113 114 115 116 |
# File 'lib/cms/behaviors/versioning.rb', line 109 def update_latest_version #Rails 3 could use update_column here instead if respond_to? :latest_version sql = "UPDATE #{self.class.table_name} SET latest_version = #{draft.version} where id = #{self.id}" connection.execute sql self.latest_version = draft.version # So we don't need to #reload this object. Probably marks it as dirty though, which could have weird side effects. end end |
#version_comment ⇒ Object
354 355 356 |
# File 'lib/cms/behaviors/versioning.rb', line 354 def version_comment @version_comment end |
#version_comment=(version_comment) ⇒ Object
358 359 360 361 |
# File 'lib/cms/behaviors/versioning.rb', line 358 def version_comment=(version_comment) @version_comment = version_comment send(:changed_attributes)["version_comment"] = @version_comment end |