class Conjoin::FormBuilder::Fields

Public Instance Methods

association(field_name, options = {}) click to toggle source
# File lib/conjoin/form_builder.rb, line 87
def association field_name, options = {}
  options[:is_association] = true
  input field_name, options
end
errors_for(attr) click to toggle source
# File lib/conjoin/form_builder.rb, line 219
def errors_for attr
  mab do
    span class: 'has-error has-feedback form-control-feedback' do
      text! record.errors.messages[attr.to_sym].try :join, ', '
    end
  end
end
fields_for(field_name, options = {}) click to toggle source
# File lib/conjoin/form_builder.rb, line 159
def fields_for field_name, options = {}, &block
  names = [].concat models

  associated_record = record.send field_name

  if scope = options.delete(:scope)
    associated_record = associated_record.send(scope, *options.delete(:scope_args))
  end

  if select = options.delete(:select)
    associated_record = Hash[associated_record.each_with_index.map {|a, i| [i, a]}]

    select.each do |key, select_array|
      select_array = [select_array] unless select_array.is_a? Array

      associated_record.select! do |k, v|
        select_array.include? :"#{v[key]}"
      end
    end
  end

  if name = options.delete(:name)
    field_name = name
  end

  names << "#{field_name}_attributes"

  if !associated_record.kind_of? ActiveRecord::Associations::CollectionProxy \
  and !associated_record.kind_of? ActiveRecord::AssociationRelation \
  and !associated_record.kind_of? Array \
  and !associated_record.kind_of? Hash
    fields = Fields.new app, names, associated_record, block, 0
    fields.render
  else
    html = ''
    if associated_record.kind_of? Array
      associated_record.each_with_index do |current_record, i|
        nested_names = [].concat names
        nested_names << i

        fields = Fields.new app, nested_names, current_record, block, i
        html += fields.render
      end
    else
      associated_record.each_with_index do |current_record, i|
        nested_names = [].concat names
        nested_names << i

        fields = Fields.new app, nested_names, current_record, block, i
        html += fields.render
      end
    end

    html
  end

# rescue
#   raise "No associated record #{field_name} for #{record.class}"
end
input(field_name, options = {}) click to toggle source
# File lib/conjoin/form_builder.rb, line 97
def input field_name, options = {}
  names = [].concat models
  if options.delete(:is_association)
    names << "#{field_name.to_s.singularize}_ids"
    names << ''
  else
    names << field_name
  end

  # create field names that map to the correct models
  nested_name = nested_names_for names

  begin
    record_class = record.class.model_name.name.constantize
  rescue Exception
    m = models.join('.').gsub(/_attributes/, '')
    raise "No value for #{field_name} as #{m} is nil."
  end

  if as = options.delete(:as)
    record_type = as.to_s.classify
  elsif record_class.mini_record_columns \
    and mini_column = record_class.mini_record_columns[field_name] \
    and input_as = mini_column[:input_as]
      record_type = input_as.to_s.classify
  elsif record_class.respond_to?(field_name) && record_class.send(field_name).is_a?(Enumerize::Attribute)
    record_type = 'Select'
  else
    record_type = record_class.columns_hash[field_name.to_s].type.to_s.classify
  end

  if mini_column and opts = mini_column[:input_options]
    options = opts.merge options
  end

  input_class = "Conjoin::FormBuilder::#{record_type}Input".constantize

  data = OpenStruct.new({
    name: nested_name,
    record: record,
    value: record.send(field_name),
    options: options,
    errors: record.errors.messages[field_name],
    names: names,
    field_name: field_name,
    record_class: record_class
  })

  new_input = input_class.new data, app, record

  if record_type != 'Hidden' \
  and not options.key(:wrapper) and options[:wrapper] != false
    if !options.key(:label) and options[:label] != false
      wrapper field_name.to_s, nested_name, new_input, options
    else
      new_input.render
    end
  else
    new_input.render
  end
end
input_field(field_name, options = {}) click to toggle source
# File lib/conjoin/form_builder.rb, line 92
def input_field field_name, options = {}
  options[:label] = false
  input field_name, options
end
nested_names_for(names) click to toggle source
# File lib/conjoin/form_builder.rb, line 80
def nested_names_for names
  # create field names that map to the correct models
  names.each_with_index.map do |field, i|
    i != 0 ? "[#{field}]" : field
  end.join
end
render() click to toggle source
# File lib/conjoin/form_builder.rb, line 59
def render
  html = block.call(self, index)
  names = [].concat models
  names << 'id'

  mab do
    if record.id
      input type: 'hidden', name: nested_names_for(names), value: record.id
    end
    text! html
  end
end
submit(options = {}) click to toggle source
# File lib/conjoin/form_builder.rb, line 72
def submit options = {}
  mab do
    input type: 'submit',
      value: options[:value] || 'Submit',
      class: 'btn'
  end
end

Private Instance Methods

errors?(obj, attr) click to toggle source
# File lib/conjoin/form_builder.rb, line 259
def errors? obj, attr
  obj.errors.messages[attr.to_sym]
end
id_for(field_name) click to toggle source
# File lib/conjoin/form_builder.rb, line 229
def id_for field_name
  field_name.gsub(/[^a-z0-9]/, '_').gsub(/__/, '_').gsub(/_$/, '')
end
required?(obj, attr, options) click to toggle source
# File lib/conjoin/form_builder.rb, line 233
def required?(obj, attr, options)
  if options.key?(:required)
    options[:required]
  else
    target = (obj.class == Class) ? obj : obj.class
    presence = target.validators_on(attr).select { |t| t.class.to_s == 'ActiveRecord::Validations::PresenceValidator' }
    if presence.any?
      is_required = true

      presence.each do |p|
        if p.options[:if]
          is_required &= p.options[:if].call(record)
        end

        if p.options[:unless]
          is_required &= !p.options[:if].call(record)
        end
      end
    else
      is_required = false
    end

    is_required
  end
end
wrapper(field_name, nested_name, input, options) click to toggle source
# File lib/conjoin/form_builder.rb, line 263
def wrapper field_name, nested_name, input, options
  if w = options[:wrapper] and w.is_a? String
    label_width, input_width = w.split ','
  else
    label_width, input_width = [3, 9]
  end

  mab do
    div class: "form-group #{errors?(record, field_name) ? 'has-error has-feedback' : ''}" do
      label for: id_for(nested_name), class: "control-label col-sm-#{label_width}" do
        if required? record, field_name, options
          abbr title: 'required' do
            text '*'
          end
        end

        i18n_s = nested_name.gsub(/.+\[([a-z\_]+)\](?:.*|)\[([a-z\_]+)\]$/, 'model.\1.\2').gsub(/_attributes/, '')

        i18n_name = options[:label] || R18n.t(i18n_s.gsub(/^model/, 'form.label')) | R18n.t.form.label[field_name] | R18n.t(i18n_s) |  field_name.titleize

        text! i18n_name
      end
      div class: "col-sm-#{input_width}" do
        text! input.render
        if errors = errors?(record, field_name)
          span class: 'help-block has-error' do
            text errors.join ', '
          end
          span class: 'fa fa-times form-control-feedback'
        end
      end
    end
  end
end