Class: AutoForme::Action

Inherits:
Object
  • Object
show all
Defined in:
lib/autoforme/action.rb

Overview

Represents an action on a model in response to a web request.

Constant Summary collapse

ALL_SUPPORTED_ACTIONS =

Array of strings for all action types currently supported

%w'new create show edit update delete destroy browse search mtm_edit mtm_update association_links autocomplete'.freeze
NON_IDEMPOTENT_TYPES =

Map of regular type symbols to normalized type symbols

NORMALIZED_ACTION_MAP = {:create=>:new, :update=>:edit, :destroy=>:delete, :mtm_update=>:mtm_edit}
TITLE_MAP =

Map of type symbols to HTML titles

{:new=>'New', :show=>'Show', :edit=>'Edit', :delete=>'Delete', :browse=>'Browse', :search=>'Search', :mtm_edit=>'Many To Many Edit'}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, request) ⇒ Action

Creates a new action for the model and request. This action is not usable unless supported? is called first and it returns true.



44
45
46
47
# File 'lib/autoforme/action.rb', line 44

def initialize(model, request)
  @model = model
  @request = request
end

Instance Attribute Details

#modelObject (readonly)

The AutoForme::Model instance related to the current action



9
10
11
# File 'lib/autoforme/action.rb', line 9

def model
  @model
end

#normalized_typeObject (readonly)

The normalized type symbol related to the current action, so that paired actions such as new and create both use :new.



13
14
15
# File 'lib/autoforme/action.rb', line 13

def normalized_type
  @normalized_type
end

#output_filenameObject (readonly)

The filename to use for file output



31
32
33
# File 'lib/autoforme/action.rb', line 31

def output_filename
  @output_filename
end

#output_typeObject (readonly)

The type of output, currently nil for normal output, and ‘csv’ for csv output



28
29
30
# File 'lib/autoforme/action.rb', line 28

def output_type
  @output_type
end

#params_associationObject (readonly)

An association symbol for the current related association.



16
17
18
# File 'lib/autoforme/action.rb', line 16

def params_association
  @params_association
end

#requestObject (readonly)

The AutoForme::Request instance related to the current action



19
20
21
# File 'lib/autoforme/action.rb', line 19

def request
  @request
end

#titleObject (readonly)

An string suitable for use as the HTML title on the displayed page



22
23
24
# File 'lib/autoforme/action.rb', line 22

def title
  @title
end

#typeObject (readonly)

The type symbols related to the current action (e.g. :new, :create).



25
26
27
# File 'lib/autoforme/action.rb', line 25

def type
  @type
end

Instance Method Details

If the framework contains the associated model class and that supports browsing, return a link to the associated browse page, otherwise, just return the name.



611
612
613
614
615
616
617
618
# File 'lib/autoforme/action.rb', line 611

def association_class_link(mc, assoc)
  assoc_name = humanize(assoc)
  if mc && mc.supported_action?(:browse, request)
    "<a href=\"#{base_url_for("#{mc.link}/browse")}\">#{assoc_name}</a>"
  else
    assoc_name
  end
end

For the given associated object, if the framework contains the associated model class, and that supports the type of action we are doing, return a link to the associated action page.



623
624
625
626
627
628
629
630
631
632
633
# File 'lib/autoforme/action.rb', line 623

def association_link(mc, assoc_obj)
  if mc
    t = mc.object_display_name(:association, request, assoc_obj)
    if mc.supported_action?(type, request)
      t = "<a href=\"#{base_url_for("#{mc.link}/#{type}/#{mc.primary_key_value(assoc_obj)}")}\">#{t}</a>"
    end
    t
  else
    model.default_object_display_name(assoc_obj)
  end
end

HTML fragment for the list of association links, allowing quick access to associated models and objects.



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
# File 'lib/autoforme/action.rb', line 557

