Class: AutoForme::Model

Inherits:
Object
  • Object
show all
Extended by:
OptsAttributes
Defined in:
lib/autoforme/model.rb

Overview

Wraps a specific model class

Direct Known Subclasses

AutoForme::Models::Sequel

Constant Summary collapse

AUTOCOMPLETE_TYPES =

Array of supported autocomplete types

[:show, :edit, :delete, :association, :mtm_edit].freeze
DEFAULT_LIMIT =

The default number of records to show on each browse/search results pages

25
DEFAULT_TABLE_CLASS =

The default table class to use for browse/search results pages

"table table-bordered table-striped"
DEFAULT_SUPPORTED_ACTIONS =

The default supported actions for models.

[:browse, :new, :show, :edit, :delete, :search, :mtm_edit]
VALID_CONSTANT_NAME_REGEXP =

Regexp for valid constant names, to prevent code execution.

/\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OptsAttributes

opts_attribute

Constructor Details

#initialize(model, framework) ⇒ Model

Returns a new instance of Model.



46
47
48
49
50
# File 'lib/autoforme/model.rb', line 46

def initialize(model, framework)
  @model = model
  @framework = framework
  @opts = {}
end

Instance Attribute Details

#frameworkObject (readonly)

The AutoForme::Framework class tied to the current model



32
33
34
# File 'lib/autoforme/model.rb', line 32

def framework
  @framework
end

#optsObject (readonly)

The options for the given model.



35
36
37
# File 'lib/autoforme/model.rb', line 35

def opts
  @opts
end

Class Method Details

.for(framework, type, model_class, &block) ⇒ Object

Create a new instance for the given model type and underlying model class tied to the given framework.



25
26
27
28
29
# File 'lib/autoforme/model.rb', line 25

def self.for(framework, type, model_class, &block)
  model = AutoForme.model_class_for(type).new(model_class, framework)
  model.instance_exec(&block) if block
  model
end

Instance Method Details

#associated_model_class(assoc) ⇒ Object

The AutoForme::Model instance associated to the given association.



246
247
248
# File 'lib/autoforme/model.rb', line 246

def associated_model_class(assoc)
  framework.model_class(associated_class(assoc))
end

#associated_object_display_name(assoc, request, obj) ⇒ Object

A human reable string for the associated object.



339
340
341
# File 'lib/autoforme/model.rb', line 339

def associated_object_display_name(assoc, request, obj)
  apply_name_method(column_options_for(:mtm_edit, request, assoc)[:name_method], obj, :mtm_edit, request)
end


204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/autoforme/model.rb', line 204

def association_links_for(type, request)
  case v = handle_proc(association_links || framework.association_links_for(model, type, request), type, request)
  when nil
    []
  when Array
    v
  when :all
    association_names
  when :all_except_mtm
    association_names - mtm_association_names
  else
    [v]
  end
end

#autocomplete_options_for(type, request) ⇒ Object



226
227
228
229
230
231
232
233
# File 'lib/autoforme/model.rb', line 226

def autocomplete_options_for(type, request)
  return unless AUTOCOMPLETE_TYPES.include?(type)
  framework_opts = framework.autocomplete_options_for(model, type, request)
  model_opts = handle_proc(autocomplete_options, type, request)
  if model_opts
    (framework_opts || {}).merge(model_opts)
  end
end

#before_action_hook(type, request) ⇒ Object

Run framework and model before_action hooks with type symbol and request.



276
277
278
279
280
281
282
283
# File 'lib/autoforme/model.rb', line 276

def before_action_hook(type, request)
  if v = framework.before_action
    v.call(type, request)
  end
  if v = before_action
    v.call(type, request)
  end
end

#class_nameObject

The name to display to the user for this model.



236
237
238
# File 'lib/autoforme/model.rb', line 236

def class_name
  class_display_name || model.name
end

#column_options_for(type, request, column) ⇒ Object

The options to use for the given column and request. Instead of the model options overriding the framework options, they are merged together.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/autoforme/model.rb', line 100

def column_options_for(type, request, column)
  framework_opts = case framework_opts = framework.column_options
  when Proc, Method
    framework_opts.call(model, column, type, request) || {}
  else
    extract_column_options(framework_opts, column, type, request)
  end

  model_opts = case model_opts = column_options
  when Proc, Method
    model_opts.call(column, type, request) || {}
  else
    extract_column_options(model_opts, column, type, request)
  end

  opts = framework_opts.merge(model_opts).dup

  if association?(column) && associated_model = associated_model_class(column)
    if associated_model.autocomplete_options_for(:association, request) && !opts[:as] && association_type(column) == :one
      opts[:type] = 'text'
      opts[:class] = 'autoforme_autocomplete'
      opts[:attr] = {'data-column'=>column, 'data-type'=>type}
      opts[:name] = form_param_name(column)
    else
      unless opts[:name_method]
        opts[:name_method] = lambda{|obj| associated_model.object_display_name(:association, request, obj)}
      end

      case type
      when :edit, :new, :search_form
        unless opts[:options] || opts[:dataset]
          opts[:dataset] = lambda{|ds| associated_model.apply_dataset_options(:association, request, ds)}
        end
      end
    end
  end

  case type
  when :show, :search_form
    opts[:required] = false unless opts.has_key?(:required)
    if type == :search_form && opts[:as] == :textarea
      opts.delete(:as)
    end
  end

  opts
