module Formality

Constants

VERSION

Attributes

id[RW]

Public Instance Methods

assign(new_attributes) click to toggle source

Assigns a hash of attributes to the form. Only assigns values if the key for that value is a declared attribute. It silently ignores non-declared keys.

# File lib/formality.rb, line 112
def assign(new_attributes)
  new_attributes.each do |name, value|
    next unless attribute?(name)
    send("#{name}=", value)
  end
  self.id = new_attributes[:id]
  self
end
attribute?(name) click to toggle source

Returns a Boolean that answers the question: Is this ‘name` a declared attribute?

# File lib/formality.rb, line 123
def attribute?(name)
  attribute_names.include?(name.to_s)
end
attribute_names() click to toggle source

Returns an Array of attribute names (Strings).

# File lib/formality.rb, line 95
def attribute_names
  self.class.attributes.to_a
end
attributes() click to toggle source

Returns a HashWithIndifferentAccess of all the defined attributes and their values.

# File lib/formality.rb, line 101
def attributes
  hash = ActiveSupport::HashWithIndifferentAccess.new
  attribute_names.each_with_object({}) do |name|
    hash[name] = send(name)
  end
  hash
end
invalid() { || ... } click to toggle source

Same as :valid, but in reverse: only yields to the block if the form is invalid.

# File lib/formality.rb, line 183
  def invalid; yield if invalid? end

  #
  # Nesting
  # =======
  #
  # Allows forms to have forms nested within them that
  # work nicely with Rails' :fields_for method.
  #
  # Validations are called on nested forms, so that if
  # any nested form is invalid, so is the parent.
  #

  module ClassMethods
    # Singular Nesting.
    def nest_one(child, options={})
      add_nested_form(child)
      define_nested_form_one(child, options)
    end

    # Plural nesting.
    #
    # Works just like :nest_one, except it works for
    # an Array of nested forms.
    def nest_many(children, options={})
      add_nested_form(children)
      define_nested_form_many(children, options)
    end

    # Keep track of what forms we've nested.
    def nested_forms
      @__nested_forms ||= Set.new
    end

    private

    def add_nested_form(nested)
      attributes << "#{nested}_attributes"
      nested_forms << nested
    end

    # Define the accessors for a singular nested form.
    def define_nested_form_one(name, options={})
      define_reader(name)
      from_model_attribute = options[:from_model_attribute]
      class_eval <<-one
        def #{name}_attributes
          self.#{name} ? @#{name}.attributes : nil
        end

        def #{name}_attributes=(attrs)
          form_klass = "#{name}".classify.constantize
          @#{name} = form_klass.new.assign(attrs)
        end

        def #{name}=(model)
          return unless #{from_model_attribute.inspect}
          nested_model = model.send(#{from_model_attribute.inspect})
          self.#{name}_attributes = nested_model.attributes
        end
      one
    end

    # Define the accessors for a plural nested form.
    def define_nested_form_many(name, options={})
      define_reader(name, [])
      from_model_attribute = options[:from_model_attribute]
      class_eval <<-many
        def #{name}_attributes
          self.#{name}.map { |form| form.attributes }
        end

        def #{name}_attributes=(attrs_array)
          form_klass = "#{name}".classify.constantize
          @#{name} = attrs_array.map do |attrs|
            form_klass.new.assign(attrs)
          end
        end

        def #{name}=(model)
          return unless #{from_model_attribute.inspect}
          nested_models = model.send(#{from_model_attribute.inspect})
          self.#{name}_attributes = nested_models.map { |m| m.attributes }
        end
      many
    end
  end

  # A Formality form object is valid if its attributes
  # validate and all of its children are valid.
  def valid?(context=nil)
    nested_forms_valid?(context) && super(context)
  end

  # If there are nested forms, call :valid? on them.
  def nested_forms_valid?(context)
    self.class.nested_forms.all? do |name|
      nested = Array(send(name))
      nested.all? { |form| form.valid?(context) }
    end
  end
end
nested_forms_valid?(context) click to toggle source

If there are nested forms, call :valid? on them.

# File lib/formality.rb, line 278
def nested_forms_valid?(context)
  self.class.nested_forms.all? do |name|
    nested = Array(send(name))
    nested.all? { |form| form.valid?(context) }
  end
end
persisted?() click to toggle source

:form_for calls :persisted? on the object it receives to determine whether to :post or :put.

We assume we’re persisted (i.e. editing an object) if we have an id.

# File lib/formality.rb, line 50
def persisted?
  id.present?
end
to_key() click to toggle source

More ActiveModel compliance shenanigans.

# File lib/formality.rb, line 33
def to_key; end
to_param() click to toggle source
# File lib/formality.rb, line 34
def to_param; end
to_partial_path() click to toggle source
# File lib/formality.rb, line 35
def to_partial_path; "" end
valid() { || ... } click to toggle source

Yields to its block if the form is valid.

# File lib/formality.rb, line 179
  def valid;   yield if valid?   end

  # Same as :valid, but in reverse: only yields to
  # the block if the form is invalid.
  def invalid; yield if invalid? end

  #
  # Nesting
  # =======
  #
  # Allows forms to have forms nested within them that
  # work nicely with Rails' :fields_for method.
  #
  # Validations are called on nested forms, so that if
  # any nested form is invalid, so is the parent.
  #

  module ClassMethods
    # Singular Nesting.
    def nest_one(child, options={})
      add_nested_form(child)
      define_nested_form_one(child, options)
    end

    # Plural nesting.
    #
    # Works just like :nest_one, except it works for
    # an Array of nested forms.
    def nest_many(children, options={})
      add_nested_form(children)
      define_nested_form_many(children, options)
    end

    # Keep track of what forms we've nested.
    def nested_forms
      @__nested_forms ||= Set.new
    end

    private

    def add_nested_form(nested)
      attributes << "#{nested}_attributes"
      nested_forms << nested
    end

    # Define the accessors for a singular nested form.
    def define_nested_form_one(name, options={})
      define_reader(name)
      from_model_attribute = options[:from_model_attribute]
      class_eval <<-one
        def #{name}_attributes
          self.#{name} ? @#{name}.attributes : nil
        end

        def #{name}_attributes=(attrs)
          form_klass = "#{name}".classify.constantize
          @#{name} = form_klass.new.assign(attrs)
        end

        def #{name}=(model)
          return unless #{from_model_attribute.inspect}
          nested_model = model.send(#{from_model_attribute.inspect})
          self.#{name}_attributes = nested_model.attributes
        end
      one
    end

    # Define the accessors for a plural nested form.
    def define_nested_form_many(name, options={})
      define_reader(name, [])
      from_model_attribute = options[:from_model_attribute]
      class_eval <<-many
        def #{name}_attributes
          self.#{name}.map { |form| form.attributes }
        end

        def #{name}_attributes=(attrs_array)
          form_klass = "#{name}".classify.constantize
          @#{name} = attrs_array.map do |attrs|
            form_klass.new.assign(attrs)
          end
        end

        def #{name}=(model)
          return unless #{from_model_attribute.inspect}
          nested_models = model.send(#{from_model_attribute.inspect})
          self.#{name}_attributes = nested_models.map { |m| m.attributes }
        end
      many
    end
  end

  # A Formality form object is valid if its attributes
  # validate and all of its children are valid.
  def valid?(context=nil)
    nested_forms_valid?(context) && super(context)
  end

  # If there are nested forms, call :valid? on them.
  def nested_forms_valid?(context)
    self.class.nested_forms.all? do |name|
      nested = Array(send(name))
      nested.all? { |form| form.valid?(context) }
    end
  end
valid?(context=nil) click to toggle source

A Formality form object is valid if its attributes validate and all of its children are valid.

Calls superclass method
# File lib/formality.rb, line 273
def valid?(context=nil)
  nested_forms_valid?(context) && super(context)
end