Module: Citier::ChildInstanceMethods

Includes:
InstanceMethods
Defined in:
lib/citier/child_instance_methods.rb

Instance Method Summary collapse

Methods included from InstanceMethods

included

Instance Method Details

#save(options = {}) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/citier/child_instance_methods.rb', line 4

def save(options={})
  return false if (options[:validate] != false && !self.valid?)

  #citier_debug("Callback (#{self.inspect})")
  citier_debug("SAVING #{self.class.to_s}")

  #AIT NOTE: Will change any protected values back to original values so any models onwards won't see changes.
  # Run save and create/update callbacks, just like ActiveRecord does
  self.run_callbacks(:save) do
    self.run_callbacks(self.new_record? ? :create : :update) do
      #get the attributes of the class which are inherited from it's parent.
      attributes_for_parent = self.attributes.reject { |key,value| !self.class.superclass.column_names.include?(key) }
      changed_attributes_for_parent = self.changed_attributes.reject { |key,value| !self.class.superclass.column_names.include?(key) }

      # Get the attributes of the class which are unique to this class and not inherited.
      attributes_for_current = self.attributes.reject { |key,value| self.class.superclass.column_names.include?(key) }
      changed_attributes_for_current = self.changed_attributes.reject { |key,value| self.class.superclass.column_names.include?(key) }

      citier_debug("Attributes for #{self.class.superclass.to_s}: #{attributes_for_parent.inspect}")
      citier_debug("Changed attributes for #{self.class.superclass.to_s}: #{changed_attributes_for_parent.keys.inspect}")
      citier_debug("Attributes for #{self.class.to_s}: #{attributes_for_current.inspect}")
      citier_debug("Changed attributes for #{self.class.to_s}: #{changed_attributes_for_current.keys.inspect}")

      ########
      #
      # Parent saving

      #create a new instance of the superclass, passing the inherited attributes.
      parent = self.class.superclass.new
  
      parent.force_attributes(attributes_for_parent, :merge => true)
      changed_attributes_for_parent["id"] = 0 # We need to change at least something to force a timestamps update.
      parent.force_changed_attributes(changed_attributes_for_parent)
  
      parent.id = self.id if id
      parent.type = self.type

      parent.is_new_record(new_record?)
  
      # If we're root (AR subclass) this will just be saved as normal through AR. If we're a child it will call this method again. 
      # It will try and save it's parent and then save itself through the Writable constant.
      parent_saved = parent.save
      self.id = parent.id

      if !parent_saved
        # Couldn't save parent class
        citier_debug("Class (#{self.class.superclass.to_s}) could not be saved")
        citier_debug("Errors = #{parent.errors.to_s}")
        return false # Return false and exit run_callbacks :save and :create/:update, so the after_ callback won't run.
      end

      #End of parent saving

      ######
      ##
      ## Self Saving
      ##

      # If there are attributes for the current class (unique & not inherited), save current model
      if !attributes_for_current.empty?
        current = self.class::Writable.new
    
        current.force_attributes(attributes_for_current, :merge => true)
        current.force_changed_attributes(changed_attributes_for_current)
    
        current.id = self.id
        current.is_new_record(new_record?)
  
        current_saved = current.save
        
        current.after_save_change_request if current.respond_to?('after_save_change_request') #Specific to an app I'm building

        if !current_saved
          citier_debug("Class (#{self.class.superclass.to_s}) could not be saved")
          citier_debug("Errors = #{current.errors.to_s}")
          return false # Return false and exit run_callbacks :save and :create/:update, so the after callback won't run.
        end
      end  

      # at this point, parent_saved && current_saved
      
      is_new_record(false) # This is no longer a new record

      self.force_changed_attributes({}) # Reset changed_attributes so future changes will be tracked correctly
      
      # No return, because we want the after callback to run.
    end
  end
  return true
end

#save!(options = {}) ⇒ Object

Raises:

  • (ActiveRecord::RecordInvalid)


95
96
97
98
# File 'lib/citier/child_instance_methods.rb', line 95

def save!(options={})
  raise ActiveRecord::RecordInvalid.new(self) if (options[:validate] != false && !self.valid?)
  self.save || raise(ActiveRecord::RecordNotSaved)
end