end

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

The column value to display for the given object and column.



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/autoforme/model.rb', line 251

def column_value(type, request, obj, column)
  v = obj.send(column)
  return if v.nil?
  if association?(column) 
    opts = column_options_for(type, request, column) 
    case nm = opts[:name_method]
    when Symbol, String
      v = v.send(nm)
    when nil
    else
      v = nm.call(v)
    end
  end
  if v.is_a?(base_class)
    v = default_object_display_name(v)
  end
  v
end

#columns_for(type, request) ⇒ Object



94
95
96
# File 'lib/autoforme/model.rb', line 94

def columns_for(type, request)
  handle_proc(columns || framework.columns_for(model, type, request), type, request) || default_columns
end

#default_object_display_name(obj) ⇒ Object

A fallback for the display name for the object if none is configured.



344
345
346
347
348
349
350
351
352
# File 'lib/autoforme/model.rb', line 344

def default_object_display_name(obj)
  if obj.respond_to?(:forme_name)
    obj.forme_name
  elsif obj.respond_to?(:name)
    obj.name
  else
    primary_key_value(obj)
  end.to_s
end

#destroy(obj) ⇒ Object

Destroy the given object, deleting it from the database.



271
272
273
# File 'lib/autoforme/model.rb', line 271

def destroy(obj)
  obj.destroy
end

#display_name_forObject



200
201
202
# File 'lib/autoforme/model.rb', line 200

def display_name_for
  display_name || framework.display_name_for(model)
end

#eager_for(type, request) ⇒ Object



160
161
162
# File 'lib/autoforme/model.rb', line 160

def eager_for(type, request)
  handle_proc(eager, type, request)
end

#eager_graph_for(type, request) ⇒ Object



164
165
166
# File 'lib/autoforme/model.rb', line 164

def eager_graph_for(type, request)
  handle_proc(eager_graph, type, request)
end

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



152
153
154
# File 'lib/autoforme/model.rb', line 152

def edit_html_for(obj, column, type, request)
  handle_proc(edit_html || framework.edit_html_for(obj, column, type, request), obj, column, type, request)
end

#filter_forObject



168
169
170
# File 'lib/autoforme/model.rb', line 168

def filter_for
  filter || framework.filter_for(model)
end

#form_attributes_for(type, request) ⇒ Object



176
177
178
# File 'lib/autoforme/model.rb', line 176

def form_attributes_for(type, request)
  framework.form_attributes_for(model, type, request).merge(handle_proc(form_attributes, type, request) || {})
end

#form_options_for(type, request) ⇒ Object



180
181
182
# File 'lib/autoforme/model.rb', line 180

def form_options_for(type, request)
  framework.form_options_for(model, type, request).merge(handle_proc(form_options, type, request) || {})
end

#hook(type, request, obj) ⇒ Object

Run given hooks with the related object and request.



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

def hook(type, request, obj)
  if type.to_s =~ /before/
    if v = framework.send(type)
      v.call(obj, request)
    end
    if v = send(type)
      v.call(obj, request)
    end
  else
    if v = send(type)
      v.call(obj, request)
    end
    if v = framework.send(type)
      v.call(obj, request)
    end
  end
end

#inline_mtm_assocs(request) ⇒ Object

An array of many to many association symbols to handle inline on the edit forms.



90
91
92
# File 'lib/autoforme/model.rb', line 90

def inline_mtm_assocs(request)
  normalize_mtm_associations(handle_proc(inline_mtm_associations || framework.inline_mtm_associations_for(model, request), request))
end

#lazy_load_association_links?(type, request) ⇒ Boolean

Whether to lazy load association links for this model.

Returns:

  • (Boolean)


220
221
222
223
224
# File 'lib/autoforme/model.rb', line 220

def lazy_load_association_links?(type, request)
  v = handle_proc(lazy_load_association_links, type, request)
  v = framework.lazy_load_association_links?(model, type, request) if v.nil?
  v || false
end

#limit_for(type, request) ⇒ Object



196
197
198
# File 'lib/autoforme/model.rb', line 196

def limit_for(type, request)
  handle_proc(per_page || framework.limit_for(model, type, request), type, request) || DEFAULT_LIMIT
end

The name to use in links for this model. Also affects where this model is mounted at.



241
242
243
# File 'lib/autoforme/model.rb', line 241

def link
  link_name || class_name
end

#modelObject

The underlying model class for the current model



53
54
55
56
57
58
59
60
61
# File 'lib/autoforme/model.rb', line 53

def model
  if @model.is_a?(Class)
    @model
  elsif m = VALID_CONSTANT_NAME_REGEXP.match(@model)
    Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
  else
    raise Error, "invalid model for AutoForme::Model, not a class or valid constant name: #{@model.inspect}"
  end
end

#mtm_association_select_options(request) ⇒ Object

An array of many to many association symbols to handle via a separate mtm_edit page.



75
76
77
# File 'lib/autoforme/model.rb', line 75

def mtm_association_select_options(request)
  normalize_mtm_associations(handle_proc(mtm_associations || framework.mtm_associations_for(model, request), request))
end

#new(params, request) ⇒ Object

Create a new instance of the underlying model, setting defaults based on the params given.



306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/autoforme/model.rb', line 306

def new(params, request)
  obj = model.new
  if params
    columns_for(:new, request).each do |col|
      if association?(col)
        col = association_key(col)
      end
      if v = params[col.to_s]
        obj.send("#{col}=", v)
      end
    end
  end
  obj
end

#object_display_name(type, request, obj) ⇒ Object

A human readable string representing the object.



334
335
336
# File 'lib/autoforme/model.rb', line 334

def object_display_name(type, request, obj)
  apply_name_method(display_name_for, obj, type, request).to_s
end

#order_for(type, request) ⇒ Object



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

def order_for(type, request)
  handle_proc(order || framework.order_for(model, type, request), type, request)
end


184
185
186
# File 'lib/autoforme/model.rb', line 184

def page_footer_for(type, request)
  handle_proc(page_footer || framework.page_footer_for(model, type, request), type, request)
end

#page_header_for(type, request) ⇒ Object



188
189
190
# File 'lib/autoforme/model.rb', line 188

def page_header_for(type, request)
  handle_proc(page_header || framework.page_header_for(model, type, request), type, request)
end

#redirect_forObject



172
173
174
# File 'lib/autoforme/model.rb', line 172

def redirect_for
  redirect || framework.redirect_for(model)
end

#select_options(type, request, opts = {}) ⇒ Object

An array of pairs for the select options to return for the given type.



322
323
324
325
326
327
328
329
330
331
# File 'lib/autoforme/model.rb', line 322

def select_options(type, request, opts={})
  case nm = opts[:name_method]
  when Symbol, String
    all_rows_for(type, request).map{|obj| [obj.send(nm), primary_key_value(obj)]}
  when nil
    all_rows_for(type, request).map{|obj| [object_display_name(type, request, obj), primary_key_value(obj)]}
  else
    all_rows_for(type, request).map{|obj| [nm.call(obj), primary_key_value(obj)]}
  end
end

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



148
149
150
# File 'lib/autoforme/model.rb', line 148

def show_html_for(obj, column, type, request)
  handle_proc(show_html || framework.show_html_for(obj, column, type, request), obj, column, type, request)
end

#supported_action?(type, request) ⇒ Boolean

Whether the given type of action is supported for this model.

Returns:

  • (Boolean)


64
65
66
67
68
69
70
71
72
# File 'lib/autoforme/model.rb', line 64

def supported_action?(type, request)
  v = (handle_proc(supported_actions || framework.supported_actions_for(model, request), request) || DEFAULT_SUPPORTED_ACTIONS).include?(type)
  if v && type == :mtm_edit
    assocs = mtm_association_select_options(request)
    assocs && !assocs.empty?
  else
    v
  end
end

#supported_mtm_edit?(assoc, request) ⇒ Boolean

Whether an mtm_edit can be displayed for the given association

Returns:

  • (Boolean)


80
81
82
# File 'lib/autoforme/model.rb', line 80

def supported_mtm_edit?(assoc, request)
  mtm_association_select_options(request).map(&:to_s).include?(assoc)
end

#supported_mtm_update?(assoc, request) ⇒ Boolean

Whether an mtm_update can occur for the given association

Returns:

  • (Boolean)


85
86
87
# File 'lib/autoforme/model.rb', line 85

def supported_mtm_update?(assoc, request)
  supported_mtm_edit?(assoc, request) || inline_mtm_assocs(request).map(&:to_s).include?(assoc) 
end

#table_class_for(type, request) ⇒ Object



192
193
194
# File 'lib/autoforme/model.rb', line 192

def table_class_for(type, request)
  handle_proc(table_class || framework.table_class_for(model, type, request), type, request) || DEFAULT_TABLE_CLASS
end