lib/scrivito/attribute_content.rb in scrivito_sdk-0.66.0 vs lib/scrivito/attribute_content.rb in scrivito_sdk-0.70.0.rc1
- old
+ new
@@ -1,9 +1,12 @@
module Scrivito
-#
+# This class is for handling attributes: setting and accessing their values, providing
+# default values, restricting the types of widgets that may be added to a +widgetlist+
+# attribute, plus a couple of convenience methods.
# @api public
+# @see http://scrivito.com/attribute-types Attributes and their type
#
module AttributeContent
ATTRIBUTE_TYPES = %w[
binary
date
@@ -22,12 +25,10 @@
COMPATIBLE_ATTRIBUTE_TYPES = [
%w[enum string],
%w[html string],
%w[multienum stringlist],
%w[string html],
- %w[string],
- %w[widgetlist],
]
#
# @api public
#
@@ -77,35 +78,37 @@
has_custom_attribute?(attribute_name) ? read_attribute(attribute_name) : super
end
#
# Returns the value of an attribute specified by its name.
- # Passing an invalid key will not raise an error, but return +nil+.
+ # Passing an invalid key will not raise an error but return +nil+.
#
# @api public
# @param [Symbol, String] attribute_name the name of the attribute.
- # @return the value of the attribute if it defined or +nil+ otherwise.
+ # @return the value of the attribute if it's defined or +nil+ otherwise.
#
def [](attribute_name)
attribute_name = attribute_name.to_s
read_attribute(attribute_name) if has_attribute?(attribute_name)
end
#
- # Hook method to control which widget classes should be available for this page
- # or widget. Override it to allow only certain classes or none.
+ # Hook method that lets you control the widget classes that are made available for adding
+ # instances of them to this page or widget. Override it to allow only specific classes
+ # or none at all.
# Must return either +NilClass+, or +Array+.
#
- # If +nil+ is returned (default), then all widget classes will be available for this page or widget.
+ # If +nil+ is returned (default), 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.
+ # If an +Array+ is returned, it is expected to include the permitted classes.
+ # Their order is preserved as they are offered to the user via the widget browser.
#
# @api public
- # @param [String] field_name Name of the widget field.
+ # @param [String] field_name Name of the widget attribute.
# @return [nil, Array<Class>]
+ # @see http://scrivito.com/limiting-widget-and-page-types Limiting available widget and page types
#
def valid_widget_classes_for(field_name)
end
def valid_widget_ruby_classes_for(field)
@@ -140,11 +143,11 @@
end
end
end
#
- # Returns the obj class name of this object.
+ # Returns the object class name of this CMS object.
# @api public
# @return [String]
#
def obj_class_name
data_from_cms.value_of('_obj_class')
@@ -199,10 +202,22 @@
else
@data_from_cms
end
end
+ #
+ # Returns a hash to be used for the JSON serialization.
+ # @api public
+ # @note Override it in subclasses to fit your needs.
+ # @param [Hash] options
+ # @return [Hash]
+ # @see http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html
+ #
+ def as_json(options = nil)
+ {id: id}
+ end
+
private
attr_writer :data_from_cms
def value_of_attribute(attribute_name)
@@ -247,13 +262,13 @@
#
# @api public
#
module ClassMethods
#
- # Instantiate an Obj or Widget instance from obj_data.
- # If a subclass of Obj or Widget with the same name as the property +_obj_class+ exists,
- # the instantiated Obj or Widget will be an instance of that subclass.
+ # Instantiate an {BasicObj Obj} or {BasicWidget Widget} instance from +obj_data+.
+ # If a subclass of +Obj+ or +Widget+ with the same name as the +_obj_class+ property exists,
+ # the instantiated +Obj+ or +Widget+ will be an instance of that subclass.
#
def instantiate(obj_data)
obj_class = obj_data.value_of('_obj_class')
instance = type_computer.compute_type(obj_class).allocate
@@ -277,37 +292,39 @@
#
# Defines an attribute.
#
# @api public
#
- # 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.
+ # For the purpose of persisting model data in the CMS, the attributes of the model need
+ # to be defined. When defining an attribute, you specify the name under which Scrivito
+ # should persist its value as well as the type of content it is meant to contain, and,
+ # for the +enum+ and +multienum+ types, the selectable values.
#
- # 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.
+ # Attributes are inherited. If, for example, the +Page+ model defines a +title+ attribute
+ # of the +string+ type, the +SpecialPage+ model, which inherits from +Page+, is also equipped
+ # with +title+. Inherited attributes can be overridden, i.e. you may redefine +title+ in
+ # +SpecialPage+ if you want its type to be +html+, for example.
#
# @param [Symbol, String] name name of the attribute.
- # @param [Symbol, String] type type of the attribute. Scrivito supports following types:
+ # @param [Symbol, String] type type of the attribute. Scrivito supports the following types:
# +string+, +stringlist+, +html+, +enum+, +multienum+, +widgetlist+, +reference+,
- # +referencelist+, +link+, +linklist+ and +binary+.
+ # +referencelist+, +link+, +linklist+, and +binary+.
# @param [Hash] options definition options.
#
- # @option options [Symbol, String] :values allowed values for types +enum+ and +multienum+.
- # If no values are given for that types, then an empty array will be assumed.
+ # @option options [Symbol, String] :values selectable values for +enum+ and +multienum+ attributes.
+ # If no values are provided for attributes of these types, the resulting array of selectable
+ # values is empty.
# @option options [Symbol, String] :default custom default value.
# See {Scrivito::AttributeContent::DEFAULT_ATTRIBUTE_VALUES} for factory defaults.
- # See {Scrivito::AttributeContent::ClassMethods#default_for} for more advanced default settings.
+ # See {Scrivito::AttributeContent::ClassMethods#default_for} for more advanced defaults.
#
# @return nil
# @raise [Scrivito::ScrivitoError] if the +type+ is unknown
# @see Scrivito::AttributeContent::DEFAULT_ATTRIBUTE_VALUES
# @see Scrivito::AttributeContent::ClassMethods#default_for
#
- # @example Defining attributes
+ # @example Defining attributes:
# class Page < ::Obj
# attribute :my_string, :string
# attribute 'my_html', 'my_html'
# attribute :my_enum, :enum, values: %w[a b c], default: 'a'
# attribute :my_multienum, :multienum
@@ -333,22 +350,22 @@
# Page.attribute_definitions[:my_multienum].type
# #=> "multienum"
# Page.attribute_definitions[:my_multienum].values
# #=> []
#
- # @example Inheriting attributes
+ # @example Inheriting attributes:
# class Page < ::Obj
# attribute :title, :string
# end
#
# class SpecialPage < Page
# end
#
# SpecialPage.attribute_definitions[:title].type
# #=> "string"
#
- # @example Overriding inherited attributes
+ # @example Overriding inherited attributes:
# class Page < ::Obj
# attribute :title, :string
# end
#
# class SpecialPage < Page
@@ -359,59 +376,64 @@
# #=> "string"
#
# SpecialPage.attribute_definitions[:title].type
# #=> "html"
#
+ # @see http://scrivito.com/default-attribute-values Specifying default attribute values
+ #
def attribute(name, type, options = {})
- name, type, options = name, type, options
- assert_valid_attribute_name(name.to_s)
- assert_valid_attribute_type(type.to_s)
+ name, type, options = name.to_s, type.to_s, options
+ assert_valid_attribute_name(name)
+ assert_valid_attribute_type(type)
default = options.delete(:default) || options.delete('default')
- own_attribute_definitions[name.to_s] = AttributeDefinition.new(name, type, options)
- default_for(name) { default } if default
+ if default
+ assert_valid_attribute_default(name, type, default)
+ default_for(name) { default }
+ end
+ own_attribute_definitions[name] = AttributeDefinition.new(name, type, options)
nil
end
#
- # Sets a default for an attribute.
+ # Sets the default value of an attribute.
#
# @api public
#
# If {Scrivito::BasicObj.create Obj.create} or {Scrivito::BasicWidget.new Widget.new} are called
- # with no value provided for attribute +attribute_name+, then the +block+ will be called and its
- # return value will be set as the attribute's value.
+ # without providing a value for a specific custom attribute, the +block+ is called, and its
+ # return value is used as the initial value of this attribute.
#
- # The +block+ will be called with two parameters.
+ # The +block+ is called with two parameters.
#
- # The first parameter is an +ActiveSupport::HashWithIndifferentAccess+ containing attributes,
- # which were provided to {Scrivito::BasicObj.create Obj.create} or
+ # The first parameter is an +ActiveSupport::HashWithIndifferentAccess+ containing the attributes
+ # that were passed to {Scrivito::BasicObj.create Obj.create} or
# {Scrivito::BasicWidget.new Widget.new}.
#
- # The second parameter is a +Hash+ containing the context, which were provided to
- # {Scrivito::BasicObj.create Obj.create} or {Scrivito::BasicWidget.new Widget.new}. If there is
- # a current visitor of type {Scrivito::User}, then it can be accessed under the key
- # +:scrivito_user+ in the provided context.
+ # The second parameter is a +Hash+ containing the context that was handed over to
+ # {Scrivito::BasicObj.create Obj.create} or {Scrivito::BasicWidget.new Widget.new}. If the
+ # current visitor is a {Scrivito::User}, this user can be accessed by means of the
+ # +:scrivito_user+ key contained in the provided context.
#
# @param [Symbol, String] attribute_name the name of the attribute.
# @param [Proc] block that returns the default value.
- # @raise [Scrivito::ScrivitoError] if no block given
+ # @raise [Scrivito::ScrivitoError] if no block is present
# @return nil
#
# @see Scrivito::BasicObj.create
# @see Scrivito::BasicWidget.new
# @see Scrivito::Configuration.editing_auth
#
- # @example A simple default
+ # @example Setting a simple default:
# class MyPage < Obj
# attribute :title, :string
# default_for(:title) { 'Spam' }
# end
#
# my_page = MyPage.create
# my_page.title # => 'Spam'
#
- # @example A default depending on the given attributes
+ # @example A default depending on the given attributes:
# class MyPage < Obj
# attribute :title, :string
#
# default_for :title do |attributes|
# if (path = attributes[:_path]) && path.starts_with('/de')
@@ -426,11 +448,11 @@
# my_page.title # => 'Your title here'
#
# my_page = MyPage.create(_path: '/de/test')
# my_page.title # => 'Hier den Titel eingeben'
#
- # @example A more complex default depending on the given attributes and the current user
+ # @example A more complex default, depending on the given attributes and the current user:
# class MyPage < Obj
# attribute :title, :string
#
# default_for :title do |attributes, context|
# if use_german_title?(context[:scrivito_user], attributes[:_path])
@@ -441,12 +463,12 @@
# end
#
# private
#
# #
- # # Assuming there is a model +MyUser+ with a +preferences+ method returning the preferences
- # # of the current user.
+ # # Assuming there is a +MyUser+ model equipped with a +preferences+ method which
+ # # returns 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' ||
@@ -464,10 +486,12 @@
# bob.preferences[:locale] # => 'de'
#
# my_page = MyPage.create({_path: '/en/test'}, bob)
# my_page.title # => 'Hier den Titel eingeben'
#
+ # @see http://scrivito.com/default-attribute-values Specifying default attribute values
+ #
def default_for(attribute_name, &block)
attribute_name = attribute_name.to_s
raise ScrivitoError, 'No block given' unless block_given?
attribute_defaults[attribute_name] = block
nil
@@ -478,13 +502,13 @@
# Short description of a CMS object or widget type for the UI. The description is displayed
# when adding new pages or widgets, for example. As a general rule, it is used whenever no
# widget or object instance is available. If there is, the +BasicObj#description_for_editor+
# and, respectively, +BasicWidget#description_for_editor+ instance methods are used instead.
#
- # This method can be overridden to customize the description displayed to the editor.
+ # This method can be overridden to customize the description displayed to editors.
#
- # @return [String] the name of the +Class+
+ # @return [String] the +Class+ name
def description_for_editor
name
end
#
@@ -496,11 +520,11 @@
#
def attribute_definitions
AttributeDefinitionCollection.new(all_attribute_definitions)
end
- # For test purpose only.
+ # For testing purposes only.
def reset_attribute_defaults!
@attribute_defaults = nil
end
def build_attributes_with_defaults(attributes = {}, context = {})
@@ -524,21 +548,21 @@
attributes_with_defaults
end
# @api public
#
- # This method disables the creation of +Objs+ or +Widgets+ of the given type using the UI.
- # It does not prevent adding these objects programatically.
+ # This method prevents UI users from creating +Objs+ or +Widgets+ of the given type.
+ # It does not prevent adding such objects programatically.
#
- # By default +hide_from_editor+ is +false+.
+ # By default, +hide_from_editor+ is +false+.
#
- # @example Hiding error pages
+ # @example Hiding error pages:
# class ErrorPage < Obj
# hide_from_editor
# end
#
- # @example Hiding admin widgets
+ # @example Hiding admin widgets:
# class AdminWidget < Widget
# hide_from_editor
# end
def hide_from_editor
@hide_from_editor = true
@@ -569,9 +593,18 @@
end
end
def assert_valid_attribute_type(type)
raise ScrivitoError, "Unknown attribute type '#{type}'" unless ATTRIBUTE_TYPES.include?(type)
+ end
+
+ def assert_valid_attribute_default(name, type, default)
+ inlined_default_allowed = ['string', 'stringlist', 'enum', 'multienum', 'html']
+ unless inlined_default_allowed.include?(type)
+ raise ScrivitoError, "Attribute '#{name}': " \
+ "Inline defaults for '#{type}' attributes are not supported. " \
+ "Please use 'default_for(:#{name})' for '#{type}' attributes instead."
+ end
end
def all_attribute_definitions
if superclass.respond_to?(:all_attribute_definitions, true)
superclass.all_attribute_definitions.merge(own_attribute_definitions)