Module: InlineForms

Defined in:
lib/inline_forms.rb,
lib/inline_forms/version.rb,
lib/generators/inline_forms_generator.rb,
lib/inline_forms/form_element_from_callee.rb,
bin/inline_forms

Overview

easy. Please install it as a gem or include it in your Gemfile.

Defined Under Namespace

Classes: Creator, Engine, InlineFormsGenerator, PlainTextColumnMissingError

Constant Summary collapse

DEFAULT_COLUMN_TYPES =

DEFAULT_COLUMN_TYPES holds the standard ActiveRecord::Migration column types. This list provides compatability with the standard types, but we add our own later in ‘Special Column Types’.

These types will override Special Column Types of the same name.\

Example: rails g inline_forms Example name:string price:integer will result in:

class InlineFormsCreateExamples < ActiveRecord::Migration
  def self.up
    create_table :examples do |t|
      t.string  :name
      t.integer :price
      t.timestamps
    end
  end
  def self.down
    drop_table :examples
  end
end
{
  :string     => :string,
  :text       => :text,
  :integer    => :integer,
  :float      => :float,
  :decimal    => :decimal,
  :datetime   => :datetime,
  :timestamp  => :timestamp,
  :time       => :time,
  :date       => :date,
  :binary     => :binary,
  :boolean    => :boolean,
  # :references => :belongs_to,
  # :belongs_to => :belongs_to,
}
DEFAULT_FORM_ELEMENTS =

DEFAULT_FORM_ELEMENTS holds a mapping from Default Column Types to Form Elements. Form Elements are defined in lib/app/helpers/form_elements and are pieces of code that display a form for a field.

Example:

rails g inline_forms Example name:string price:integer

will result in the following model:

class Example < ApplicationRecord
  def inline_forms_attribute_list
    {
      :name  => [ "name", :text_field ],
      :price => [ "price", :text_field ],
    }
  end
end

as you see, both :string and :integer are mapped to a :text_field

{
  :string     => :text_field,
  :text       => :plain_text,
  :integer    => :text_field,
  :float      => :text_field,
  :decimal    => :text_field,
  :datetime   => :datetime_select,
  :timestamp  => :datetime_select,
  :time       => :time_select,
  :date       => :date_select,
  :binary     => :text_field,
  :boolean    => :check_box,
}
SPECIAL_COLUMN_TYPES =

SPECIAL_COLUMN_TYPES maps the column types that we define here and in lib/app/helpers/form_elements to the standard ActiveRecord::Migration column types

Example: in lib/app/helpers/form_elements/dropdown.rb

InlineForms::SPECIAL_COLUMN_TYPES[:dropdown]=:belongs_to

this maps the :dropdown form element to the :belongs_to column type.

If you call the generator with country:dropdown, it will add

t.belongs_to :country

to the migration. (In fact AR will add t.integer :country_id). And it will add

:country => [ "country", :dropdown ],

to the inline_forms_attribute_list in the model.

{
  :associated => :no_migration
}
PLAIN_TEXT_FORM_ELEMENTS =
%i[
  plain_text
  plain_text_area
  text_area_without_ckeditor
].freeze
RELATIONS =

RELATIONS defines a mapping between AR::Migrations columns and the Model.

When a column has the type of :references or :belongs_to, then there will be a line in the migration reflecting that, but not in the model.

Why?

  • Let’s say we have a customer that has_many phone_numbers.

  • Let’s say that a phone_number belongs_to a customer.

  • Let’s say that every number has_one type_of_number (like ‘private’,‘gsm’ etc.)

  • Let’s say a type_of_number belongs_to a number.

Wait a minute… thats sounds right… but it ain’t!

In fact, a type_of_number has_many phone_numbers and a phone_number belongs_to a type_of_number!

In a form, it’s quite logical to use a dropdown for type_of_number. So, in the generator, use

type_of_number:dropdown

This creates the correct migration (t.integer :type_of_number_id) and the correct model. (It adds ‘belongs_to :type_of_number’ and adds a dropdown in the inline_forms_attribute_list)

But, you also want to have a client_id in the migration, and a ‘belongs_to :client’ in the model. In such cases, you need to use :belongs_to, like this:

rails g inline_forms Example phone_number:string type_of_number:dropdown client:belongs_to
{
  :belongs_to => :belongs_to,
  :references => :belongs_to,
}
SPECIAL_RELATIONS =

SPECIAL_RELATIONS maps AR relations to migrations. In most cases, these relations have no migration at all, but they do need a line in the model.

{
  :has_many                 => :no_migration,
  :has_many_destroy         => :no_migration,
  :has_one                  => :no_migration,
  :has_and_belongs_to_many  => :no_migration,
  :habtm                    => :no_migration,
}
VERSION =
"7.5.2"

Class Method Summary collapse

Class Method Details

.assert_plain_text_column!(object:, attribute:, form_element:) ⇒ Object



110
111
112
113
114
115
116
117
# File 'lib/inline_forms.rb', line 110

def self.assert_plain_text_column!(object:, attribute:, form_element:)
  return unless plain_text_form_element?(form_element)
  return if object.class.column_names.include?(attribute.to_s)

  raise PlainTextColumnMissingError,
    "#{object.class.name}##{attribute} uses #{form_element} but has no DB column `#{attribute}`. " \
    "Use :rich_text for ActionText-backed attributes, or add a text column for :plain_text."
end

.form_element_string_from_callee(from_callee) ⇒ Object

Maps __callee__ from a *_show helper to the params[:form_element] string (e.g. :text_field_show“text_field”).



5
6
7
8
9
# File 'lib/inline_forms/form_element_from_callee.rb', line 5

def self.form_element_string_from_callee(from_callee)
  s = from_callee.to_s
  s = s.sub(/\Ablock in /, "")
  s.delete_suffix("_show")
end

.plain_text_form_element?(form_element) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
107
108
# File 'lib/inline_forms.rb', line 104

def self.plain_text_form_element?(form_element)
  PLAIN_TEXT_FORM_ELEMENTS.include?(form_element.to_sym)
rescue NoMethodError
  false
end

.validate_plain_text_configuration_for!(klass) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/inline_forms.rb', line 119

def self.validate_plain_text_configuration_for!(klass)
  return unless klass.respond_to?(:table_exists?) &&
                klass.respond_to?(:column_names) &&
                klass.instance_methods.include?(:inline_forms_attribute_list)
  return unless klass.table_exists?

  attributes = klass.new.inline_forms_attribute_list
  attributes.each do |attribute, _label, form_element|
    next unless plain_text_form_element?(form_element)
    next if klass.column_names.include?(attribute.to_s)

    raise PlainTextColumnMissingError,
      "#{klass.name} inline_forms_attribute_list declares #{attribute}:#{form_element}, " \
      "but table `#{klass.table_name}` has no `#{attribute}` column. " \
      "Use :rich_text for ActionText-backed attributes."
  end
end