module Reactor::Persistence::Base
Provides API for writing into the Content Manager. It aims to be just like ActiveRecord::Persistence, so that the difference for the developer is minimal If the method is marked as exception raising, then it should be expected also to raise Reactor::Cm::XmlRequestError
when generic write/connection error occurs.
It should support all generic model callbacks, plus complete set of callbacks for release action (before/after/around).
@raise [Reactor::Cm::XmlRequestError] generic error occoured
Public Class Methods
# File lib/reactor/persistence.rb, line 18 def self.included(base) base.extend(ClassMethods) base.send(:define_model_callbacks, :release) base.class_eval do before_create :sanitize_name before_create :trim_crul_attributes end end
It should excactly match ActiveRecord::Base.new in it's behavior @see ActiveRecord::Base.new
# File lib/reactor/persistence.rb, line 245 def initialize(attributes = nil, &block) if true || !self.class.send(:attribute_methods_overriden?) # FIXME !!!! ignored_attributes = ignore_attributes(attributes) # supress block hijacking! super(attributes) {} load_ignored_attributes(ignored_attributes) yield self if block_given? else super(attributes) end end
Public Instance Methods
Deletes the object from the CM. No callbacks are executed. Though exceptions can be raised. Freezes the object.
# File lib/reactor/persistence.rb, line 184 def delete crul_obj_delete if persisted? @destroyed = true freeze end
Removes the object from the CM. Runs all the callbacks. Can raise exception. Freezes the object.
# File lib/reactor/persistence.rb, line 192 def destroy run_callbacks(:destroy) do self.delete end end
Returns true if this object has been destroyed, otherwise returns false.
# File lib/reactor/persistence.rb, line 172 def destroyed? @destroyed == true end
Creates a working version of the object. Returns true on success or when the object already has a working version. Returns false when: @param comment [String] comment to leave for the next user
-
user lacks the permissions
-
other error occured
# File lib/reactor/persistence.rb, line 126 def edit(comment=nil) edit!(comment) return true rescue Reactor::Cm::XmlRequestError, Reactor::NotPermitted return false end
Creates a working version of the object. Returns true on success or when the object already has a working version. Raises exceptions @param comment [String] comment to leave for the next user @raise [Reactor::NotPermitted] current user lacks required permissions
# File lib/reactor/persistence.rb, line 137 def edit!(comment=nil) crul_obj.edit!(comment) unless self.really_edited? reload return true end
Returns true, if the object has any links pointing to it. @raise [Reactor::Cm::XmlRequestError] generic error occoured
# File lib/reactor/persistence.rb, line 145 def has_super_links? crul_obj.get('hasSuperLinks') == '1' end
Returns true if this object hasn't been saved yet – that is, a record for the object doesn't exist in the data store yet; otherwise, returns false.
# File lib/reactor/persistence.rb, line 158 def new_record? #!destroyed? && (self.id.nil? || !self.class.exists?(self.id)) !destroyed? && (self.id.nil? || self.path.blank?) end
Stolen from Rails 3. Returns if the record is persisted, i.e. stored in database (it's not a new record and it was not destroyed.) @note Code should not be changed without large modifications to the module.
# File lib/reactor/persistence.rb, line 167 def persisted? !(new_record? || destroyed?) end
Equivalent to Obj#edited?
# File lib/reactor/persistence.rb, line 275 def really_edited? self.edited? end
Returns an array of errors
# File lib/reactor/persistence.rb, line 280 def reasons_for_incomplete_state crul_obj.get('reasonsForIncompleteState') || [] end
Releases the object. Returns true on success, false when one of the following occurs:
-
user lacks the permissions
-
the object has already been released
-
object is invalid
-
other error occoured
@param comment [String] comment to leave for the next user
# File lib/reactor/persistence.rb, line 34 def release(comment=nil) return release!(comment) rescue Reactor::Cm::XmlRequestError, ActiveRecord::RecordInvalid, Reactor::NotPermitted, Reactor::AlreadyReleased return false end
Releases the object. Returns true on succes, can raise exceptions @param comment [String] comment to leave for the next user @raise [Reactor::AlreadyReleased] @raise [ActiveRecord::RecordInvalid] validations failed @raise [Reactor::NotPermitted] current user lacks required permissions
# File lib/reactor/persistence.rb, line 76 def release!(comment=nil) run_callbacks(:release) do raise(Reactor::AlreadyReleased) unless self.really_edited? crul_obj.release!(comment) reload end return true end
Reloads object attributes. Invalidates caches. Does not call any other reload methods (neither from RailsConnector
nor from ActiveRecord) but tries to mimmic their behaviour.
# File lib/reactor/persistence.rb, line 201 def reload(options = nil) RailsConnector::AbstractObj.uncached do #super # Throws RecordNotFound when changing obj_class # AR reload clear_aggregation_cache clear_association_cache fresh_object = RailsConnector::AbstractObj.find(self.id, options) @attributes = fresh_object.instance_variable_get('@attributes') @attributes_cache = {} # RC reload @attr_values = nil @attr_defs = nil @attr_dict = nil @obj_class_definition = nil @object_with_meta_data = nil # meta reload @editor = nil @object_with_meta_data = nil self end end
Resolves references in any of the html fields. Returns true on success, or false when:
-
user lacks the permissions
-
generic error occoured
# File lib/reactor/persistence.rb, line 227 def resolve_refs resolve_refs! return true rescue Reactor::Cm::XmlRequestError, Reactor::NotPermitted return false end
Resolves references in any of the html fields. Returns true on success, raises exceptions. @raise [Reactor::NotPermitted] current user lacks required permissions
# File lib/reactor/persistence.rb, line 237 def resolve_refs! crul_obj.resolve_refs! return true end
Removes the working version of the object, if it exists @param comment [String] comment to leave for the next user @return [true]
# File lib/reactor/persistence.rb, line 56 def revert(comment=nil) return revert!(comment) end
Removes the working version of the object, if it exists @param comment [String] comment to leave for the next user @return [true] @note There is no difference between revert
and revert!
# File lib/reactor/persistence.rb, line 65 def revert!(comment=nil) crul_obj.revert!(comment) reload return true end
Return an array of RailsConnector::AbstractObj
that contain a link to this file. @raise [Reactor::Cm::XmlRequestError] generic error occoured
# File lib/reactor/persistence.rb, line 152 def super_objects RailsConnector::AbstractObj.where(:obj_id => crul_obj.get('superObjects')).to_a end
Makes the current user the editor of the object. Returns true when user is already the editor or take succeded, false when one of the following occurs:
-
user lacks the permissions
-
the object has not beed edited
-
other error occured
@param comment [String] comment to leave for the next user
# File lib/reactor/persistence.rb, line 100 def take(comment=nil) take!(comment) return true rescue Reactor::Cm::XmlRequestError, Reactor::NotPermitted, Reactor::NoWorkingVersion return false end
Makes the current user the editor of the object. Returns true when user is already the editor or take succeded. Raises exceptions @param comment [String] comment to leave for the next user @raise [Reactor::NoWorkingVersion] there is no working version of the object @raise [Reactor::NotPermitted] current user lacks required permissions
# File lib/reactor/persistence.rb, line 112 def take!(comment=nil) raise(Reactor::NoWorkingVersion) unless self.really_edited? # TODO: refactor the if condition crul_obj.take!(comment) if (crul_obj.editor != Reactor::Configuration::xml_access[:username]) # neccessary to recalculate #editor reload return true end
Unreleases the object. Returns true on success, false when one of the following occurs:
-
user lacks the permissions
-
the object is not released
-
object is invalid
-
other error occoured
# File lib/reactor/persistence.rb, line 46 def unrelease(comment=nil) return unrelease!(comment) rescue Reactor::Cm::XmlRequestError, ActiveRecord::RecordInvalid, Reactor::NotPermitted return false end
Unreleases the object. Returns true on succes, can raise exceptions @param comment [String] comment to leave for the next user
# File lib/reactor/persistence.rb, line 87 def unrelease!(comment=nil) crul_obj.unrelease!(comment) reload return true end
Protected Instance Methods
# File lib/reactor/persistence.rb, line 310 def changed_linklists custom_attrs = self.singleton_class.send(:instance_variable_get, '@_o_allowed_attrs') || self.class.send(:instance_variable_get, '@_o_allowed_attrs') || [] custom_attrs.select do |attr| self.send(:attribute_type, attr) == :linklist && self.send(:[],attr.to_sym).try(:changed?) end end
# File lib/reactor/persistence.rb, line 321 def crul_attributes @__crul_attributes || {} end
# File lib/reactor/persistence.rb, line 302 def crul_attributes_set? !crul_attributes.empty? || uploaded? end
# File lib/reactor/persistence.rb, line 306 def crul_links_changed? !changed_linklists.empty? end
# File lib/reactor/persistence.rb, line 325 def crul_obj @crul_obj ||= Reactor::Cm::Obj.load(obj_id) end
# File lib/reactor/persistence.rb, line 329 def crul_obj_delete crul_obj.delete! end
# File lib/reactor/persistence.rb, line 333 def crul_obj_save attrs, _ = crul_attributes.partition do |field, (value, options)| self.send(:attribute_type, field) != :linklist end linklists = changed_linklists new_links = {}.tap do |result| linklists.map do |field| result[field] = Reactor::Attributes::LinkListFromAccessor.new(self, field).call.map do |l| {:link_id => l.id, :title => l.title, :destination_url => (l.internal? ? l.destination_object.path : l.url), :target => l.target} end end end links_modified = !linklists.empty? crul_obj.composite_save(attrs, [], [], [], links_modified) do |attrs, links_to_add, links_to_remove, links_to_set| links_to_add.clear links_to_remove.clear links_to_set.clear copy = RailsConnector::AbstractObj.uncached { RailsConnector::AbstractObj.find(self.id) } linklists.each do |linklist| original_link_ids = Reactor::Attributes::LinkListFromAttrValues.new(copy, linklist).call.map(&:id) i = 0 common = [original_link_ids.length, new_links[linklist].length].min # replace existing links while i < common link = new_links[linklist][i] link[:link_id] = link_id = original_link_ids[i] links_to_set << [link_id, link] i += 1 end # add appended links while i < new_links[linklist].length link = new_links[linklist][i] links_to_add << [linklist, link] i += 1 end # remove trailing links while i < original_link_ids.length links_to_remove << original_link_ids[i] i += 1 end end end self.class.connection.clear_query_cache end
# File lib/reactor/persistence.rb, line 285 def prevent_resolve_refs @prevent_resolve_refs = true end
# File lib/reactor/persistence.rb, line 289 def prevent_resolve_refs? @prevent_resolve_refs == true end
# File lib/reactor/persistence.rb, line 293 def sanitize_name return unless self.name.present? sanitized_name = self.class.send(:sanitize_name, self.name) if sanitized_name != self.name self.name = sanitized_name end end
Private Instance Methods
TODO: test it & make it public Copy an Obj to another tree, returnes ID of the new Object @param [String, Obj, Integer] new_parent path, id, or instance of target where to copy @param [true, false] recursive set to true to also copy the underlying subtree @param [String] new_name gives the object new name
# File lib/reactor/persistence.rb, line 398 def copy(new_parent, recursive = false, new_name = nil) self.id = crul_obj.copy(RailsConnector::AbstractObj.path_from_anything(new_parent), recursive, new_name) #self.reload resolve_refs #? self.id end
# File lib/reactor/persistence.rb, line 413 def create run_callbacks(:create) do c_name = self.name c_parent= self.class.path_from_anything(self.parent_obj_id) c_objcl = self.obj_class crul_obj_create(c_name, c_parent, c_objcl) self.id = @crul_obj.obj_id crul_obj_save if crul_attributes_set? || crul_links_changed? self.reload # ? self.id end end
# File lib/reactor/persistence.rb, line 409 def crul_obj_create(name, parent, klass) @crul_obj = Reactor::Cm::Obj.create(name, parent, klass) end
# File lib/reactor/persistence.rb, line 450 def ignore_attributes(attributes) return {} if attributes.nil? obj_class = attributes.delete(:obj_class) parent = attributes.delete(:parent) {:obj_class => obj_class, :parent => parent} end
# File lib/reactor/persistence.rb, line 460 def load_ignored_attributes(attributes) return if attributes.nil? set_parent(attributes[:parent]) if attributes[:parent].present? set_obj_class(attributes[:obj_class]) if attributes[:obj_class].present? end
disables active record transactions
# File lib/reactor/persistence.rb, line 484 def rollback_active_record_state! yield end
# File lib/reactor/persistence.rb, line 473 def set_obj_class(obj_class) self.obj_class = obj_class end
# File lib/reactor/persistence.rb, line 467 def set_parent(parent_something) parent_obj = self.class.obj_from_anything(parent_something) self.parent_obj_id = parent_obj.id crul_set(:parent, parent_obj.path, {}) if persisted? end
# File lib/reactor/persistence.rb, line 405 def trim_crul_attributes crul_attributes.delete_if {|attr, options| [:name, :objClass].include?(attr) } end
# File lib/reactor/persistence.rb, line 434 def update run_callbacks(:update) do crul_obj_save if crul_attributes_set? || crul_links_changed? self.reload self.id end end
disables active record transactions
# File lib/reactor/persistence.rb, line 479 def with_transaction_returning_status yield end