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)