def association_link_list(obj)
  assocs = model.association_links_for(type, request) 
  return if assocs.empty?
  read_only = type == :show
  t = String.new
  t << '<h3 class="associated_records_header">Associated Records</h3>'
  t << "<ul class='association_links'>\n"
  assocs.each do |assoc|
    mc = model.associated_model_class(assoc)
    t << "<li>"
    t << association_class_link(mc, assoc)
    t << "\n "

    case model.association_type(assoc)
    when :one
      if assoc_obj = obj.send(assoc)
        t << " - "
        t << association_link(mc, assoc_obj)
      end
      assoc_objs = []
    when :edit
      if !read_only && model.supported_mtm_edit?(assoc.to_s, request)
        t << "(<a href=\"#{url_for("mtm_edit/#{model.primary_key_value(obj)}?association=#{assoc}")}\">associate</a>)"
      end
      assoc_objs = obj.send(assoc)
    when :new
      if !read_only && mc && mc.supported_action?(:new, request)
        params = model.associated_new_column_values(obj, assoc).map do |col, value|
          "#{mc.link}%5b#{col}%5d=#{value}"
        end
        t << "(<a href=\"#{base_url_for("#{mc.link}/new?#{params.join('&amp;')}")}\">create</a>)"
      end
      assoc_objs = obj.send(assoc)
    else
      assoc_objs = []
    end

    unless assoc_objs.empty?
      t << "<ul>\n"
      assoc_objs.each do |assoc_obj1|
        t << "<li>"
        t << association_link(mc, assoc_obj1)
        t << "</li>"
      end
      t << "</ul>"
    end

    t << "</li>"
  end
  t << "</ul>"
end

HTML fragment containing the association links for the given object, or a link to lazily load them if configured. Also contains the inline mtm_edit forms when editing.



546
547
548
549
550
551
552
553
554
# File 'lib/autoforme/action.rb', line 546

def association_links(obj)
  if model.lazy_load_association_links?(type, request) && normalized_type != :association_links && request.params['associations'] != 'show'
    "<div id='lazy_load_association_links' data-object='#{model.primary_key_value(obj)}' data-type='#{type}'><a href=\"#{url_for("#{type}/#{model.primary_key_value(obj)}?associations=show")}\">Show Associations</a></div>"
  elsif type == :show
    association_link_list(obj).to_s
  else
    "#{inline_mtm_edit_forms(obj)}#{association_link_list(obj)}"
  end
end

#base_url_for(page) ⇒ Object

A path for the given page tied to the framework, but not the current model. Used for linking to other models in the same framework.



111
112
113
# File 'lib/autoforme/action.rb', line 111

def base_url_for(page)
  "#{request.path}#{model.framework.prefix}/#{page}"
end

#column_label_for(type, request, model, column) ⇒ Object

The label to use for the given column.



174
175
176
177
178
179
# File 'lib/autoforme/action.rb', line 174

def column_label_for(type, request, model, column)
  unless label = model.column_options_for(type, request, column)[:label]
    label = humanize(column)
  end
  label
end

#column_options_for(type, request, obj, column) ⇒ Object

The options to use for the given column, which will be passed to Forme::Form#input.



161
162
163
164
165
166
167
168
169
170
171
# File 'lib/autoforme/action.rb', line 161

def column_options_for(type, request, obj, column)
  opts = model.column_options_for(type, request, column)
  if opts[:class] == 'autoforme_autocomplete'
    if type == :show
      opts[:value] = model.column_value(type, request, obj, column)
    elsif key = obj.send(model.association_key(column))
      opts[:value] = "#{key} - #{model.column_value(type, request, obj, column)}"
    end
  end
  opts
end

#csv(meth) ⇒ Object

Return a string in CSV format with the results



182
183
184
185
186
187
188
189
190
# File 'lib/autoforme/action.rb', line 182

def csv(meth)
  @output_type = 'csv'
  @output_filename = "#{model.link.downcase}_#{normalized_type}.csv"
  columns = model.columns_for(type, request)
  headers = columns.map{|column| column_label_for(type, request, model, column)}
  EnumCSV.csv(model.send(meth, normalized_type, request, :all_results=>true), :headers=>headers) do |obj|
    columns.map{|column| model.column_value(type, request, obj, column)}
  end
end

#edit_page(obj) ⇒ Object

The page to use when editing the object.



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/autoforme/action.rb', line 341

