• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IUBLibTech / datacore / 77975a5c-9259-4063-a1a2-b05cad60aea7

19 Sep 2025 02:05PM UTC coverage: 28.184% (-0.04%) from 28.224%
77975a5c-9259-4063-a1a2-b05cad60aea7

Pull #187

circleci

rdlebeau
IUS-2780 DataCORE updating header image
Pull Request #187: IUS-2780 DataCORE updating header image

4231 of 15012 relevant lines covered (28.18%)

17.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.63
/lib/active_fedora/persistence.rb
1
# frozen_string_literal: true
2

3
# monkey patch of active_fedora gem, lib/active_fedora/persistence.rb
4

5
module ActiveFedora
1✔
6
  # = Active Fedora Persistence
7
  module Persistence
1✔
8
    extend ActiveSupport::Concern
1✔
9

10
    def new_record?
1✔
11
      return true if @ldp_source.subject.nil?
5,427✔
12
      @ldp_source.get
3,410✔
13
      false
3,119✔
14
    rescue Ldp::Gone
15
      false
×
16
    rescue Ldp::NotFound
17
      true
291✔
18
    end
19

20
    def persisted?
1✔
21
      !(destroyed? || new_record?)
1,456✔
22
    end
23

24
    # Returns true if this object has been destroyed, otherwise returns false.
25
    def destroyed?
1✔
26
      @destroyed
1,820✔
27
    end
28

29
    # Saves a Base object, and any dirty attached files, then updates
30
    # the Solr index for this object, unless option :update_index=>false is present.
31
    # Indexing is also controlled by the `create_needs_index?' and `update_needs_index?' methods.
32
    #
33
    # @param [Hash] options
34
    # @option options [Boolean] :update_index (true) set false to skip indexing
35
    # @return [Boolean] true if save was successful, otherwise false
36
    def save(*options)
1✔
37
      create_or_update(*options)
218✔
38
    end
39

40
    def save!(*args)
1✔
41
      create_or_update(*args)
249✔
42
    end
43

44
    # Pushes the object and all of its new or dirty attached files into Fedora
45
    def update(attributes)
1✔
46
      assign_attributes(attributes)
×
47
      save
×
48
    end
49

50
    alias update_attributes update
1✔
51

52
    # Updates its receiver just like #update but calls #save! instead
53
    # of +save+, so an exception is raised if the record is invalid and saving will fail.
54
    def update!(attributes)
1✔
55
      assign_attributes(attributes)
3✔
56
      save!
3✔
57
    end
58

59
    alias update_attributes! update!
1✔
60

61
    # Deletes an object from Fedora and deletes the indexed record from Solr.
62
    # Delete does not run any callbacks, so consider using _destroy_ instead.
63
    # @param [Hash] opts
64
    # @option opts [Boolean] :eradicate if passed in, eradicate the tombstone from Fedora
65
    def delete(opts = {})
1✔
66
      return self if new_record?
×
67

68
      @destroyed = true
×
69

70
      id = self.id ## cache so it's still available after delete
×
71
      # Clear out the ETag
72
      @ldp_source = build_ldp_resource(id)
×
73
      begin
74
        @ldp_source.delete
×
75
      rescue Ldp::NotFound
76
        raise ObjectNotFoundError, "Unable to find #{id} in the repository"
×
77
      end
78

79
      ActiveFedora::SolrService.delete(id) if ActiveFedora.enable_solr_updates?
×
80
      self.class.eradicate(id) if opts[:eradicate]
×
81
      freeze
×
82
    end
83

84
    # Delete the object from Fedora and Solr. Run any before/after/around callbacks for destroy
85
    # @param [Hash] opts
86
    # @option opts [Boolean] :eradicate if passed in, eradicate the tombstone from Fedora
87
    def destroy(*opts)
1✔
88
      raise ReadOnlyRecord if readonly?
×
89
      delete(*opts)
×
90
    end
