Module: CmAdmin::Models::DslMethod

Extended by:
ActiveSupport::Concern
Defined in:
lib/cm_admin/models/dsl_method.rb

Instance Method Summary collapse

Instance Method Details

#alert_box(header: nil, body: nil, type: nil, partial: nil, display_if: nil, html_attrs: {}) ⇒ Object

Note:

Alerts cannot be placed inside nested sections. If added within a nested section, the alert will appear on the wrapped cm_show_section.

Note:

Only the specified types (info, success, danger, warning) are supported. Any other type will default to a standard div.

Adds a new alert to the current section.

Examples:

Basic info alert

alert_box(header: "Information", body: "This is an informational message.", type: :info)

Basic info alert with custom body

alert_box(header: "Information", body: "This is an informational message. <br>This is a break text", type: :info)

Alert with custom partial

alert_box(partial: "/users/sessions/alert", display_if: ->(arg) { arg.present? })

Alert with conditional display and custom HTML attributes

alert_box(
  header: "Warning",
  body: "Please review your submission.",
  type: :warning,
  display_if: ->(user) { user.submissions.any?(&:incomplete?) },
  html_attrs: { id: "submission-warning", data: { turbo_frame: "warnings" } }
)

See Also:



380
381
382
# File 'lib/cm_admin/models/dsl_method.rb', line 380

def alert_box(header: nil, body: nil, type: nil, partial: nil, display_if: nil, html_attrs: {})
  @section_fields << CmAdmin::Models::Alert.new(header, body, type, partial:, display_if:, html_attrs:)
end

#all_db_columns(options = {}) ⇒ Object

Get all columns for a model for index layout.

Examples:

Getting all columns

all_db_columns(exclude: ['id'])


229
230
231
232
233
234
235
236
237
238
# File 'lib/cm_admin/models/dsl_method.rb', line 229

def all_db_columns(options = {})
  field_names = instance_variable_get(:@ar_model)&.columns&.map { |x| x.name.to_sym }
  if options.include?(:exclude) && field_names
    excluded_fields = ([] << options[:exclude]).flatten.map(&:to_sym)
    field_names -= excluded_fields
  end
  field_names.each do |field_name|
    column field_name
  end
end

#bulk_action(name: nil, display_name: nil, display_if: ->(_arg) { true }, redirection_url: nil, icon_name: nil, verb: nil, display_type: nil, modal_configuration: {}, route_type: nil, partial: nil, execution_mode: :individual, &block) ⇒ Object

Create a new bulk action for model

Examples:

Creating a bulk action

bulk_action name: 'approve', display_name: 'Approve', display_if: lambda { |arg| arg.draft? }, redirection_url: '/posts', icon_name: 'fa-regular fa-circle-check', verb: :patch, display_type: :modal, modal_configuration: { title: 'Approve Post', description: 'Are you sure you want approve this post', confirmation_text: 'Approve' }, execution_mode: :individual do
  posts = ::Post.where(id: params[:ids])
  posts.each(&:approved!)
  posts
end


298
299
300
301
302
303
304
305
306
# File 'lib/cm_admin/models/dsl_method.rb', line 298

def bulk_action(name: nil, display_name: nil, display_if: ->(_arg) { true }, redirection_url: nil, icon_name: nil, verb: nil, display_type: nil, modal_configuration: {}, route_type: nil, partial: nil, execution_mode: :individual, &block)
  bulk_action = CmAdmin::Models::BulkAction.new(
    name:, display_name:, display_if:, modal_configuration:,
    redirection_url:, icon_name:, action_type: :bulk_action,
    execution_mode:,
    verb:, display_type:, route_type:, partial:, &block
  )
  @available_actions << bulk_action
end

#cm_edit(page_title: nil, page_description: nil, partial: nil, redirect_to: nil) ⇒ Object

Create a form for edit action

Examples:

Editing page with a redirect

