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 ⇒ <Class>::Version
Returns the most recently created Version for this class.
- #draft_attributes ⇒ Object
- #draft_version? ⇒ Boolean
- #find_version(number) ⇒ Object
- #initialize_version ⇒ Object
- #live_version ⇒ Object
- #live_version? ⇒ Boolean
- #revert ⇒ Object
- #revert_to(version, options = {}) ⇒ Object
- #revert_to_without_save(version, options) ⇒ Object
- #save!(perform_validations = true) ⇒ Object
-
#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
290 291 292 |
# File 'lib/cms/behaviors/versioning.rb', line 290 def as_of_draft_version draft.build_object_from_version end |
#as_of_version(version) ⇒ ContentBlock
Find a Content Block as of a specific version.
298 299 300 301 302 |
# File 'lib/cms/behaviors/versioning.rb', line 298 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 v.build_object_from_version 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.
251 252 253 254 |
# File 'lib/cms/behaviors/versioning.rb', line 251 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
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/cms/behaviors/versioning.rb', line 160 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 #puts "Im a '#{self.class}', vc = #{self.class.version_class}" 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.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/cms/behaviors/versioning.rb', line 216 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" } if !published && publish_on_save logger.debug { "Publishing current draft version" } return publish else self.skip_callbacks = true return true end 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 compatible_clear_changes_information 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
282 283 284 |
# File 'lib/cms/behaviors/versioning.rb', line 282 def current_version find_version(self.version) end |
#default_version_comment ⇒ Object
185 186 187 188 189 190 191 |
# File 'lib/cms/behaviors/versioning.rb', line 185 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
346 347 348 349 350 351 352 353 354 |
# File 'lib/cms/behaviors/versioning.rb', line 346 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 false end |
#draft ⇒ <Class>::Version
Returns the most recently created Version for this class. Drafts are the most recent change from the _versions table for a given content item.
i.e. For Cms::Page, this would return Cms::Page::Version
265 266 267 |
# File 'lib/cms/behaviors/versioning.rb', line 265 def draft versions.order("version desc").first end |
#draft_attributes ⇒ Object
178 179 180 181 182 183 |
# File 'lib/cms/behaviors/versioning.rb', line 178 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
269 270 271 272 |
# File 'lib/cms/behaviors/versioning.rb', line 269 def draft_version? return true unless draft version == draft.version end |
#find_version(number) ⇒ Object
286 287 288 |
# File 'lib/cms/behaviors/versioning.rb', line 286 def find_version(number) versions.where(:version => number).first end |
#initialize_version ⇒ Object
146 147 148 |
# File 'lib/cms/behaviors/versioning.rb', line 146 def initialize_version self.version = 1 if new_record? end |
#live_version ⇒ Object
274 275 276 |
# File 'lib/cms/behaviors/versioning.rb', line 274 def live_version find_version(self.class.find(id).version) end |
#live_version? ⇒ Boolean
278 279 280 |
# File 'lib/cms/behaviors/versioning.rb', line 278 def live_version? version == self.class.find(id).version end |
#revert ⇒ Object
304 305 306 307 |
# File 'lib/cms/behaviors/versioning.rb', line 304 def revert draft_version = draft.version revert_to(draft_version - 1) unless draft_version == 1 end |
#revert_to(version, options = {}) ⇒ Object
332 333 334 335 |
# File 'lib/cms/behaviors/versioning.rb', line 332 def revert_to(version, ={}) revert_to_without_save(version, ) save end |
#revert_to_without_save(version, options) ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/cms/behaviors/versioning.rb', line 309 def revert_to_without_save(version, ) raise "Version parameter missing" if version.blank? revert_to_version = find_version(version) raise "Could not find version #{version}" unless revert_to_version self.before_revert(revert_to_version) if self.respond_to?(:before_revert) (self.class.versioned_columns - ["version"]).each do |a| send("#{a}=", revert_to_version.send(a)) end .keys.each do |key| send("#{key}=", [key]) end self.after_revert(revert_to_version) if self.respond_to?(:after_revert) self.version_comment = "Reverted to version #{version}" self.publish_on_save = false self end |
#save!(perform_validations = true) ⇒ Object
256 257 258 |
# File 'lib/cms/behaviors/versioning.rb', line 256 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.
151 152 153 154 155 156 157 158 |
# File 'lib/cms/behaviors/versioning.rb', line 151 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}" self.class.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
337 338 339 |
# File 'lib/cms/behaviors/versioning.rb', line 337 def version_comment @version_comment end |
#version_comment=(version_comment) ⇒ Object
341 342 343 344 |
# File 'lib/cms/behaviors/versioning.rb', line 341 def version_comment=(version_comment) @version_comment = version_comment send(:changed_attributes)["version_comment"] = @version_comment end |