Class: Scrivito::BasicObj

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming
Defined in:
lib/scrivito/basic_obj.rb

Overview

Note:

Please do not use BasicObj directly, as it is intended as an abstract class. Always use Obj or a subclass of Obj.

The abstract base class for cms objects.

Direct Known Subclasses

Obj

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Scrivito::AttributeContent

Class Method Details

.allObjSearchEnumerator

Returns a ObjSearchEnumerator of all Objs. If invoked on a subclass of Obj, the result will be restricted to instances of that subclass.

Returns:

Raises:



186
187
188
189
190
191
192
193
194
# File 'lib/scrivito/basic_obj.rb', line 186

def self.all
  assert_not_basic_obj('.all')
  if self == ::Obj
    Workspace.current.objs.all
  else
    assert_has_obj_class('.all')
    find_all_by_obj_class(name)
  end
end

.create(attributes) ⇒ Obj

Create a new Obj in the cms

This allows you to set the different attributes types of an obj by providing a hash with the attributes names as key and the values you want to set as values

Examples:

Reference lists have to be provided as an Array of Objs

Obj.create(:reference_list => [other_obj])

Passing an Obj allows you to set a reference

Obj.create(:reference => other_obj)

you can upload files by passing a ruby File object

Obj.create(:blob => File.new("image.png"))

Link list can be set as an Array of Links

Obj.create(:link_list => [
  # external link
  Link.new(:url => "http://www.example.com", :title => "Example"),
  # internal link
  Link.new(:obj => other_obj, :title => "Other Obj")
])

Passing a Link allows you to set a link.

Obj.create(
  external_link: Link.new(url: 'http://www.example.com', title: 'Example')
  internal_link: Link.new(obj: other_obj, title: 'Other Obj')
)

Dates attributes accept Time, Date and their subclasses (DateTime for example)

Obj.create(:date => Time.new)
Obj.create(:date => Date.now)

String, text, html and enum can be set by passing a String value

Obj.create(:title => "My Title")

Arrays of Strings allow you to set multi enum fields

Obj.create(:tags => ["ruby", "rails"])

Simply pass an Array of Widgets to change a widget field. See Widget#copy on how to copy a widget.

# Add new widgets
Obj.create(:widgets => [Widget.new(_obj_class: 'TitleWidget', title: 'My Title')])

# Add a widget copy
Obj.create(:widgets => [another_obj.widgets.first.copy])

# Changing a widget field
obj.update(:widgets => [obj.widgets.first])

# Clear a widget field
obj.update(:widgets => [])

Parameters:

  • attributes (Hash)

Returns:

  • (Obj)

    the newly created Obj



95
96
97
98
99
100
101
102
# File 'lib/scrivito/basic_obj.rb', line 95

def self.create(attributes)
  attributes = with_default_obj_class(attributes)
  api_attributes, widget_properties = prepare_attributes_for_rest_api(attributes, nil)
  json = Workspace.current.api_request(:post, '/objs', obj: api_attributes)
  obj = find(json['_id'])
  CmsRestApi::WidgetExtractor.notify_persisted_widgets(obj, widget_properties)
  obj
end

.find(id_or_list) ⇒ Obj+

Find a Obj by its id. If the parameter is an Array containing ids, return a list of corresponding Objs.

Parameters:

  • id_or_list (String, Integer, Array<String, Integer>)

Returns:



132
133
134
# File 'lib/scrivito/basic_obj.rb', line 132

def self.find(id_or_list)
  Workspace.current.objs.find(id_or_list)
end

.find_all_by_name(name) ⇒ ObjSearchEnumerator

Returns a ObjSearchEnumerator of all Objs with the given name.

Parameters:

  • name (String)

    Name of the Obj.

Returns:



227
228
229
# File 'lib/scrivito/basic_obj.rb', line 227

def self.find_all_by_name(name)
  where(:_name, :equals, name)
end

.find_all_by_obj_class(obj_class) ⇒ ObjSearchEnumerator

Returns a ObjSearchEnumerator of all Objs with the given obj_class.

Parameters:

  • obj_class (String)

    Name of the ObjClass.

Returns:



200
201
202
# File 'lib/scrivito/basic_obj.rb', line 200

def self.find_all_by_obj_class(obj_class)
  Workspace.current.objs.find_all_by_obj_class(obj_class)