cm_edit(page_title: "Edit Post", page_description: 'Enter all details to edit Post', redirect_to: ->(current_object) { "/pages/#{current_object.id}" }) do
  cm_section 'Details' do
    form_field :title, input_type: :string
    form_field :body, input_type: :rich_text
  end
end


63
64
65
66
67
# File 'lib/cm_admin/models/dsl_method.rb', line 63

def cm_edit(page_title: nil, page_description: nil, partial: nil, redirect_to: nil)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
  @current_action.set_values(page_title, page_description, partial, redirect_to)
  yield
end

#cm_index(page_title: nil, page_description: nil, partial: nil, view_type: :table) ⇒ Object

Create a table for index page with pagination.

Examples:

Index page

cm_index do
  page_title 'Post'
  column :title
  column :created_at, field_type: :date, format: '%d %b, %Y'
  column :updated_at, field_type: :date, format: '%d %b, %Y', header: 'Last Updated At'
end


20
21
22
23
24
# File 'lib/cm_admin/models/dsl_method.rb', line 20

def cm_index(page_title: nil, page_description: nil, partial: nil, view_type: :table)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
  @current_action.set_values(page_title, page_description, partial, view_type)
  yield
end

#cm_new(page_title: nil, page_description: nil, partial: nil, redirect_to: nil) ⇒ Object

Create a form for new action

Examples:

Creating a new page with a redirect

cm_new(page_title: "Add Post", page_description: 'Enter all details to add Post', redirect_to: ->(current_object) { "/pages/#{current_object.id}" }) do
  cm_section 'Details' do
    form_field :title, input_type: :string
    form_field :body, input_type: :rich_text
  end
end


83
84
85
86
87
# File 'lib/cm_admin/models/dsl_method.rb', line 83

def cm_new(page_title: nil, page_description: nil, partial: nil, redirect_to: nil)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
  @current_action.set_values(page_title, page_description, partial, redirect_to)
  yield
end

#cm_section(section_name, display_if: nil, col_size: nil, html_attrs: nil, partial: nil, &block) ⇒ Object

Examples:

Creating a section

cm_section('Basic Information', display_if: ->(current_object) { current_object.name == 'John' }, col_size: 6, html_attrs: { class: 'section-class' }) do
  field :title, input_type: :string
end


179
180
181
182
# File 'lib/cm_admin/models/dsl_method.rb', line 179

def cm_section(section_name, display_if: nil, col_size: nil, html_attrs: nil, partial: nil, &block)
  @available_fields[@current_action.name.to_sym] ||= []
  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Section.new(section_name, @current_action, @model, display_if, html_attrs, col_size, partial, &block)
end

#cm_show(page_title: nil, page_description: nil, partial: nil) ⇒ Object

Create a view for show page

Examples:

Showing page

cm_show page_title: :title do
  tab :profile, '' do
    cm_section 'Post Details' do
      field :title
      field :body, field_type: :rich_text
      field :is_featured
      field :status, field_type: :tag, tag_class: STATUS_TAG_COLOR
    end
  end
end


43
44
45
46
47
# File 'lib/cm_admin/models/dsl_method.rb', line 43

def cm_show(page_title: nil, page_description: nil, partial: nil)
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
  @current_action.set_values(page_title, page_description, partial)
  yield
end

#cm_show_section(section_name, display_if: nil, html_attrs: nil, partial: nil, &block) ⇒ Object

Deprecated.

Use #cm_section instead of this method



185
186
187
# File 'lib/cm_admin/models/dsl_method.rb', line 185

def cm_show_section(section_name, display_if: nil, html_attrs: nil, partial: nil, &block)
  cm_section(section_name, display_if:, html_attrs:, partial:, &block)
end

#column(field_name, options = {}) ⇒ Object

Create a new column on index layout.

Examples:

Creating a column

column('name', field_type: :string)


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/cm_admin/models/dsl_method.rb', line 203

def column(field_name, options = {})
  @available_fields[@current_action.name.to_sym] ||= []
  raise 'Only one column can be locked in a table.' if @available_fields[@current_action.name.to_sym].select { |x| x.lockable }.size > 0 && options[:lockable]

  duplicate_columns = @available_fields[@current_action.name.to_sym].filter { |x| x.field_name.to_sym == field_name }
  terminate = false

  if duplicate_columns.size.positive?
    duplicate_columns.each do |column|
      if options[:field_type].to_s != 'association'
        terminate = true
      elsif options[:field_type].to_s == 'association' && column.association_name.to_s == options[:association_name].to_s
        terminate = true
      end
    end
  end

  return if terminate

  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Column.new(field_name, options)
end

#custom_action(name: nil, page_title: nil, page_description: nil, display_name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, modal_configuration: {}, url_params: {}, display_if: ->(_arg) { true }, route_type: nil, icon_name: 'fa fa-th-large', &block) ⇒ Object

Create a new custom action for model

Examples:

Creating a custom action with modal

custom_action name: 'approve', route_type: 'member', verb: 'patch', icon_name: 'fa-regular fa-circle-check', path: ':id/approve', display_type: :modal, display_if: lambda(&:draft?), modal_configuration: { title: 'Approve Post', description: 'Are you sure you want approve this post', confirmation_text: 'Approve' } do
  post = ::Post.find(params[:id])
  post.approved!
  post
end

Creating a custom action with button

custom_action name: 'approve', route_type: 'member', verb: 'patch', icon_name: 'fa-regular fa-circle-check', path: ':id/approve', display_type: :button, display_if: lambda(&:draft?) do
  post = ::Post.find(params[:id])
  post.approved!
  post
end


268
269
270
271
272
273
274
275
276
277
278
# File 'lib/cm_admin/models/dsl_method.rb', line 268

def custom_action(name: nil, page_title: nil, page_description: nil, display_name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, modal_configuration: {}, url_params: {}, display_if: ->(_arg) { true }, route_type: nil, icon_name: 'fa fa-th-large', &block)
  action = CmAdmin::Models::CustomAction.new(
    page_title:, page_description:,
    name:, display_name:, verb:, layout:,
    layout_type:, partial:, path:,
    parent: current_action.name, display_type:, display_if:,
    action_type: :custom, route_type:, icon_name:, modal_configuration:,
    model_name: self.name, url_params:, &block
  )
  @available_actions << action
end

#eager_load_associations(associations = []) ⇒ Object

Configure Eager load associations for action This will help us avoid N+1 queries

Examples:

Eager load associations

eager_load_assocations [:association_name]
eager_load_assocations [:constant]


415
416
417
# File 'lib/cm_admin/models/dsl_method.rb', line 415

def eager_load_associations(associations=[])
  @current_action.eager_load_associations = associations if @current_action
end

#filter(db_column_name, filter_type, options = {}) ⇒ Object

Create a new filter for model

Examples:

Creating a filter

filter('name', :search)
filter('created_at', :date)
filter('status', :single_select, collection: ['draft', 'published'])
filter('status', :multi_select,  helper_method: 'status_collection')
filter('age', :range)


322
323
324
# File 'lib/cm_admin/models/dsl_method.rb', line 322

def filter(db_column_name, filter_type, options = {})
  @filters << CmAdmin::Models::Filter.new(db_column_name:, filter_type:, options:)
end

#kanban_view(column_name, exclude: [], only: []) ⇒ Object

Set kanban view for current action



109
110
111
112
113
114
115
# File 'lib/cm_admin/models/dsl_method.rb', line 109

def kanban_view(column_name, exclude: [], only: [])
  return unless @current_action

  @current_action.kanban_attr[:column_name] = column_name
  @current_action.kanban_attr[:exclude] = exclude
  @current_action.kanban_attr[:only] = only
end

#page_description(description) ⇒ Object

Set page description for current action



99
100
101
102
103
# File 'lib/cm_admin/models/dsl_method.rb', line 99

def page_description(description)
  return unless @current_action

  @current_action.page_description = description
end

#page_title(title) ⇒ Object

Set page title for current action



91
92
93
94
95
# File 'lib/cm_admin/models/dsl_method.rb', line 91