def edit_page(obj)
  page do
    t = String.new
    t << Forme.form(obj, form_attributes(:action=>url_for("update/#{model.primary_key_value(obj)}")), form_opts) do |f|
      model.columns_for(:edit, request).each do |column|
        col_opts = column_options_for(:edit, request, obj, column)
        if html = model.edit_html_for(obj, column, :edit, request)
          col_opts = col_opts.merge(:html=>html)
        end
        f.input(column, col_opts)
      end
      f.button(:value=>'Update', :class=>'btn btn-primary')
    end.to_s
    if model.supported_action?(:delete, request)
      t << Forme.form(form_attributes(:action=>url_for("delete/#{model.primary_key_value(obj)}")), form_opts) do |f|
        f.button(:value=>'Delete', :class=>'btn btn-danger')
      end.to_s
    end
    t << association_links(obj)
  end
end

#form_attributes(attrs) ⇒ Object

Merge the model’s form attributes into the given form attributes, yielding the attributes to use for the form.



239
240
241
# File 'lib/autoforme/action.rb', line 239

def form_attributes(attrs)
  attrs.merge(model.form_attributes_for(type, request))
end

#form_optsObject

Options to use for the form. If the form uses POST, automatically adds the CSRF token.



228
229
230
231
232
233
234
235
# File 'lib/autoforme/action.rb', line 228

def form_opts
  opts = model.form_options_for(type, request).dup
  hidden_tags = opts[:hidden_tags] = []
  if csrf = request.csrf_token_hash
    hidden_tags << lambda{|tag| csrf if tag.attr[:method].to_s.upcase == 'POST'}
  end
  opts
end

#h(s) ⇒ Object

Convert input to a string adn HTML escape it.



99
100
101
# File 'lib/autoforme/action.rb', line 99

def h(s)
  Rack::Utils.escape_html(s.to_s)
end

#handleObject

Handle the current action, returning an HTML string containing the page content, or redirecting.



149
150
151
152
# File 'lib/autoforme/action.rb', line 149

def handle
  model.before_action_hook(type, request)
  send("handle_#{type}")
end

Handle association_links action by returning an HTML fragment of association links.



531
532
533
534
535
# File 'lib/autoforme/action.rb', line 531

def handle_association_links
  @type = @normalized_type = @subtype
  obj = model.with_pk(@type, request, request.id)
  association_links(obj)
end

#handle_autocompleteObject

Handle autocomplete action by returning a string with one line per model object.



538
539
540
541
542
# File 'lib/autoforme/action.rb', line 538

def handle_autocomplete
  unless (query = request.params['q'].to_s).empty?
    model.autocomplete(:type=>@subtype, :request=>request, :association=>params_association, :query=>query, :exclude=>request.params['exclude']).join("\n")
  end
end

#handle_browseObject

Handle browse action by showing a table containing model objects.



436
437
438
439
440
441
442
# File 'lib/autoforme/action.rb', line 436

def handle_browse
  if request.id == 'csv'
    csv(:browse)
  else
    table_page(*model.browse(type, request))
  end
end

#handle_createObject

Handle the create action by creating a new model object.



267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/autoforme/action.rb', line 267

def handle_create
  obj = model.new(nil, request)
  model.set_fields(obj, :new, request, model_params)
  model.hook(:before_create, request, obj)
  if model.save(obj)
    model.hook(:after_create, request, obj)
    request.set_flash_notice("Created #{model.class_name}")
    redirect(:new, obj)
  else
    request.set_flash_now_error("Error Creating #{model.class_name}")
    new_page(obj)
  end
end

#handle_deleteObject

Handle the edit action by showing a list page if there is no model object selected, or a confirmation screen if there is one.



390
391
392
393
394
395
396
# File 'lib/autoforme/action.rb', line 390

def handle_delete
  if request.id
    handle_show
  else
    list_page(:delete, :form=>{:action=>url_for('delete')})
  end
end

#handle_destroyObject

Handle the destroy action by destroying the model object.



399
400
401
402
403
404
405
406
# File 'lib/autoforme/action.rb', line 399

def handle_destroy
  obj = model.with_pk(normalized_type, request, request.id)
  model.hook(:before_destroy, request, obj)
  model.destroy(obj)
  model.hook(:after_destroy, request, obj)
  request.set_flash_notice("Deleted #{model.class_name}")
  redirect(:delete, obj)
end

#handle_editObject

Handle the edit action by showing a list page if there is no model object selected, or the edit page if there is one.



364
365
366
367
368
369
370
371
372
# File 'lib/autoforme/action.rb', line 364

def handle_edit
  if request.id
    obj = model.with_pk(normalized_type, request, request.id)
    model.hook(:before_edit, request, obj)
    edit_page(obj)
  else
    list_page(:edit)
  end
