Class: Basepack::BaseController

Inherits:
InheritedResources::Base
  • Object
show all
Defined in:
app/controllers/basepack/base_controller.rb

Direct Known Subclasses

ResourcesController

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.actions(*actions_to_keep) ⇒ Object

Copied from inherited_resources for support of custom actions. Defines wich actions will be inherited from the inherited controller. Syntax is borrowed from resource_controller.

actions :index, :show, :edit
actions :all, :except => :index

Raises:

  • (ArgumentError)


21
22
23
24
25
26
27
28
29
30
31
# File 'app/controllers/basepack/base_controller.rb', line 21

def actions(*actions_to_keep)
  raise ArgumentError, 'Wrong number of arguments. You have to provide which actions you want to keep.' if actions_to_keep.empty?

  options = actions_to_keep.extract_options!
  actions_to_remove = Array(options[:except])
  actions_to_remove += __actions - actions_to_keep.map { |a| a.to_sym } unless actions_to_keep.first == :all
  actions_to_remove.map! { |a| a.to_sym }.uniq!
  (instance_methods.map { |m| m.to_sym } & actions_to_remove).each do |action|
    undef_method action, "#{action}!"
  end
end

.create_custom_action(resource_or_collection, action) ⇒ Object



10
11
12
13
# File 'app/controllers/basepack/base_controller.rb', line 10

def create_custom_action(resource_or_collection, action)
  super
  self.__actions += [action.to_sym]
end

Instance Method Details

#bulk_delete(options = {}, &block) ⇒ Object

DELETE

/resources/bulk_delete



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'app/controllers/basepack/base_controller.rb', line 243

def bulk_delete(options = {}, &block)
  unless params[:ids]
    redirect_to collection_url
    return
  end

  ids = params[:ids].split(',')
  col = collection_without_pagination.accessible_by(current_ability,
    :destroy).where(id: ids)

  ret = col.destroy_all

  destroyed_count = ret.count
  not_destroyed_count = ids.count - destroyed_count
  destroyed_message = "#{destroyed_count}
    #{resource_class.model_name.human(count: destroyed_count)}"

  if not_destroyed_count == 0
    flash[:success] = t("basepack.flash.successful",
      name: destroyed_message,
      action: t("basepack.actions.delete.done"),
      default: :'admin.flash.successful'
    )
  else
    message = ", #{not_destroyed_count}
      #{resource_class.model_name.human(count: not_destroyed_count)}"

    flash[:error] = t("basepack.flash.successful",
      name: destroyed_message,
      action: t("admin.actions.delete.done"),
      default: :'admin.flash.successful'
    )
    flash[:error] << t("basepack.flash.error", name: message,
      action: t("admin.actions.delete.done"),
      default: :'admin.flash.successful'
    )
  end

  redirect_to collection_url
end

#bulk_edit(option = {}, &block) ⇒ Object

Bulk_edit shows form for bulk editing items (edit multiple items at one) Forms look like normal edit form, but for the fields where you can set several values (has_and_belongs_to_many, has_many with through, tags, etc.) the form shows possibilites for add/delete items as well. The particular fields partials are defined in app/views/forms/bulk_edit basepack directiry.

You can configure a field input by defining bulk_edit_partion in the field’s configuration.

If the form’s field is blank, then the attribute in the model is not changed because of that the validation on presence is excluded.

I dont know how to check if the form is valid, so I allways proseed updated and redirect to the index action (and show proper notice/error on the screen).

The defaut action for extend fields should be configured by bulk_edit accessors in the model. For example:

def bulk_edit
  @bulk_edit ||= OpenStruct.new
  @ddbulk_edit.my_habtml_relation_ids = 'delete'
  @bulk_edit
end

# following method should be useful only for rendering the form again
# currently there is no such workflow.
def bulk_edit=(fields)
  @bulk_edit = OpenStruct.new(fields)
end

For customizing particular behaviour for field action on the model you
can define methods with naming "bulk_edit_<field_name>=", as
demonstrates following example:

def bulk_edit_tag_list=(action, new_value)
  value_arr = new_value.to_s.split(/,/)
  case action
  when 'add'
    self.tag_list += value_arr
  when 'assign'
    self.tag_list = new_value
  when 'delete'
    self.tag_list -= value_arr
  else
    raise ArgumentError, "Unknow bulk action: #{action.inspect}"
  end
end

TODO:

  • the URL contains filter params, which could overflow the GET length limit

  • filter like f=… don’t work



337
338
339
# File 'app/controllers/basepack/base_controller.rb', line 337

def bulk_edit(option = {}, &block)
  # empty, all is done by 'custom_actions'
end

#bulk_edit_form_for(resource_or_chain, options = {}) ⇒ Object