def page_title(title)
  return unless @current_action

  @current_action.page_title = title
end

#row(display_if: nil, html_attrs: nil, &block) ⇒ Object

Create a new row on page or form.

Examples:

Creating a row

row(display_if: ->(current_object) { current_object.name == 'John' }, html_attrs: { class: 'row-class' }) do
  cm_section 'Details' do
    form_field :title, input_type: :string
  end
end


164
165
166
167
# File 'lib/cm_admin/models/dsl_method.rb', line 164

def row(display_if: nil, html_attrs: nil, &block)
  @available_fields[@current_action.name.to_sym] ||= []
  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Row.new(@current_action, @model, display_if, html_attrs, &block)
end

#scope_list(scopes = []) ⇒ Object

Set scopes for current action



119
120
121
122
123
# File 'lib/cm_admin/models/dsl_method.rb', line 119

def scope_list(scopes = [])
  return unless @current_action

  @current_action.scopes = scopes
end

#sort_column(column = :created_at) ⇒ Object

@deprecated: use #sortable_columns instead of this method Set sort column for filters

Examples:

Setting sort column

sort_column(:created_at)


342
343
344
# File 'lib/cm_admin/models/dsl_method.rb', line 342

def sort_column(column = :created_at)
  @current_action.sort_column = column.to_sym if @current_action
end

#sort_direction(direction = :desc) ⇒ Object

@deprecated: use #sortable_columns instead of this method Set sort direction for filters

Examples:

Setting sort direction

sort_direction(:asc)

Raises:

  • (ArgumentError)


331
332
333
334
335
# File 'lib/cm_admin/models/dsl_method.rb', line 331

def sort_direction(direction = :desc)
  raise ArgumentError, "Select a valid sort direction like #{CmAdmin::Models::Action::VALID_SORT_DIRECTION.join(' or ')} instead of #{direction}" unless CmAdmin::Models::Action::VALID_SORT_DIRECTION.include?(direction.to_sym.downcase)

  @current_action.sort_direction = direction.to_sym if @current_action
end

#sortable_columns(columns) ⇒ Object

Note:

default sort direction will be ascending

Configure sortable columns for model

Examples:

Sortable Columns

sortable_columns([{column: 'id', display_name: 'ID'},
                  {column: 'updated_at', display_name: 'Last Updated At'}])

Sortable Columns with default column and direction

sortable_columns([{column: 'id', display_name: 'ID', default: true, default_direction: 'desc'},
                  {column: 'updated_at', display_name: 'Last Updated At'}])

Raises:

  • (ArgumentError)


394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/cm_admin/models/dsl_method.rb', line 394

def sortable_columns(columns)
  @sort_columns = columns
  default_column = columns.filter do |column|
    column.key?(:default) || column.key?(:default_direction)
  end
  raise ArgumentError, 'only one column can be default' if default_column.size > 1
  return if default_column.blank?

  default_column = default_column.first

  @default_sort_column = default_column[:column]
  @default_sort_direction = default_column[:default_direction] if default_column[:default_direction].present?
end

#tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, display_if: nil, view_type: nil, &block) ⇒ Object

Create a new tab on show page.

Examples:

Creating a tab

tab :comments, 'comment', associated_model: 'comments', layout_type: 'cm_association_index' do
  column :message
end


140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/cm_admin/models/dsl_method.rb', line 140

def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, display_if: nil, view_type: nil, &block)
  if custom_action.to_s == ''
    @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
    @available_tabs << CmAdmin::Models::Tab.new(tab_name, '', display_if, &block)
  else
    action = CmAdmin::Models::Action.new(name: custom_action.to_s, verb: :get, path: ':id/' + custom_action,
                                         layout_type:, layout:, partial:, child_records: associated_model,
                                         action_type: :custom, display_type: :page, model_name: name, view_type:)
    @available_actions << action
    @current_action = action
    @available_tabs << CmAdmin::Models::Tab.new(tab_name, custom_action, display_if, &block)
  end
  yield if block
end