end

#handle_mtm_editObject

Handle the mtm_edit action by showing a list page if there is no model object selected, a list of associations for that model if there is a model object but no association selected, or a mtm_edit form if there is a model object and association selected.



469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/autoforme/action.rb', line 469

def handle_mtm_edit
  if request.id
    obj = model.with_pk(:edit, request, request.id)
    unless assoc = params_association
      options = model.mtm_association_select_options(request)
      if options.length == 1
        assoc = options.first
      end
    end
    if assoc
      page do
        t = String.new
        t << "<h2>Edit #{humanize(assoc)} for #{h model.object_display_name(type, request, obj)}</h2>"
        t << Forme.form(obj, form_attributes(:action=>url_for("mtm_update/#{model.primary_key_value(obj)}?association=#{assoc}")), form_opts) do |f|
          opts = model.column_options_for(:mtm_edit, request, assoc)
          add_opts = opts[:add] ? opts.merge(opts.delete(:add)) : opts
          remove_opts = opts[:remove] ? opts.merge(opts.delete(:remove)) : opts
          add_opts = {:name=>'add[]', :id=>'add', :label=>'Associate With'}.merge(add_opts)
          if model.association_autocomplete?(assoc, request)
            f.input(assoc, {:type=>'text', :class=>'autoforme_autocomplete', :attr=>{'data-type'=>'association', 'data-column'=>assoc, 'data-exclude'=>model.primary_key_value(obj)}, :value=>''}.merge(add_opts))
          else
            f.input(assoc, {:dataset=>model.unassociated_mtm_objects(request, assoc, obj)}.merge(add_opts))
          end
          f.input(assoc, {:name=>'remove[]', :id=>'remove', :label=>'Disassociate From', :dataset=>model.associated_mtm_objects(request, assoc, obj), :value=>[]}.merge(remove_opts))
          f.button(:value=>'Update', :class=>'btn btn-primary')
        end.to_s
      end
    else
      page do
        Forme.form(form_attributes(:action=>"mtm_edit/#{model.primary_key_value(obj)}"), form_opts) do |f|
          f.input(:select, :options=>options, :name=>'association', :id=>'association', :label=>'Association', :add_blank=>true)
          f.button(:value=>'Edit', :class=>'btn btn-primary')
        end
      end
    end
  else
    list_page(:edit, :form=>{})
  end
end

#handle_mtm_updateObject

Handle mtm_update action by updating the related many to many association. For ajax requests, return an HTML fragment to update the page, otherwise redirect to the appropriate form.



511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
# File 'lib/autoforme/action.rb', line 511

def handle_mtm_update
  obj = model.with_pk(:edit, request, request.id)
  assoc = params_association
  assoc_obj = model.mtm_update(request, assoc, obj, request.params['add'], request.params['remove'])
  request.set_flash_notice("Updated #{assoc} association for #{model.class_name}") unless request.xhr?
  if request.xhr?
    if request.params['add']
      @type = :edit
      mtm_edit_remove(assoc, model.associated_model_class(assoc), obj, assoc_obj)
    else
      "<option value=\"#{model.primary_key_value(assoc_obj)}\">#{model.associated_object_display_name(assoc, request, assoc_obj)}</option>"
    end
  elsif request.params['redir'] == 'edit'
    redirect(:edit, obj)
  else
    redirect(:mtm_edit, obj)
  end
end

#handle_newObject

Handle the new action by always showing the new form.



260
261
262
263
264
# File 'lib/autoforme/action.rb', line 260

def handle_new
  obj = model.new(request.params[model.link], request)
  model.hook(:before_new, request, obj)
  new_page(obj)
end

#handle_searchObject

Handle browse action by showing a search form if no page is selected, or the correct page of search results if there is a page selected.



446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'lib/autoforme/action.rb', line 446

def handle_search
  if request.id == 'csv'
    csv(:search_results)
  elsif request.id
    table_page(*model.search_results(normalized_type, request))
  else
    page do
      Forme.form(model.new(nil, request), form_attributes(:action=>url_for("search/1"), :method=>:get), form_opts) do |f|
        model.columns_for(:search_form, request).each do |column|
          col_opts = column_options_for(:search_form, request, f.obj, column).merge(:name=>column, :id=>column)
          if html = model.edit_html_for(f.obj, column, :search_form, request)
            col_opts[:html] = html
          end
          f.input(column, col_opts)
        end
        f.button(:value=>'Search', :class=>'btn btn-primary')
      end
    end
  end
end

#handle_showObject

Handle the show action by showing a list page if there is no model object selected, or the show page if there is one.



332
333
334
335
336
337
338
# File 'lib/autoforme/action.rb', line 332

def handle_show
  if request.id
    show_page(model.with_pk(normalized_type, request, request.id))
  else
    list_page(:show)
  end
end

#handle_updateObject

Handle the update action by updating the current model object.



375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/autoforme/action.rb', line 375

def handle_update
  obj = model.with_pk(normalized_type, request, request.id)
  model.set_fields(obj, :edit, request, model_params)
  model.hook(:before_update, request, obj)
  if model.save(obj)
    model.hook(:after_update, request, obj)
    request.set_flash_notice("Updated #{model.class_name}")
    redirect(:edit, obj)
  else
    request.set_flash_now_error("Error Updating #{model.class_name}")
    edit_page(obj)
  end
end

#humanize(string) ⇒ Object

Convert the given object into a suitable human readable string.



155
156
157
158
# File 'lib/autoforme/action.rb', line 155

def humanize(string)
  string = string.to_s
  string.respond_to?(:humanize) ? string.humanize : string.gsub(/_/, " ").capitalize
end

#inline_mtm_edit_forms(obj) ⇒ Object

HTML fragment used for the inline mtm_edit forms on the edit page.



636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
# File 'lib/autoforme/action.rb', line 636

def inline_mtm_edit_forms(obj)
  assocs = model.inline_mtm_assocs(request)
  return if assocs.empty?

  t = String.new
  t << "<div class='inline_mtm_add_associations'>"
  assocs.each do |assoc|
    form_attr = form_attributes(:action=>url_for("mtm_update/#{model.primary_key_value(obj)}?association=#{assoc}&redir=edit"), :class => 'mtm_add_associations', 'data-remove' => "##{assoc}_remove_list")
    t << Forme.form(obj, form_attr, form_opts) do |f|
      opts = model.column_options_for(:mtm_edit, request, assoc)
      add_opts = opts[:add] ? opts.merge(opts.delete(:add)) : opts.dup
      add_opts = {:name=>'add[]', :id=>"add_#{assoc}"}.merge(add_opts)
      if model.association_autocomplete?(assoc, request)
        f.input(assoc, {:type=>'text', :class=>'autoforme_autocomplete', :attr=>{'data-type'=>'association', 'data-column'=>assoc, 'data-exclude'=>model.primary_key_value(obj)}, :value=>''}.merge(add_opts))
      else
        f.input(assoc, {:dataset=>model.unassociated_mtm_objects(request, assoc, obj), :multiple=>false, :add_blank=>true}.merge(add_opts))
      end
      f.button(:value=>'Add', :class=>'btn btn-xs btn-primary')
    end.to_s
  end
  t << "</div>"
  t << "<div class='inline_mtm_remove_associations'><ul>"
  assocs.each do |assoc|
    mc = model.associated_model_class(assoc)
    t << "<li>"
    t << association_class_link(mc, assoc)
    t << "<ul id='#{assoc}_remove_list'>"
    obj.send(assoc).each do |assoc_obj|
      t << mtm_edit_remove(assoc, mc, obj, assoc_obj)
    end
    t << "</ul></li>"
  end
  t << "</ul></div>"
end

#list_page(type, opts = {}) ⇒ Object

Shared page used by show, edit, and delete actions that shows a list of available model objects (or an autocompleting box), and allows the user to choose one to act on.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/autoforme/action.rb', line 283

def list_page(type, opts={})
  page do
    form_attr = form_attributes(opts[:form] || {:action=>url_for(type)})
    Forme.form(form_attr, form_opts) do |f|
      input_opts = {:name=>'id', :id=>'id', :label=>model.class_name}
      if model.autocomplete_options_for(type, request)
        input_type = :text
        input_opts.merge!(:class=>'autoforme_autocomplete', :attr=>{'data-type'=>type})
      else
        input_type = :select
        input_opts.merge!(:options=>model.select_options(type, request), :add_blank=>true)
      end
      f.input(input_type, input_opts)
      f.button(:value=>type.to_s.capitalize, :class=>"btn btn-#{type == :delete ? 'danger' : 'primary'}")
    end
  end