523
524
525
# File 'app/controllers/basepack/base_controller.rb', line 523

def bulk_edit_form_for(resource_or_chain, options = {})
  form_factory_rails_admin(:bulk_edit, Basepack::Forms::BulkEdit, resource_or_chain, options)
end

#bulk_update(options = {}, &block) ⇒ Object Also known as: bulk_update!



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'app/controllers/basepack/base_controller.rb', line 341

def bulk_update(options = {}, &block)
  bulk_params = resource_build_bulk_params
  bulk_values = build_resource_params.first.slice(*bulk_params.keys)
  update_params = build_resource_params.first.except(*bulk_params.keys).reject { |k,v| v.blank? }

  res = collection_without_pagination.accessible_by(current_ability, :update).reject do |object|
    update_bulk_params(object, update_params, bulk_params, bulk_values)
  end

  if res.empty?
    flash[:notice] ||= message_bulk_edit_done
    redirect_to polymorphic_path(chain_with_class, query_params)
  else
    flash[:error] ||= message_bulk_edit_fail
    filter_params = { "f[#{resource_class.primary_key}_in]" => res.map(&:id) }.reverse_merge(query_params)
    redirect_to polymorphic_path(chain_with_class, filter_params)
  end
end

#create(options = {}, &block) ⇒ Object Also known as: create!



124
125
126
# File 'app/controllers/basepack/base_controller.rb', line 124

def create(options={}, &block)
  super(options.reverse_merge(notice: message_new_done), &block)
end

#default_queryObject

Used to set default query (default fiter) It is called by before_filter. To define default custom filter redefine method default_query_params



65
66
67
68
# File 'app/controllers/basepack/base_controller.rb', line 65

def default_query
  return if default_query_params.nil? or default_query_params.empty?
  redirect_to query_resources_path(default_query_params) unless params[:f] or params[:ql]
end

#default_query_paramsObject

returns the hash of default query params redefine in sub-classes to customize the default filter



72
73
74
# File 'app/controllers/basepack/base_controller.rb', line 72

def default_query_params
  nil
end

#destroy(options = {}, &block) ⇒ Object Also known as: destroy!



130
131
132
# File 'app/controllers/basepack/base_controller.rb', line 130

def destroy(options={}, &block)
  super(options.reverse_merge(notice: message_destroy_done), &block)
end

#diffObject Also known as: diff!

GET

/resources/:id/diff/:id2



213
214
215
216
# File 'app/controllers/basepack/base_controller.rb', line 213

def diff
  @resource2 = resource2
  respond_with(chain)
end

#diff_form_for(resource, resource2, options = {}) ⇒ Object

resource or chain



514
515
516
517
# File 'app/controllers/basepack/base_controller.rb', line 514

def diff_form_for(resource, resource2, options = {}) # resource or chain
  options[:method] = :post
  Basepack::Forms::Factories::RailsAdmin.new(:edit, view_context, Basepack::Forms::Diff, Basepack::Forms::Groups::Diff).new_form(resource, resource2, options)
end

#edit_form_for(resource_or_chain, options = {}) ⇒ Object



508
509
510
511
512
# File 'app/controllers/basepack/base_controller.rb', line 508

def edit_form_for(resource_or_chain, options = {})
  res = Array.wrap(resource_or_chain).last
  section = (res.is_a?(Class) or res.new_record?) ? :create : :update
  form_factory_rails_admin(section, Basepack::Forms::Edit, resource_or_chain, options)
end

#exportObject Also known as: export!

GET,POST

/resources/export



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'app/controllers/basepack/base_controller.rb', line 177

def export
  export_model_name = Basepack::Settings.export_template.model_name
  export_model_class = export_model_name.constantize

  if export_model_name.present? and params[:export_template_name].present?
    @schema = params[:schema]
    export = export_model_class.new(
      name:         params[:export_template_name],
      class_type:  resource_class.to_s,
      active: true,
      schema_template: @schema
    )

    export.assign_attributes(current_ability.attributes_for(:create, export_model_class))
    if export.save
      flash.now[:notice] = message_new_done(Basepack::Utils.model_config(export_model_class).label)
    else
      flash.now[:error] = I18n.t('basepack.export.export_template_error')
    end

    render and return
  end

  @schema = export_model_class.find_by(id: params[:export_template_id]).try(:schema_template) || []

  if format = params[:json] && :json || params[:csv] && :csv || params[:xml] && :xml
    request.format = format
    index
  else
    render
  end
end

#export_form_for(query_form) ⇒ Object



519
520
521
# File 'app/controllers/basepack/base_controller.rb', line 519

def export_form_for(query_form)
  form_factory_rails_admin(:export, Basepack::Forms::Export, query_form.chain_with_class, query_form: query_form)