91

92
    # Deletes the record in the database and freezes this instance to reflect
93
    # that no changes should be made (since they can't be persisted).
94
    #
95
    # There's a series of callbacks associated with #destroy!. If the
96
    # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
97
    # and #destroy! raises ActiveFedora::RecordNotDestroyed.
98
    # See ActiveFedora::Callbacks for further details.
99
    def destroy!
1✔
100
      destroy || _raise_record_not_destroyed
×
101
    end
102

103
    def eradicate
1✔
104
      self.class.eradicate(id)
×
105
    end
106

107
    # Used when setting containment
108
    def base_path_for_resource=(path)
1✔
109
      @base_path = path
278✔
110
    end
111

112
    module ClassMethods
1✔
113
      # Creates an object (or multiple objects) and saves it to the repository, if validations pass.
114
      # The resulting object is returned whether the object was saved successfully to the repository or not.
115
      #
116
      # The +attributes+ parameter can be either be a Hash or an Array of Hashes.  These Hashes describe the
117
      # attributes on the objects that are to be created.
118
      #
119
      # ==== Examples
120
      #   # Create a single new object
121
      #   User.create(:first_name => 'Jamie')
122
      #
123
      #   # Create an Array of new objects
124
      #   User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
125
      #
126
      #   # Create a single object and pass it into a block to set other attributes.
127
      #   User.create(:first_name => 'Jamie') do |u|
128
      #     u.is_admin = false
129
      #   end
130
      #
131
      #   # Creating an Array of new objects using a block, where the block is executed for each object:
132
      #   User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
133
      #     u.is_admin = false
134
      #   end
135
      def create(attributes = nil, &block)
1✔
136
        if attributes.is_a?(Array)
×
137
          attributes.collect { |attr| create(attr, &block) }
×
138
        else
139
          object = new(attributes, &block)
×
140
          object.save
×
141
          object
×
142
        end
143
      end
144

145
      # Removes an object's tombstone so another object with the same uri may be created.
146
      # NOTE: this is in violation of the linked data platform and is only here as a convience
147
      # method. It shouldn't be used in the general course of repository operations.
148
      def eradicate(uri)
1✔
149
        gone?(uri) ? delete_tombstone(uri) : false
×
150
      end
151

152
      # Allows the user to find out if an id has been used in the system and then been deleted
153
      # @param uri id in fedora that may or may not have been deleted
154
      def gone?(uri)
1✔
155
        ActiveFedora::Base.find(uri)
×
156
        false
×
157
      rescue Ldp::Gone
158
        true
×
159
      rescue ActiveFedora::ObjectNotFoundError
160
        false
×
161
      end
162

163
      private
1✔
164

165
        def delete_tombstone(uri)
1✔
166
          tombstone = ActiveFedora::Base.id_to_uri(uri) + "/fcr:tombstone"
×
167
          ActiveFedora.fedora.connection.delete(tombstone)
×
168
          true
×
169
        end
170
    end
171

172
    private
1✔
173

174
      def create_or_update(*args)
1✔
175
        raise ReadOnlyRecord if readonly?
467✔
176
        result = new_record? ? _create_record(*args) : _update_record(*args)
467✔
177
        result != false
467✔
178
      end
179

180
      ## begin monkey patch
181

182
      # Deals with preparing new object to be saved to Fedora, then pushes it and its attached files into Fedora.
183
      def _create_record(_options = {})
1✔
184
        assign_rdf_subject
211✔
185
        serialize_attached_files
211✔
186
        begin
187
          @ldp_source = @ldp_source.create
211✔
188
        rescue Ldp::Conflict
189
          _create_record_ldp_source_create_retry
2✔
190
        end
191
        assign_uri_to_contained_resources
211✔
192
        save_contained_resources
211✔
193
        refresh
211✔
194
      end
195

196
      def _create_record_ldp_source_create_retry