end

#model_paramsObject

Get request parameters for the model. Used when retrieving form values that use namespacing.



105
106
107
# File 'lib/autoforme/action.rb', line 105

def model_params
  request.params[model.params_name]
end

#mtm_edit_remove(assoc, mc, obj, assoc_obj) ⇒ Object

Line item containing form to remove the currently associated object.



672
673
674
675
676
677
678
679
680
681
# File 'lib/autoforme/action.rb', line 672

def mtm_edit_remove(assoc, mc, obj, assoc_obj)
  t = String.new
  t << "<li>"
  t << association_link(mc, assoc_obj)
  form_attr = form_attributes(:action=>url_for("mtm_update/#{model.primary_key_value(obj)}?association=#{assoc}&remove%5b%5d=#{model.primary_key_value(assoc_obj)}&redir=edit"), :method=>'post', :class => 'mtm_remove_associations', 'data-add'=>"#add_#{assoc}")
  t << Forme.form(form_attr, form_opts) do |f|
    f.button(:value=>'Remove', :class=>'btn btn-xs btn-danger')
  end.to_s
  t << "</li>"
end

#new_page(obj, opts = {}) ⇒ Object

HTML content used for the new action



244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/autoforme/action.rb', line 244

def new_page(obj, opts={})
  page do
    Forme.form(obj, form_attributes(:action=>url_for("create")), form_opts) do |f|
      model.columns_for(:new, request).each do |column|
        col_opts = column_options_for(:new, request, obj, column)
        if html = model.edit_html_for(obj, column, :new, request)
          col_opts = col_opts.merge(:html=>html)
        end
        f.input(column, col_opts)
      end
      f.button(:value=>'Create', :class=>'btn btn-primary')
    end
  end
end

#pageObject

Yields and wraps the returned data in a header and footer for the page.



217
218
219
220
221
222
223
224
225
# File 'lib/autoforme/action.rb', line 217

def page
  html = String.new
  html << (model.page_header_for(type, request) || tabs)
  html << "<div id='autoforme_content' data-url='#{url_for('')}'>"
  html << yield.to_s
  html << "</div>"
  html << model.page_footer_for(type, request).to_s
  html
end

#redirect(type, obj) ⇒ Object

Redirect to a page based on the type of action and the given object.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/autoforme/action.rb', line 126

def redirect(type, obj)
  if redir = model.redirect_for
    path = redir.call(obj, type, request)
  end

  unless path
    path = case type
    when :new, :delete
      type.to_s
    when :edit
      "edit/#{model.primary_key_value(obj)}"
    when :mtm_edit
      "mtm_edit/#{model.primary_key_value(obj)}?association=#{params_association}"
    end
    path = url_for(path)
  end

  request.redirect(path)
  nil
end

#show_page(obj) ⇒ Object

The page to use when displaying an object, always used as a confirmation screen when deleting an object.



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/autoforme/action.rb', line 302

def show_page(obj)
  page do
    t = String.new
    f = Forme::Form.new(obj, :formatter=>:readonly, :wrapper=>:trtd, :labeler=>:explicit)
    t << "<table class=\"#{model.table_class_for(:show, request)}\">"
    model.columns_for(type, request).each do |column|
      col_opts = column_options_for(type, request, obj, column)
      if html = model.show_html_for(obj, column, type, request)
        col_opts = col_opts.merge(:html=>html)
      end
      t << f.input(column, col_opts).to_s
    end
    t << '</table>'
    if type == :show && model.supported_action?(:edit, request)
      t << Forme.form(form_attributes(:action=>url_for("edit/#{model.primary_key_value(obj)}")), form_opts) do |f1|
        f1.button(:value=>'Edit', :class=>'btn btn-primary')
      end.to_s
    end
    if type == :delete
      t << Forme.form(form_attributes(:action=>url_for("destroy/#{model.primary_key_value(obj)}"), :method=>:post), form_opts) do |f1|
        f1.button(:value=>'Delete', :class=>'btn btn-danger')
      end.to_s
    else
      t << association_links(obj)
    end
    t
  end
end

#subtypeObject

The subtype of request, used for association_links and autocomplete actions.



121
122
123
# File 'lib/autoforme/action.rb', line 121

def subtype
  ((t = request.params['type']) && ALL_SUPPORTED_ACTIONS.include?(t) && t.to_sym) || :edit
end

#supported?Boolean

Return true if the action is supported, and false otherwise. An action may not be supported if the type is not one of the supported types, or if an non-idemponent request is issued with get instead of post, or potentionally other reasons.

As a side-effect, this sets up additional state related to the request.

Returns:

  • (Boolean)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/autoforme/action.rb', line 55

def supported?
  return false unless ALL_SUPPORTED_ACTIONS.include?(request.action_type)
  type = @type = request.action_type.to_sym
  @normalized_type = NORMALIZED_ACTION_MAP.fetch(type, type)
  return false if NON_IDEMPOTENT_TYPES[type] && !request.post?

  case type
  when :mtm_edit
    return false unless model.supported_action?(type, request)
    if request.id && (assoc = request.params['association'])
      return false unless model.supported_mtm_edit?(assoc, request)
      @params_association = assoc.to_sym
    end

    @title = "#{model.class_name} - #{TITLE_MAP[type]}"
  when :mtm_update
    return false unless request.id && (assoc = request.params['association']) && model.supported_mtm_update?(assoc, request)
    @params_association = assoc.to_sym
  when :association_links
    @subtype = subtype
    return false unless model.supported_action?(@subtype, request)
  when :autocomplete
    if assoc = request.id
      return false unless model.association?(assoc)
      @params_association = assoc.to_sym
      @subtype = :association
      return false unless associated_class = model.associated_model_class(@params_association)
      return false unless associated_class.autocomplete_options_for(@subtype, request)
    else
      @subtype = subtype
      return false unless model.autocomplete_options_for(@subtype, request)
    end
  else
    return false unless model.supported_action?(normalized_type, request)

    if title = TITLE_MAP[type]
      @title = "#{model.class_name} - #{title}"
    end
  end

  true
end

#tab_name(type) ⇒ Object

The name to give the tab for the given type.



205
206
207
208
209
210
211
212
213
214
# File 'lib/autoforme/action.rb', line 205

def tab_name(type)
  case type
  when :browse
    model.class_name
  when :mtm_edit
    'MTM'
  else
    type.to_s.capitalize
  end
end

#table_page(next_page, objs) ⇒ Object

Show page used for browse/search pages.



429
430
431
432
433
# File 'lib/autoforme/action.rb', line 429

def table_page(next_page, objs)
  page do
    Table.new(self, objs).to_s << table_pager(normalized_type, next_page)
  end
end

#table_pager(type, next_page) ⇒ Object

HTML fragment for the table pager, showing links to next page or previous page for browse/search forms.



409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/autoforme/action.rb', line 409

def table_pager(type, next_page)
  html = String.new
  html << '<ul class="pager">'
  page = request.id.to_i
  if page > 1
    html << "<li><a href=\"#{url_for("#{type}/#{page-1}?#{h request.query_string}")}\">Previous</a></li>"
  else
    html << '<li class="disabled"><a href="#">Previous</a></li>'
  end
  if next_page
    page = 1 if page < 1
    html << "<li><a href=\"#{url_for("#{type}/#{page+1}?#{h request.query_string}")}\">Next</a></li>"
  else
    html << '<li class="disabled"><a href="#">Next</a></li>'
  end
  html << "</ul>"
  html << "<p><a href=\"#{url_for("#{type}/csv?#{h request.query_string}")}\">CSV Format</a></p>"
end

#tabsObject

HTML fragment for the default page header, which uses tabs for each supported action.



193
194
195
196
197
198
199
200
201
202
# File 'lib/autoforme/action.rb', line 193

def tabs
  content = String.new
  content << '<ul class="nav nav-tabs">'
  Model::DEFAULT_SUPPORTED_ACTIONS.each do |action_type|
    if model.supported_action?(action_type, request)
      content << "<li class=\"#{'active' if type == action_type}\"><a href=\"#{url_for(action_type)}\">#{tab_name(action_type)}</a></li>"
    end
  end
  content << '</ul>'
end

#url_for(page) ⇒ Object

A path for the given page for the same model.



116
117
118
# File 'lib/autoforme/action.rb', line 116

def url_for(page)
  base_url_for("#{model.link}/#{page}")
end