end

.find_by_name(name) ⇒ Obj

Find an Obj with the given name. If several Objs with the given name exist, an arbitrary one of these Objs is chosen and returned. If no Obj with the name exits, nil is returned.

Parameters:

  • name (String)

    Name of the Obj.

Returns:



219
220
221
# File 'lib/scrivito/basic_obj.rb', line 219

def self.find_by_name(name)
  where(:_name, :equals, name).batch_size(1).first
end

.find_by_path(path) ⇒ Obj

Find the Obj with the given path. Returns nil if no matching Obj exists.

Parameters:

  • path (String)

    Path of the Obj.

Returns:



209
210
211
# File 'lib/scrivito/basic_obj.rb', line 209

def self.find_by_path(path)
  Workspace.current.objs.find_by_path(path)
end

Returns the Obj with the given permalink, or nil if no matching Obj exists.

Parameters:

  • permalink (String)

    The permalink of the Obj.

Returns:



236
237
238
# File 'lib/scrivito/basic_obj.rb', line 236

def self.find_by_permalink(permalink)
  Workspace.current.objs.find_by_permalink(permalink)
end

.find_by_permalink!(permalink) ⇒ Obj

Returns the Obj with the given permalink, or raise ResourceNotFound if no matching Obj exists.

Parameters:

  • permalink (String)

    The permalink of the Obj.

Returns:



245
246
247
248
# File 'lib/scrivito/basic_obj.rb', line 245

def self.find_by_permalink!(permalink)
  find_by_permalink(permalink) or
    raise ResourceNotFound, "Could not find Obj with permalink '#{permalink}'"
end

.find_including_deleted(id_or_list) ⇒ Obj+

Find a Obj by its id. If the parameter is an Array containing ids, return a list of corresponding Objs. The results include deleted objects as well.

Parameters:

  • id_or_list (String, Integer, Array<String, Integer>)

Returns:



146
147
148
# File 'lib/scrivito/basic_obj.rb', line 146

def self.find_including_deleted(id_or_list)
  Workspace.current.objs.find_including_deleted(id_or_list)
end

.homepageObj

Returns the homepage obj. This can be overwritten in your application’s Obj. Use #homepage? to check if an obj is the homepage.

Returns:



400
401
402
# File 'lib/scrivito/basic_obj.rb', line 400

def self.homepage
  root
end

.restore(obj_id) ⇒ Object

Restores a previously deleted Obj.

Raises:



967
968
969
970
971
972
# File 'lib/scrivito/basic_obj.rb', line 967

def restore(obj_id)
  Workspace.current.assert_revertable
  base_revision_path = "revisions/#{Workspace.current.base_revision_id}/objs/#{obj_id}"
  obj_attributes = CmsRestApi.get(base_revision_path).merge('_id' => obj_id)
  Workspace.current.api_request(:post, '/objs', obj: obj_attributes)
end

.rootObj

Returns the root Obj, i.e. the Obj with the path “/”

Returns:



389
390
391
392
393
394
# File 'lib/scrivito/basic_obj.rb', line 389

def self.root
  BasicObj.find_by_path('/') or raise ResourceNotFound,
      '"Obj.root" not found: There is no "Obj" with path "/". '\
      'Maybe you forgot the migration when setting up your Scrivito application? '\
      'Try "bundle exec rake scrivito:migrate scrivito:migrate:publish".'
end

.valid_page_classes_beneath(parent_path) ⇒ NilClass, Array<Symbol, String>

Hook method to control which page classes should be available for a page with given path. Override it to allow only certain classes or none. Must return either NilClass, or Array.

Be aware that the given argument is a parent path. E.g. when creating a page with path /products/shoes then the argument will be /products.

If NilClass is returned, then all possible classes will be available. By default NilClass is returned.

If Array is returned, then it should include desired class names. Each class name must be either a String or a Symbol. Only this class names will be available. Order of the class names will be preserved.

Parameters:

  • parent_path (String)

    Path of the parent obj

Returns:

  • (NilClass, Array<Symbol, String>)


267
268
# File 'lib/scrivito/basic_obj.rb', line 267

def self.valid_page_classes_beneath(parent_path)
end

.where(field, operator, value, boost = nil) ⇒ ObjSearchEnumerator