1✔
197
        # puts ">>>>>>>>>>>>>>>> _create_record_ldp_source_create_retry <<<<<<<<<<<<<<<<<<<<<"
198
        attempts = 0
2✔
199
        loop do
2✔
200
          break if attempts > 99
2✔
201
          new_id = assign_id
2✔
202
          # puts ">>>>>>>>>>> assign_id=#{assign_id} <<<<<<<<<<<<<"
203
          begin
204
            @ldp_source = LdpResource.new(ActiveFedora.fedora.connection, self.class.id_to_uri(new_id), @resource)
2✔
205
            @ldp_source = @ldp_source.create
2✔
206
            return
2✔
207
          rescue Ldp::Conflict
208
            attempts += 1
×
209
            raise if attempts > 99
×
210
          end
211
        end
212
      end
213

214
      ## end monkey patch
215

216
      def _update_record(_options = {})
1✔
217
        serialize_attached_files
256✔
218
        execute_sparql_update
256✔
219
        save_contained_resources
256✔
220
        refresh
256✔
221
      end
222

223
      def _raise_record_not_destroyed
1✔
224
        @_association_destroy_exception ||= nil
×
225
        raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
×
226
      ensure
227
        @_association_destroy_exception = nil
×
228
      end
229

230
      def refresh
1✔
231
        @ldp_source = build_ldp_resource(id)
568✔
232
        @resource = nil
568✔
233
      end
234

235
      def execute_sparql_update
1✔
236
        change_set = ChangeSet.new(self, resource, changed_attributes.keys)
256✔
237
        return true if change_set.empty?
256✔
238
        ActiveFedora.fedora.ldp_resource_service.update(change_set, self.class, id)
96✔
239
      end
240

241
      # Override to tie in an ID minting service
242
      def assign_id; end
1✔
243

244
      # This is only used when creating a new record. If the object doesn't have an id
245
      # and assign_id can mint an id for the object, then assign it to the resource.
246
      # Otherwise the resource will have the id assigned by the LDP server
247
      def assign_rdf_subject
1✔
248
        @ldp_source = if !id && new_id = assign_id # rubocop:disable Lint/AssignmentInCondition
211✔
249
                        LdpResource.new(ActiveFedora.fedora.connection, self.class.id_to_uri(new_id), @resource)
60✔
250
                      else
251
                        LdpResource.new(ActiveFedora.fedora.connection, @ldp_source.subject, @resource, base_path_for_resource)
151✔
252
                      end
253
      end
254

255
      def base_path_for_resource
1✔
256
        @base_path ||= ActiveFedora.fedora.host + default_base_path_for_resource
151✔
257
      end
258

259
      def default_base_path_for_resource
1✔
260
        init_root_path if has_uri_prefix?
87✔
261
        root_resource_path
87✔
262
      end
263

264
      # Check to see if the :base_path (from fedora.yml) exists in Fedora. If it doesn't exist, then create it.
265
      def init_root_path
1✔
266
        path = root_resource_path.gsub(/^\//, "")
×
267
        ActiveFedora.fedora.connection.head(path)
×
268
      rescue Ldp::NotFound
269
        ActiveFedora.fedora.connection.put(path, "")
×
270
      end
271

272
      def assign_uri_to_contained_resources
1✔
273
        contained_resources.each do |name, source|
211✔
274
          source.uri = "#{uri}/#{name}"
62✔
275
        end
276
      end
277

278
      def save_contained_resources
1✔
279
        contained_resources.changed.each do |_, resource|
467✔
280
          resource.save
7✔
281
        end
282
      end
283

284
      def contained_resources
1✔
285
        @contained_resources ||= attached_files.merge(contained_rdf_sources)
678✔
286
      end
287

288
      def contained_rdf_sources
1✔
289
        @contained_rdf_sources ||=
216✔
290
          AssociationHash.new(self, self.class.contained_rdf_source_reflections)
291
      end
292
  end
293
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc