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
NORMALIZED_ACTION_MAP =

Map of regular type symbols to normalized type symbols

{: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.



617
618
619
620
621
622
623
624
# File 'lib/autoforme/action.rb', line 617

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.



629
630
631
632
633
634
635
636
637
638
639
# File 'lib/autoforme/action.rb', line 629

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.



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
608
609
610
611
612
613
# File 'lib/autoforme/action.rb', line 563

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_obj|
        t << "<li>"
        t << association_link(mc, assoc_obj)
        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.



552
553
554
555
556
557
558
559
560
# File 'lib/autoforme/action.rb', line 552

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.



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

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.



180
181
182
183
184
185
# File 'lib/autoforme/action.rb', line 180

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.



167
168
169
170
171
172
173
174
175
176
177
# File 'lib/autoforme/action.rb', line 167

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



188
189
190
191
192
193
194
195
196
# File 'lib/autoforme/action.rb', line 188

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.



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/autoforme/action.rb', line 347

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.



245
246
247
# File 'lib/autoforme/action.rb', line 245

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.



234
235
236
237
238
239
240
241
# File 'lib/autoforme/action.rb', line 234

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.



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

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.



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

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

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



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

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.



544
545
546
547
548
# File 'lib/autoforme/action.rb', line 544

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.



442
443
444
445
446
447
448
# File 'lib/autoforme/action.rb', line 442

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.



273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/autoforme/action.rb', line 273

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.



396
397
398
399
400
401
402
# File 'lib/autoforme/action.rb', line 396

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.



405
406
407
408
409
410
411
412
# File 'lib/autoforme/action.rb', line 405

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.



370
371
372
373
374
375
376
377
378
# File 'lib/autoforme/action.rb', line 370

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.



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
508
509
510
511
512
513
# File 'lib/autoforme/action.rb', line 475

def handle_mtm_edit
  if id = 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.



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
# File 'lib/autoforme/action.rb', line 517

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 add = 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.



266
267
268
269
270
# File 'lib/autoforme/action.rb', line 266

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.



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'lib/autoforme/action.rb', line 452

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.



338
339
340
341
342
343
344
# File 'lib/autoforme/action.rb', line 338

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.



381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/autoforme/action.rb', line 381

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.



161
162
163
164
# File 'lib/autoforme/action.rb', line 161

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

#idempotent?Boolean

Return whether the current action is an idempotent action.

Returns:

  • (Boolean)


103
104
105
# File 'lib/autoforme/action.rb', line 103

def idempotent?
  type == normalized_type
end

#inline_mtm_edit_forms(obj) ⇒ Object

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



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
670
671
672
673
674
675
# File 'lib/autoforme/action.rb', line 642

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-mini 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.



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/autoforme/action.rb', line 289

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.



109
110
111
# File 'lib/autoforme/action.rb', line 109

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.



678
679
680
681
682
683
684
685
686
687
# File 'lib/autoforme/action.rb', line 678

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-mini btn-danger')
  end.to_s
  t << "</li>"
end

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

HTML content used for the new action



250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/autoforme/action.rb', line 250

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.



223
224
225
226
227
228
229
230
231
# File 'lib/autoforme/action.rb', line 223

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.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/autoforme/action.rb', line 130

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}"
    else
      raise Error, "Unhandled redirect type: #{type.inspect}"
    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.



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/autoforme/action.rb', line 308

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 |f|
        f.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 |f|
        f.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.



125
126
127
# File 'lib/autoforme/action.rb', line 125

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
# File 'lib/autoforme/action.rb', line 55

def supported?
  return false unless idempotent? || request.post?
  return false unless ALL_SUPPORTED_ACTIONS.include?(request.action_type)

  @type = request.action_type.to_sym
  @normalized_type = NORMALIZED_ACTION_MAP.fetch(@type, @type)

  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
    else
      @subtype = subtype
    end
    return false unless model.autocomplete_options_for(@subtype, request)
  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.



211
212
213
214
215
216
217
218
219
220
# File 'lib/autoforme/action.rb', line 211

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.



435
436
437
438
439
# File 'lib/autoforme/action.rb', line 435

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.



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/autoforme/action.rb', line 415

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.



199
200
201
202
203
204
205
206
207
208
# File 'lib/autoforme/action.rb', line 199

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.



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

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