Class: Scrivito::BasicObj

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming, AttributeContent::ClassMethods
Includes:
AttributeContent
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:



208
209
210
211
212
213
214
215
# File 'lib/scrivito/basic_obj.rb', line 208

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

.attribute(name, type, options = {}) ⇒ Object Originally defined in module AttributeContent::ClassMethods

Defines an attribute.

In order to be able to persist model data in CMS you have to define its attributes. By defining an attribute you tell Scrivito under which name its value should be persisted, which type of content it will contain etc, which values are allowed etc.

Attributes are inherited, e.g. if a model Page defines an attribute title of type string and a model SpecialPage inherits from Page, then the model SpecialPage will also have the attribute title. Inherited attributes can be overridden, e.g. SpecialPage can override the inherited attribute title by defining its own title with a different type for example.

Examples:

Defining attributes

class Page < ::Obj
  attribute :my_string, :string
  attribute 'my_html', 'my_html'
  attribute :my_enum, :enum, values: %w[a b c]
  attribute :my_multienum, :multienum
end

Page.attribute_definitions
#=> #<Scrivito::AttributeDefinitionCollection>

Page.attribute_definitions[:my_string]
#=> #<Scrivito::AttributeDefinition>

Page.attribute_definitions[:my_string].type
#=> "string"

Page.attribute_definitions[:my_html].type
#=> "html"

Page.attribute_definitions[:my_enum].type
#=> "enum"
Page.attribute_definitions[:my_enum].values
#=> ["a", "b", "c"]

Page.attribute_definitions[:my_multienum].type
#=> "multienum"
Page.attribute_definitions[:my_multienum].values
#=> []

Inheriting attributes

class Page < ::Obj
  attribute :title, :string
end

class SpecialPage < Page
end

SpecialPage.attribute_definitions[:title].type
#=> "string"

Overriding inherited attributes

class Page < ::Obj
  attribute :title, :string
end

class SpecialPage < Page
  attribute :title, :html
end

Page.attribute_definitions[:title].type
#=> "string"

SpecialPage.attribute_definitions[:title].type
#=> "html"

Parameters:

  • name (Symbol, String)

    name of the attribute.

  • type (Symbol, String)

    type of the attribute. Scrivito supports following types: string, html, enum, multienum, widgetlist, reference, referencelist and binary.

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

    definition options.

Options Hash (options):

  • :values (Symbol, String)

    allowed values for types enum and multienum. If no values are given for that types, then an empty array will be assumed.

Returns:

  • nil

Raises:

.attribute_definitionsScrivito::AttributeDefinitionCollection Originally defined in module AttributeContent::ClassMethods

Returns the attribute definitions.

Returns:

See Also:

  • Scrivito::AttributeContent.attribute

.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) (defaults to: {})

Returns:

  • (Obj)

    the newly created Obj



114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/scrivito/basic_obj.rb', line 114

def self.create(attributes = {})
  if obj_class = extract_obj_class_from_attributes(attributes)
    obj_class.create(attributes)
  else
    attributes = prepare_attributes_for_instantiation(attributes)
    api_attributes, widget_properties = prepare_attributes_for_rest_api(attributes)
    json = Workspace.current.api_request(:post, '/objs', obj: api_attributes)
    obj = find(json['_id'])
    CmsRestApi::WidgetExtractor.notify_persisted_widgets(obj, widget_properties)
    obj
  end
end

.description_for_editorObject Originally defined in module AttributeContent::ClassMethods

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

.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:



155
156
157
# File 'lib/scrivito/basic_obj.rb', line 155

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:



248
249
250
# File 'lib/scrivito/basic_obj.rb', line 248

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:



221
222
223
# File 'lib/scrivito/basic_obj.rb', line 221

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:



240
241
242
# File 'lib/scrivito/basic_obj.rb', line 240

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:



230
231
232
# File 'lib/scrivito/basic_obj.rb', line 230

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:



257
258
259
# File 'lib/scrivito/basic_obj.rb', line 257

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:



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

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:



169
170
171
# File 'lib/scrivito/basic_obj.rb', line 169

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

.hide_from_editorObject Originally defined in module AttributeContent::ClassMethods

This method disables the creation of Objs or Widgets of the given type using the UI. It does not prevent adding these objects programatically.

By default hide_from_editor is false.

Examples:

Hiding error pages

class ErrorPage < Obj
  hide_from_editor
end

Hiding admin widgets

class AdminWidget < Widget
  hide_from_editor
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:



433
434
435
# File 'lib/scrivito/basic_obj.rb', line 433

def self.homepage
  root
end

.restore(obj_id) ⇒ Object

Restores a previously deleted Obj.

Raises:



980
981
982
983
984
985
# File 'lib/scrivito/basic_obj.rb', line 980

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:



422
423
424
425
426
427
# File 'lib/scrivito/basic_obj.rb', line 422

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>)


288
289
# File 'lib/scrivito/basic_obj.rb', line 288

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:



192
193
194
195
196
197
198
199
200
# File 'lib/scrivito/basic_obj.rb', line 192

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
    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 system or custom attribute specified by its name. Passing an invalid key will not raise an error, but return nil.



567
568
569
570
571
572
573
574
# File 'lib/scrivito/basic_obj.rb', line 567

def [](key)
  key = key.to_s
  if SYSTEM_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:



382
383
384
385
386
387
388
389
390
# File 'lib/scrivito/basic_obj.rb', line 382

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:



695
696
697
# File 'lib/scrivito/basic_obj.rb', line 695

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.



523
524
525
526
# File 'lib/scrivito/basic_obj.rb', line 523

def binary?
  blob_attribute_definition = attribute_definitions['blob']
  blob_attribute_definition.present? && blob_attribute_definition.type == 'binary'
end

#binary_content_typeString?

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

Returns:

  • (String, nil)


709
710
711
# File 'lib/scrivito/basic_obj.rb', line 709

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



702
703
704
# File 'lib/scrivito/basic_obj.rb', line 702

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)


719
720
721
# File 'lib/scrivito/basic_obj.rb', line 719

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)


679
680
681
682
683
684
685
# File 'lib/scrivito/basic_obj.rb', line 679

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

#childrenArray<Obj>

return a list of all child Objs.

Returns:



395
396
397
398
399
# File 'lib/scrivito/basic_obj.rb', line 395

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)


462
463
464
# File 'lib/scrivito/basic_obj.rb', line 462

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)


453
454
455
# File 'lib/scrivito/basic_obj.rb', line 453

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.



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

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.



492
493
494
# File 'lib/scrivito/basic_obj.rb', line 492

def description_for_editor
  display_title
end

#destroyObject

Destroys the Obj in the current Workspace



359
360
361
362
363
364
# File 'lib/scrivito/basic_obj.rb', line 359

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.



505
506
507
# File 'lib/scrivito/basic_obj.rb', line 505

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)


671
672
673
# File 'lib/scrivito/basic_obj.rb', line 671

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

#homepage?Boolean

Returns true if the current obj is the homepage obj.

Returns:

  • (Boolean)


468
469
470
# File 'lib/scrivito/basic_obj.rb', line 468

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

#idObject



135
136
137
# File 'lib/scrivito/basic_obj.rb', line 135

def id
  read_attribute('_id')
end

#last_changedObject



603
604
605
# File 'lib/scrivito/basic_obj.rb', line 603

def last_changed
  read_attribute('_last_changed')
end

#nameObject

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



411
412
413
414
415
416
417
# File 'lib/scrivito/basic_obj.rb', line 411

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

#obj_classScrivito::ObjClass? Originally defined in module AttributeContent

Deprecated.

Returns the obj class of this object.

Returns:

See Also:

#obj_class_nameString Originally defined in module AttributeContent

Returns the obj class name of this object.

Returns:

  • (String)

#parentObject

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



373
374
375
376
377
# File 'lib/scrivito/basic_obj.rb', line 373

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

#pathObject

returns the Obj‘s path as a String.



405
406
407
# File 'lib/scrivito/basic_obj.rb', line 405

def path
  read_attribute('_path')
end

returns the obj’s permalink.



443
444
445
# File 'lib/scrivito/basic_obj.rb', line 443

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.



590
591
592
593
# File 'lib/scrivito/basic_obj.rb', line 590

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:



786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'lib/scrivito/basic_obj.rb', line 786

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)


530
531
532
# File 'lib/scrivito/basic_obj.rb', line 530

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)


482
483
484
# File 'lib/scrivito/basic_obj.rb', line 482

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

#titleObject



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

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:



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

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)


332
333
334
335
336
337
338
# File 'lib/scrivito/basic_obj.rb', line 332

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

#valid_widget_classes_for(field_name) ⇒ nil, Array<Symbol, String, Class> Originally defined in module AttributeContent

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

If nil is returned (default), then all widget classes will be available for this page or widget.

If an Array is returned, then it should include the desired classes. Each class must be either a String, a Symbol or the Class itself. Only these classes will be available and their order will be preserved.

Parameters:

  • field_name (String)

    Name of the widget field.

Returns:

  • (nil, Array<Symbol, String, Class>)

#widgetsScrivito::WidgetCollection

Allows accessing the Widgets of this Obj

Examples:

Access a widget by its id

obj.widgets['widget_id']

Returns:



762
763
764
# File 'lib/scrivito/basic_obj.rb', line 762

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