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.



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

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.



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

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.



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

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.



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

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.



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

def edit_page(obj)
  page do
    t = String.new
    form_attr = form_attributes(:action=>url_for("update/#{model.primary_key_value(obj)}"))
    t << Forme.form(obj, form_attr, form_opts(form_attr[:action])) 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_opts(action = nil) ⇒ Object

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(action=nil)
  opts = model.form_options_for(type, request).dup
  hidden_tags = opts[:hidden_tags] = []
  if csrf = request.csrf_token_hash(action)
    hidden_tags << lambda{|tag| csrf if (tag.attr[:method] || 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.



535
536
537
538
539
# File 'lib/autoforme/action.rb', line 535

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.



542
543
544
545
546
# File 'lib/autoforme/action.rb', line 542

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.



439
440
441
442
443
444
445
# File 'lib/autoforme/action.rb', line 439

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.



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

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.



393
394
395
396
397
398
399
# File 'lib/autoforme/action.rb', line 393

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.



402
403
404
405
406
407
408
409
# File 'lib/autoforme/action.rb', line 402

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.



367
368
369
370
371
372
373
374
375
# File 'lib/autoforme/action.rb', line 367

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.



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

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>"
        form_attr = form_attributes(:action=>url_for("mtm_update/#{model.primary_key_value(obj)}?association=#{assoc}"))
        t << Forme.form(obj, form_attr, form_opts(form_attr[:action])) 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), :size=>10}.merge(add_opts))
          end
          f.input(assoc, {:name=>'remove[]', :id=>'remove', :label=>'Disassociate From', :dataset=>model.associated_mtm_objects(request, assoc, obj), :value=>[], :size=>10}.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.



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

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.



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

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.



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

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.



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

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.



378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/autoforme/action.rb', line 378

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.



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

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(form_attr[:action])) 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.



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

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.



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

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(form_attr[:action])) 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
258
# File 'lib/autoforme/action.rb', line 244

def new_page(obj, opts={})
  page do
    form_attr = form_attributes(:action=>url_for("create"))
    Forme.form(obj, form_attr, form_opts(form_attr[:action])) 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.



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

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
      form_attr = form_attributes(:action=>url_for("destroy/#{model.primary_key_value(obj)}"), :method=>:post)
      t << Forme.form(form_attr, form_opts(form_attr[:action])) 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.



432
433
434
435
436
# File 'lib/autoforme/action.rb', line 432

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.



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

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