Specifying Default Attribute Values

Pages and widgets can have attributes for associating them with specific data, e.g. an author name, a background image, a color, etc. Sometimes it is helpful to be able to have a default value assigned to an attribute in the very moment a CMS object or widget is created. This way, editors are given the option to alter a predefined property instead of forcing them to set this property's value for each and every new page or widget.

For this, Obj.create and Widget.new – the methods used for creating a CMS object or widget, respectively – accept an attributes hash as an argument.

For specifying simple defaults, the Obj.attribute and Widget.attribute methods have a corresponding parameter (default, see below for an example).

For specifying more advanced default values, Obj.default_for(attribute_name, &block) and Widget.default_for(attribute_name, &block) are available. The block is called with two arguments:

  1. The first argument is an ActiveSupport::HashWithIndifferentAccess containing the attributes passed to Obj.create_with_defaults or Widget.new_with_defaults, respectively.
  2. The second argument represents the context as a Hash. If the default_for callback is triggered by a UI user creating a CMS object or a Widget, Scrivito places the current_user and the current_page (originating from the UI calling the creation method) into this hash. However, current_page won't be present in the context hash if the user creates the object or widget while viewing a page which isn't a CMS object. Also, the context hash is empty if the object or widget is not created using the UI but, for example, via the console.

Please refer to the documentation on users and permissions, in particular on the Scrivito::Configuration.editing_auth callback, for details about specifying the current user.

Default attribute values that were specified using the default parameter or the default_for method are computed only once for every attribute instance, namely on creation of the CMS object or widget containing the attribute. So, changing this parameter or method does not affect existing attributes, even if they have not yet been accessed.

A simple default can be specified like this:
Copy
class MyPage < Obj
  attribute :title, :string, default: 'Spam'
  attribute :color, :enum, values: %w[red green blue], default: 'green'
end

my_page = MyPage.create_with_defaults
my_page.title # => 'Spam'
my_page.color # => 'green'

To specify a default depending on the given attributes, for example, use default_for:

Copy
class MyPage < Obj
  attribute :title, :string

  default_for :title do |attributes|
    if (path = attributes[:_path]) && path.starts_with('/de')
      'Hier den Titel eingeben'
    else
      'Enter the title here'
    end
  end
end

my_page = MyPage.create(_path: '/en/test')
my_page.title # => 'Enter the title here'

my_page = MyPage.create(_path: '/de/test')
my_page.title # => 'Hier den Titel eingeben'

In the following example, the default depends on the given attributes and the current user:

Copy
class MyPage < Obj
  attribute :title, :string
  default_for :title do |attributes, context|
    if use_german_title?(context[:scrivito_user], attributes[:_path])
      'Hier den Titel eingeben'
    else
      'Enter the title here'
    end
  end

  private

  #
  # Assuming there is a 'MyUser' model with a 'preferences' method returning the preferences
  # of the current user.
  # The 'email' of a 'MyUser' is the 'id' of the corresponding 'Scrivito::User' as set in
  # 'Scrivito::Configuration.editing_auth'.
  #
  def use_german_title?(scrivito_user, path)
    scrivito_user && MyUser.find_by(email: scrivito_user.id).preferences[:locale] == 'de' ||
      path && path.starts_with?('/de')
  end
end

alice = Scrivito::User.define('alice@scrivito.com')
alice.preferences[:locale] # => 'en'

my_page = MyPage.create({_path: '/de/test'}, alice)
my_page.title # => 'Enter the title here'

bob = Scrivito::User.define('bob@scrivito.com')
bob.preferences[:locale] # => 'de'
my_page = MyPage.create({_path: '/en/test'}, bob)
my_page.title # => 'Hier den Titel eingeben'