Note:

If invoked on a subclass of Obj, the result will be restricted to instances of that subclass.

Returns a ObjSearchEnumerator with the given initial subquery consisting of the four arguments.

Note that field and value can also be arrays for searching several fields or searching for several values.

ObjSearchEnumerators can be chained using one of the chainable methods (e.g. ObjSearchEnumerator#and and ObjSearchEnumerator#and_not).

Examples:

Look for the first 10 Objs whose ObjClass is “Pressrelease” and whose title contains “quarterly”:

Obj.where(:_obj_class, :equals, 'Pressrelease').and(:title, :contains, 'quarterly').take(10)

Parameters:

Returns:

Raises:



169
170
171
172
173
174
175
176
177
178
# File 'lib/scrivito/basic_obj.rb', line 169

def self.where(field, operator, value, boost = nil)
  assert_not_basic_obj('.where')
  if self == ::Obj
    Workspace.current.objs.where(field, operator, value, boost)
  else
    assert_has_obj_class('.where')
    Workspace.current.objs.where(:_obj_class, :equals, name)
        .and(field, operator, value, boost)
  end
end

Instance Method Details

#[](key) ⇒ Object

Returns the value of an internal or external attribute specified by its name. Passing an invalid key will not raise an error, but return nil.



539
540
541
542
543
544
545
546
# File 'lib/scrivito/basic_obj.rb', line 539

def [](key)
  key = key.to_s
  if INTERNAL_KEYS.include?(key)
    read_attribute(key)
  else
    super
  end
end

#ancestorsArray<Obj>

Returns an Array of all the ancestor objects, starting at the root and ending at this object’s parent.

Returns:



349
350
351
352
353
354
355
356
357
# File 'lib/scrivito/basic_obj.rb', line 349

def ancestors
  return [] unless child_path?

  ancestor_paths = parent_path.scan(/\/[^\/]+/).inject([""]) do |list, component|
    list << list.last + component
  end
  ancestor_paths[0] = "/"
  Workspace.current.objs.find_by_paths(ancestor_paths)
end

#binaryBinary?

This method is intended for Objs that represent binary resources like images or pdf documents. If this Obj represents a binary file, an instance of Scrivito::Binary is returned.

This method returns the attribute blob if it is of the type binary.

Returns:



667
668
669
# File 'lib/scrivito/basic_obj.rb', line 667

def binary
  self[:blob] if self[:blob].is_a?(Binary)
end

#binary?Boolean

This method indicates if the Obj represents binary data. Binaries are handled differently in that they are not rendered using the normal layout but sent as a file. Examples of binary resources are Images or PDFs.

Every Obj that has an attribute blob of the type binary is considered a binary

Returns:

  • (Boolean)

    true if this Obj represents a binary resource.



491
492
493
494
495
496
497
498
# File 'lib/scrivito/basic_obj.rb', line 491

def binary?
  if obj_type = read_attribute('_obj_type')
    [:image, :generic].include?(obj_type.to_sym)
  else
    blob_attribute = obj_class.attributes['blob']
    blob_attribute && blob_attribute.type == 'binary'
  end
end

#binary_content_typeString?

This method returns the content type of the binary of this obj if it is set.

Returns:

  • (String, nil)


681
682
683
# File 'lib/scrivito/basic_obj.rb', line 681

def binary_content_type
  binary.try(:content_type)
end

#binary_lengthFixnum

This method returns the length in bytes of the binary of this obj

Returns:

  • (Fixnum)

    If no binary is set it will return 0



674
675
676
# File 'lib/scrivito/basic_obj.rb', line 674

def binary_length
  binary.try(:content_length) || 0
end

#binary_urlString?

This method returns the url under which the content of this binary is available to the public if the binary is set.

See Scrivito::Binary#url for details

Returns:

  • (String, nil)


691
692
693
# File 'lib/scrivito/basic_obj.rb', line 691

def binary_url
  binary.try(:url)
end

#bodyString

Returns the body (main content) of the Obj for non-binary Objs. Returns nil for binary Objs.

Returns:

  • (String)


651
652
653
654
655
656
657
# File 'lib/scrivito/basic_obj.rb', line 651

def body
  if binary?
    nil
  else
    read_attribute('body')
  end
end

#childrenArray<Obj>

return a list of all child Objs.

Returns:



362
363
364
365
366
# File 'lib/scrivito/basic_obj.rb', line 362

def children
  return [] unless path

  workspace.objs.find_by_parent_path(path)
end

#controller_action_nameString

This method determines the action that should be invoked when the Obj is requested. The default action is ‘index’. Overwrite this method to force a different action to be used.

Returns:

  • (String)


430
431
432
# File 'lib/scrivito/basic_obj.rb', line 430

def controller_action_name
  "index"
end

#controller_nameString

This method determines the controller that should be invoked when the Obj is requested. By default a controller matching the Obj’s obj_class will be used. If the controller does not exist, the CmsController will be used as a fallback. Overwrite this method to force a different controller to be used.

Returns:

  • (String)


421
422
423
# File 'lib/scrivito/basic_obj.rb', line 421

def controller_name
  obj_class_name
end

#copy(options = {}) ⇒ Obj

Creates a copy of the Obj.

Examples:

Copy a blog post.

blog_post = Obj.find_by_path('/blog/first_post')
blog_post.copy(_path: '/blog/second_post')

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :_path (String, Symbol) — default: nil

    the path of the copy.

  • :_id (String, Symbol) — default: nil

    the id of the copy.

  • :_permalink (String, Symbol) — default: nil

    the permalink of the copy.

Returns:

  • (Obj)

    the created copy

Raises:

  • (ArgumentError)

    if options includes invalid keys.



318
319
320
321
322
# File 'lib/scrivito/basic_obj.rb', line 318

def copy(options={})
  options = options.stringify_keys.assert_valid_keys('_path', '_id', '_permalink')
  json = workspace.api_request(:post, '/objs', obj: copyable_attributes.merge(options))
  self.class.find(json['_id'])
end

#description_for_editorObject

This method determines the description that is shown in the UI and defaults to #display_title. It can be overriden by a custom value.



460
461
462
# File 'lib/scrivito/basic_obj.rb', line 460

def description_for_editor
  display_title
end

#destroyObject

Destroys the Obj in the current Workspace



326
327
328
329
330
331
# File 'lib/scrivito/basic_obj.rb', line 326

def destroy
  if children.any?
    raise ClientError.new(I18n.t('scrivito.errors.models.basic_obj.has_children'), 412)
  end
  workspace.api_request(:delete, "/objs/#{id}")
end

#display_titleString

Calculates appropriate title for an Obj.

Returns:

  • (String)

    Scrivito::Binary#filename if Obj is binary and has a filename.

  • (String)

    #title if Obj has a non-empty title.

  • (String)

    a placeholder <untitled MyClass> otherwise.



473
474
475
# File 'lib/scrivito/basic_obj.rb', line 473

def display_title
  (binary_title || title).presence || "<untitled #{obj_class_name}>"
end

#file_extensionString

returns the extension (the part after the last dot) from the Obj’s name. returns an empty string if no extension is present in the Obj’s name.

Returns:

  • (String)


643
644
645
# File 'lib/scrivito/basic_obj.rb', line 643

def file_extension
  File.extname(name)[1..-1] || ""
end

#homepage?Boolean

Returns true if the current obj is the homepage obj.

Returns:

  • (Boolean)


436
437
438
# File 'lib/scrivito/basic_obj.rb', line 436

def homepage?
  self == self.class.homepage
end

#idObject



112
113
114
# File 'lib/scrivito/basic_obj.rb', line 112

def id
  read_attribute('_id')
end

#last_changedObject



575
576
577
# File 'lib/scrivito/basic_obj.rb', line 575

def last_changed
  read_attribute('_last_changed')
end

#nameObject

returns the Obj‘s name, i.e. the last component of the path.



378
379
380
381
382
383
384
# File 'lib/scrivito/basic_obj.rb', line 378

def name
  if child_path?
    path.match(/[^\/]+$/)[0]
  else
    ""
  end
end

#parentObject

return the Obj that is the parent of this Obj. returns nil for the root Obj.



340
341
342
343
344
# File 'lib/scrivito/basic_obj.rb', line 340

def parent
  if child_path?
    workspace.objs.find_by_path(parent_path)
  end
end

#pathObject

returns the Obj‘s path as a String.



372
373
374
# File 'lib/scrivito/basic_obj.rb', line 372

def path
  read_attribute('_path')
end

returns the obj’s permalink.



411
412
413
# File 'lib/scrivito/basic_obj.rb', line 411

def permalink
  read_attribute('_permalink')
end

#reloadObject

Reloads the attributes of this object from the database. Notice that the ruby class of this Obj instance will NOT change, even if the obj_class in the database has changed.



562
563
564
565
# File 'lib/scrivito/basic_obj.rb', line 562

def reload
  workspace.reload
  reload_data
end

#revertObject

Note:

This method does not support Objs, which are new. Please use Obj#destroy to destroy them.

Note:

This method does not support Objs, which are deleted. Please use Obj.restore to restore them.

Reverts all changes made to the Obj in the current workspace.

Raises:



758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
# File 'lib/scrivito/basic_obj.rb', line 758

def revert
  assert_revertable

  if modification == Modification::EDITED
    base_revision_path = "revisions/#{workspace.base_revision_id}/objs/#{id}"
    previous_attributes = CmsRestApi.get(base_revision_path).except('_id')
    previous_widget_pool = previous_attributes['_widget_pool']

    ids_of_new_widgets = read_widget_pool.keys - previous_widget_pool.keys
    ids_of_new_widgets.each { |widget_id| previous_widget_pool[widget_id] = nil }

    workspace.api_request(:put, "/objs/#{id}", obj: previous_attributes)
    reload
  end
end

#root?Boolean

Returns true if this object is the root object.

Returns:

  • (Boolean)


502
503
504
# File 'lib/scrivito/basic_obj.rb', line 502

def root?
  path == "/"
end

#slugString

This method is used to calculate a part of a URL of this Obj.

The routing schema: <obj.id>/<obj.slug>

The default is parameterize on obj.title.

You can customize this part by overwriting #slug.

Returns:

  • (String)


450
451
452
# File 'lib/scrivito/basic_obj.rb', line 450

def slug
  (title || '').parameterize
end

#titleObject



478
479
480
# File 'lib/scrivito/basic_obj.rb', line 478

def title
  read_attribute('title')
end

#toclist(*args) ⇒ Array<Obj>

Returns a list of children excluding the binary? ones unless :all is specfied. This is mainly used for navigations.

Returns:



510
511
512
513
514
515
# File 'lib/scrivito/basic_obj.rb', line 510

def toclist(*args)
  return [] if binary?
  toclist = children
  toclist = toclist.reject { |toc| toc.binary? } unless args.include?(:all)
  toclist
end

#update(attributes) ⇒ Object

Update the Obj with the attributes provided.

For an overview of which values you can set via this method see the documentation of Obj.create.

Additionally, update accepts a _widget_pool hash in attributes to modify widgets. The keys of _widget_pool are widget instances, the values are the modified attributes of these particular widgets.

Examples:

Move the widget_to_move widget from the left widget field of the two_column_widget1 widget to left of two_column_widget2:

obj.update(
  _widget_pool: {
    two_column_widget1 => {left: two_column_widget1.left - [widget_to_move]},
    two_column_widget2 => {left: two_column_widget2.left + [widget_to_move]}
  },
  headline: "Some widgets were moved!"
)

Move the widget_to_move widget from the right widget field of the two_column_widget1 widget to the top-level widget field main_content:

obj.update(
  main_content: @obj.main_content + [widget_to_move],
  _widget_pool: {
    two_column_widget1 => {
      right: two_column_widget1.right - [widget_to_move]
    }
  }
)

Parameters:

  • attributes (Hash)


299
300
301
302
303
304
305
# File 'lib/scrivito/basic_obj.rb', line 299

def update(attributes)
  api_attributes, widget_properties = prepare_attributes_for_rest_api(attributes)
  workspace.api_request(:put, "/objs/#{id}", obj: api_attributes)
  reload_data
  CmsRestApi::WidgetExtractor.notify_persisted_widgets(self, widget_properties)
  self
end

#widgetsScrivito::WidgetCollection

Allows accessing the Widgets of this Obj

Examples:

Access a widget by its id

obj.widgets['widget_id']

Returns:



734
735
736
# File 'lib/scrivito/basic_obj.rb', line 734

def widgets
  @widgets ||= WidgetCollection.new(self)
end