end

#export_templatesObject



532
533
534
535
# File 'app/controllers/basepack/base_controller.rb', line 532

def export_templates
  collection #just for authorize resource
  redirect_to polymorphic_path(Basepack::Settings.export_template.model_name.constantize, 'f[class_type_eq]' => resource_class)
end

#filtersObject



527
528
529
530
# File 'app/controllers/basepack/base_controller.rb', line 527

def filters
  collection #just for authorize resource
  redirect_to polymorphic_path(Basepack::Settings.filters.model_name.constantize, 'f[filter_type_eq]' => resource_class)
end

#index(options = {}, &block) ⇒ Object Also known as: index!



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'app/controllers/basepack/base_controller.rb', line 77

def index(options={}, &block)
  block ||= proc do |format|
    format.html do
      render :index # index is also called from query action
    end

    format.json do
      schema = export_form.schema_from_params(params[:schema])
      send_export_data(header: '[', footer: ']') do |object, i|
        "#{',' if i > 0}#{object.to_json(schema)}"
      end
    end

    format.xml do
      schema = {skip_instruct: true}.reverse_merge(export_form.schema_from_params(params[:schema]))
      send_export_data(
        header: %Q{<?xml version="1.0" encoding="UTF-8"?>\n<#{resource_class.model_name.plural} type="array">\n},
        footer: %Q{</#{resource_class.model_name.plural}>}
      ) do |object, i|
        object.to_xml(schema)
      end
    end

    format.csv do
      form = export_form
      fields = form.fields_from_params(params[:schema])
      csv_options = params[:csv_options] || {}
      options = {encoding: 'UTF-8', col_sep: csv_options[:col_sep].presence || Basepack::Settings.export.default_col_sep}
      encoding_to = csv_options[:encoding_to].presence || Basepack::Settings.export.default_encoding_to
      header = csv_options[:skip_header] == 'true' ? '' : CSV.generate_line(form.csv_header(fields), options).encode(encoding_to)

      send_export_data(header: header) do |object, i|
        CSV.generate_line(form.csv_row_for_resource(object, fields), options).encode(encoding_to, invalid: :replace, undef: :replace)
      end
    end
  end
  super(options, &block)
end

#list_form_for(query_form, section = default_list_section) ⇒ Object



464
465
466
# File 'app/controllers/basepack/base_controller.rb', line 464

def list_form_for(query_form, section = default_list_section)
  form_factory_rails_admin(section, Basepack::Forms::List, query_form.chain_with_class, query_form: query_form)
end

#load_tree_nodes(options = {}, &block) ⇒ Object

POST, GET

/collection/load_tree_nodes/:parent_id

Loads part of nested tree based on parent node and expanded nodes POST method is used for big data (expanded param) used by List form with TreeList section

  • parent_id - root of the subtree

by default, only this level of tree is returned

  • expanded - string of ids separated with ‘~’. Example - “3~6~42”

If expanded is provided, returns more levels of tree depending on expanded nodes



440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'app/controllers/basepack/base_controller.rb', line 440

def load_tree_nodes(options = {}, &block)
  if params[:parent_id]
    #parent = end_of_association_chain.accessible_by(current_ability, action_name).find(params[:parent_id])
    children_ids = resource_class.find(params[:parent_id]).child_ids
    collection = collection_without_pagination.where(id: children_ids)
  else
    collection = collection_without_pagination.where(ancestry: nil)
  end

  expanded = params[:expanded].to_s.split('~').map{|s| s.to_i}

  form = list_form_for(query_form)
  form.view = view_context
  nodes = view_context.nested_tree_nodes(form, expanded, collection)

  block ||= proc do |format|
    format.json do
      render json: nodes
    end
  end

  respond_with(*with_chain(collection), options, &block)
end

#merge(options = {}, &block) ⇒ Object Also known as: merge!

POST

/resources/:id/diff/:id2



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'app/controllers/basepack/base_controller.rb', line 221

def merge(options = {}, &block)
  authorize!(:update, resource) # CanCan

  @resource = resource
  @resource2 = resource2
  merge = params[:merge]

  merge.each do |key, val|
    if val == "right"
      resource[key] = @resource2[key]
    end
  end

  resource.save
  options[:notice] ||= message_edit_done

  respond_with(*with_chain(resource), options, &block)
end

#options(options = {}) ⇒ Object Also known as: options!



136
137
138
139
140
141
142
143
144
145
# File 'app/controllers/basepack/base_controller.rb', line 136

def options(options={})
  primary_key = resource_class.primary_key
  response = (options[:collection] || collection).map do |object|
    {
      :id   => object.send(primary_key),
      :text => ERB::Util.html_escape(object.to_details_label),
    }
  end
  render :json => response
end

#queryObject Also known as: query!

GET,POST

/resources/query



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'app/controllers/basepack/base_controller.rb', line 150

def query
  filter_class_name = Basepack::Settings.filters.model_name
  if filter_class_name.present? and params[:filter_name].present?
    filter_class = filter_class_name.constantize
    filter = filter_class.new(
      name:         params[:filter_name],
      filter:       params[:ql] || query_form.conditions_to_ql,
      filter_type:  resource_class.to_s
    )
    filter.assign_attributes(current_ability.attributes_for(:create, filter_class))
    if filter.save
      flash.now[:notice] = message_new_done(Basepack::Utils.model_config(filter_class).label)
    else
      flash.now[:error] = I18n.t('basepack.query.error_filter')
    end
  end

  if request.xhr?
    render partial: "query"
  else
    index
  end
end

#query_form_for(class_or_chain, scope, options = {}) ⇒ Object



472
473
474
475
476
477
# File 'app/controllers/basepack/base_controller.rb', line 472

def query_form_for(class_or_chain, scope, options = {})
  Basepack::Forms::Factories::QueryRailsAdmin.new(view_context).new_form(
    class_or_chain,
    { scope: scope }.reverse_merge!(options.reverse_merge(params: params, auth_object: current_ability))
  )
end

#show_form_for(resource_or_chain) ⇒ Object



468
469
470
# File 'app/controllers/basepack/base_controller.rb', line 468

def show_form_for(resource_or_chain)
  form_factory_rails_admin(:show, Basepack::Forms::Show, resource_or_chain)
end

#taggings(options = {}) ⇒ Object Also known as: taggings!



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
# File 'app/controllers/basepack/base_controller.rb', line 479

def taggings(options={})
  authorize!(action_name.to_sym, resource_class)
  query_params = params.clone

  #for inital data on selectbox change searching from id_tq to name_id
  if (t = query_params['f']) and (t = t.delete 'id_eq')
    query_params['f']['name_in'] = t.map! { |value| value.strip }
  end
  #add filter to search only on proper type
  query_params['f'] ||= {}
  query_params['f']['taggings_taggable_type_eq'] = resource_class.to_s

  query_form = query_form_for(
    ActsAsTaggableOn::Tag,
    ActsAsTaggableOn::Tag.all.accessible_by(current_ability),
    params: query_params
  )

  response = query_form.collection.map do |object|
    {
      :id => ERB::Util.html_escape(object.name),
      :text => ERB::Util.html_escape(object.name),
    }
  end
  render :json => response
end

#update(options = {}, &block) ⇒ Object Also known as: update!



118
119
120
# File 'app/controllers/basepack/base_controller.rb', line 118

def update(options={}, &block)
  super(options.reverse_merge(notice: message_edit_done), &block)
end

#update_tree(options = {}, &block) ⇒ Object Also known as: update_tree!

POST

/resource/:id/:parent_id

Updates nodes parent and position

  • parent_id - New parent of actual node

Sorting

Sorting is used if Node respons to position method Updates nested tree after drag & drop action.

  • method - FancyTree drag & drop method [‘over’, ‘before’, ‘after’]

  • id2 - Node id provided by fancytree depending on method



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'app/controllers/basepack/base_controller.rb', line 369

def update_tree(options = {}, &block)
  authorize!(action_name.to_sym, resource_class)

  parent_id = params[:parent_id]
  # check that parent shoud by node which is visible for the user.
  authorize!(:list, params[:parent_id])
  err_exit = proc { |r|
    render json: {
      success: false,
      msg: t('basepack.tree_list.update_tree.error', name: r.to_label,
        msg: r.errors.full_messages.join(',')).to_json
    }
    return #it is Proc, note we are exiting form the whole method.
  }

  resource_class.transaction do

    # parent id can be changed using every d & d method
    resource.parent_id = parent_id
    err_exit.call(resource) unless resource.save

    # if +position+ attribute exists, it is orderable tree
    # and position of the tree has to be set
    if resource.respond_to?(:position)

      method = params[:method]

      if method == "over" # new node in subtree, set position to last
        pos = resource.siblings.order('position').last.position.to_i + 1
        resource.position = pos
        err_exit.call(resource) unless resource.save
      end

      # move before/after resource2
      # if moving before, position of resource2 has to be updated too
      position_cond = resource2.position
      position_cond += 1 if method == "after"

      nodes = resource2.siblings.where('position >= ?', position_cond)


      nodes.each do |n|
        authorize!(:update, n)

        n.position += 1

        err_exit.call(n) unless n.save
      end

      resource.position = position_cond

      err_exit.call(resource) unless resource.save

    end # end sorting
  end # end transaction

  render json: { success: true }
end