Class: Proscenium::UI::Form

Inherits:
Component
  • Object
show all
Includes:
FieldMethods, Translation
Defined in:
lib/proscenium/ui/form.rb,
lib/proscenium/ui/form/field_methods.rb

Overview

Helpers to aid in building forms and associated inputs with built-in styling, and inspired by Rails form helpers and SimpleForm.

Start by creating the form with ‘Proscenium::UI::Form`, which expects a model instance, and a block in which you define one or more fields. It automatically includes a hidden authenticity token field for you.

Example:

render Proscenium::UI::Form.new(User.new) do |f|
  f.text_field :name
  f.radio_group :role, %i[admin manager]
  f.submit 'Save'
end

The following fields (inputs) are available:

- `url_field` - <input> with 'url' type.
- `text_field` - <input> with 'text' type.
- `textarea_field` - <textarea>.
- `rich_textarea_field` - A rich <textarea> using ActionText and Trix.
- `email_field` - <input> with 'email' type.
- `number_field` - <input> with 'number' type.
- `color_field` - <input> with 'color' type.
- `hidden_field` - <input> with 'hidden' type.
- `search_field` - <input> with 'search' type.
- `password_field` - <input> with 'password' type.
- `tel_field` - <input> with 'tel' type.
- `range_field` - <input> with 'range' type.
- `time_field` - <input> with 'time' type.
- `date_field` - <input> with 'date' type.
- `week_field` - <input> with 'week' type.
- `month_field` - <input> with 'month' type.
- `datetime_local_field` - <input> with 'datetime-local' type.
- `checkbox_field` - <input> with 'checkbox' type.
- `radio_field` - <input> with 'radio' type.
- `radio_group` - group of <input>'s with 'radio' type.
- `select_field` - <select> input.

Defined Under Namespace

Modules: FieldMethods, Fields, Translation

Constant Summary collapse

STANDARD_METHOD_VERBS =
%w[get post].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Translation

#translate, #translate_label

Methods included from FieldMethods

#checkbox_field, #combobox_field, #datetime_local_field, #hidden_field, #radio_field, #radio_group, #radio_input, #rich_textarea_field, #select_country_field, #select_field, #tel_field, #textarea_field

Class Method Details

.input_field(method_name, type:) ⇒ Object



49
50
51
52
53
54
# File 'lib/proscenium/ui/form.rb', line 49

def self.input_field(method_name, type:)
  define_method method_name do |*args, **attributes|
    merge_bang_attributes! args, attributes
    render Fields::Input.new(args, @model, self, type:, **attributes)
  end
end

.source_pathObject



74
# File 'lib/proscenium/ui/form.rb', line 74

def self.source_path = super / '../form/index.rb'

Instance Method Details

#actionObject



162
163
164
# File 'lib/proscenium/ui/form.rb', line 162

def action
  view_context.url_for(@action || @model)
end

#authenticity_token_fieldObject



151
152
153
154
155
156
157
158
159
160
# File 'lib/proscenium/ui/form.rb', line 151

def authenticity_token_field
  return if method == 'get'

  input(
    name: 'authenticity_token',
    type: 'hidden',
    value: view_context.form_authenticity_token(form_options: { action:,
                                                                method: @method })
  )
end

#error(message: nil, attribute: nil, &content) ⇒ Object

Returns a <div> with the given ‘message` as its content. If `message` is not given, and `attribute` is, then first error message for the given model `attribute`.

Parameters:

  • message (String) (defaults to: nil)

    error message to display.

  • attribute (Symbol) (defaults to: nil)

    name of the model attribute.



106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/proscenium/ui/form.rb', line 106

def error(message: nil, attribute: nil, &content)
  if message.nil? && attribute.nil? && !content
    raise ArgumentError, 'One of `message:`, `attribute:` or a block is required'
  end

  if content
    div class: :@error, &content
  else
    div class: :@error do
      message || @model.errors[attribute]&.first
    end
  end
end

#error_for_baseObject



129
130
131
132
133
134
135
136
# File 'lib/proscenium/ui/form.rb', line 129

def error_for_base
  return if !@model.errors.key?(:base)

  callout :danger do |x|
    x.title { 'Unable to save...' }
    div { @model.errors.full_messages_for(:base).first }
  end
end

#field_idObject



147
148
149
# File 'lib/proscenium/ui/form.rb', line 147

def field_id(*)
  view_context.field_id(ActiveModel::Naming.param_key(@model.class), *)
end

#field_name(*names, multiple: false) ⇒ Object



138
139
140
141
142
143
144
145
# File 'lib/proscenium/ui/form.rb', line 138

def field_name(*names, multiple: false)
  # Delete the `?` suffix if present.
  lname = names.pop.to_s
  names.append lname.delete_suffix('?').to_sym

  view_context.field_name(ActiveModel::Naming.param_key(@model.class), *names,
                          multiple:)
end

#methodObject



172
173
174
# File 'lib/proscenium/ui/form.rb', line 172

def method
  STANDARD_METHOD_VERBS.include?(@method) ? @method : 'post'
end

#method_fieldObject



166
167
168
169
170
# File 'lib/proscenium/ui/form.rb', line 166

def method_field
  return if STANDARD_METHOD_VERBS.include?(@method)

  input type: 'hidden', name: '_method', value: @method, autocomplete: 'off'
end

#submit(value = 'Save') ⇒ Object

Returns a button with type of ‘submit’, using the ‘value` given.

Parameters:

  • value (String) (defaults to: 'Save')

    Value of the ‘value` attribute.



97
98
99
# File 'lib/proscenium/ui/form.rb', line 97

def submit(value = 'Save', **)
  input(name: 'commit', type: :submit, value:, **)
end

#use_field(field_class, *args, **attributes) ⇒ Object

Use the given ‘field_class` to render a custom field. This allows you to create a custom form field on an as-needed basis. The `field_class` must be a subclass of `Proscenium::UI::Form::Fields::Base`.

Example:

render Proscenium::UI::Form.new @resource do |f|
  f.use_field Administrator::EmailField, :email, :required!
end

Parameters:

  • field_class (Class<Proscenium::UI::Form::Fields::Base>)
  • args (Array<Symbol>)

    name or nested names of model attribute

  • attributes (Hash)

    passed through to each input



89
90
91
92
# File 'lib/proscenium/ui/form.rb', line 89

def use_field(field_class, *args, **attributes)
  merge_bang_attributes! args, attributes
  render field_class.new(args, model, self, **attributes)
end

#view_templateObject



120
121
122
123
124
125
126
127
# File 'lib/proscenium/ui/form.rb', line 120

def view_template(&)
  form action:, method:, **@attributes do
    method_field
    authenticity_token_field
    error_for_base
    yield if block_given?
  end
end