ab_admin 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +27 -12
  3. data/app/assets/javascripts/ab_admin/components/select2_bridge.js.coffee +39 -20
  4. data/app/assets/javascripts/ab_admin/core/columns_hider.js.coffee +4 -5
  5. data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +3 -3
  6. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.css.scss +5 -1
  7. data/app/assets/stylesheets/ab_admin/components/_columns_hider.css.scss +1 -1
  8. data/app/assets/stylesheets/ab_admin/components/_form.css.scss +1 -1
  9. data/app/controllers/admin/assets_controller.rb +4 -1
  10. data/app/controllers/admin/base_controller.rb +28 -10
  11. data/app/controllers/admin/locators_controller.rb +1 -1
  12. data/app/controllers/admin/manager_controller.rb +7 -2
  13. data/app/controllers/admin/static_pages_controller.rb +4 -5
  14. data/app/controllers/admin/structures_controller.rb +1 -1
  15. data/app/views/admin/base/create.js.erb +1 -1
  16. data/app/views/admin/base/edit.js.erb +16 -10
  17. data/app/views/admin/base/index.html.slim +2 -2
  18. data/app/views/admin/base/show.js.erb +2 -2
  19. data/app/views/admin/base/update.js.erb +12 -8
  20. data/app/views/admin/manager/_form.html.slim +4 -1
  21. data/app/views/admin/manager/_table.html.slim +2 -2
  22. data/app/views/admin/shared/_flash.html.slim +1 -1
  23. data/app/views/admin/structures/_form.html.slim +1 -1
  24. data/app/views/admin/users/_table.html.slim +1 -1
  25. data/config/locales/de.yml +18 -36
  26. data/config/locales/en.yml +20 -36
  27. data/config/locales/it.yml +12 -30
  28. data/config/locales/ru.yml +4 -17
  29. data/config/locales/uk.yml +301 -0
  30. data/lib/ab_admin.rb +1 -2
  31. data/lib/ab_admin/concerns/admin_addition.rb +1 -1
  32. data/lib/ab_admin/concerns/asset_human_names.rb +9 -1
  33. data/lib/ab_admin/concerns/utilities.rb +2 -6
  34. data/lib/ab_admin/controllers/tree.rb +2 -2
  35. data/lib/ab_admin/core_ext/array.rb +6 -5
  36. data/lib/ab_admin/hooks.rb +7 -32
  37. data/lib/ab_admin/hooks/{active_model_hooks.rb → active_model_attr_accessible_few_roles.rb} +12 -4
  38. data/lib/ab_admin/hooks/{globalize_hooks.rb → globalize_locale_suffix_accessors.rb} +1 -9
  39. data/lib/ab_admin/hooks/globalize_valid_locale.rb +9 -0
  40. data/lib/ab_admin/hooks/{paginate_hooks.rb → will_paginate_id_prefetch.rb} +7 -22
  41. data/lib/ab_admin/hooks/will_paginate_no_uri.rb +19 -0
  42. data/lib/ab_admin/i18n_tools/model_translator.rb +3 -2
  43. data/lib/ab_admin/menu/base_group.rb +3 -3
  44. data/lib/ab_admin/menu/item.rb +15 -4
  45. data/lib/ab_admin/models/asset.rb +6 -0
  46. data/lib/ab_admin/models/settings.rb +6 -6
  47. data/lib/ab_admin/models/user.rb +4 -0
  48. data/lib/ab_admin/utils.rb +16 -7
  49. data/lib/ab_admin/utils/xls_document.rb +9 -1
  50. data/lib/ab_admin/version.rb +1 -1
  51. data/lib/ab_admin/views/admin_helpers.rb +15 -11
  52. data/lib/ab_admin/views/admin_navigation_helpers.rb +11 -6
  53. data/lib/ab_admin/views/form_builder.rb +5 -1
  54. data/lib/ab_admin/views/search_form_builder.rb +1 -1
  55. data/lib/generators/ab_admin/glob/glob_generator.rb +6 -3
  56. data/lib/generators/ab_admin/install/install_generator.rb +1 -1
  57. data/lib/generators/ab_admin/install/templates/config/{unicorn_config.rb → unicorn/production.rb} +6 -9
  58. data/lib/generators/ab_admin/install/templates/script/unicorn.sh +7 -6
  59. data/lib/generators/template.rb +0 -1
  60. data/lib/tasks/assets.rake +7 -1
  61. metadata +34 -61
  62. data/app/assets/stylesheets/ab_admin/components/_text_styles.css.scss +0 -47
  63. data/lib/ab_admin/views/inputs/capture_block_input.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ce9c95c69fe8e4cb07758d71225cfb377274ced
4
- data.tar.gz: b7f96a49bccb158542018212f2098a4ab69d36b6
3
+ metadata.gz: 950054e682380c39155c5f4f1fb1727242ffe375
4
+ data.tar.gz: 399c85e16c87b277a2f360eaeb4fb1dae08e2c8e
5
5
  SHA512:
6
- metadata.gz: 19d5aa9eb7421200d0c64c1300c96d094a7345f1270e87adca60b7750254c5429ca9071a85a6a3c7334f0d0dc38d5fe52eccda6de3163813e71c9efc0d377385
7
- data.tar.gz: 81dc3ac75c26b89e13626bc46cf072db406e98da0d524aa3b0add79f42169ed899b7ce48767fd4f1c09e96b8539b37e6bd9793098dca5fce21d37f64a3a26c82
6
+ metadata.gz: 5d98d2191b2c4b2178f22766d32f248101408f6ed6ee515aa0d5bcd8ae0700a28a9934fe36bc1d9c779459b1084cd137f6e7bb8fdd8106e7e44f09acd0a78e2f
7
+ data.tar.gz: 95545153ff5019b13e296e08287d50d6a6d1d55c886ac33edab38c385daa7f3c336b8035b63c45388670af508dc42e5dc9cb036e17b047809d328acca00ca432
@@ -1,18 +1,22 @@
1
1
  EditableForm = $.fn.editableform.Constructor
2
2
  EditableForm.prototype.saveWithUrlHook = (value) ->
3
- url = @options.url
3
+ originalUrl = @options.url
4
4
  @options.url = (params) =>
5
- params[@options.model] ||= {}
6
- params[@options.model][params.name] = value
7
- ajax_opts =
8
- url: url
9
- data: params
10
- type: 'PATCH'
11
- dataType: 'json'
12
- delete params.name
13
- delete params.value
14
- delete params.pk
15
- $.ajax $.extend(ajax_opts, @options.ajaxOptions)
5
+ if typeof originalUrl == 'function'
6
+ originalUrl.call(@options.scope, params)
7
+ else
8
+ params[@options.model] ||= {}
9
+ params[@options.model][params.name] = params.value
10
+ params._method = 'PATCH'
11
+ ajax_opts =
12
+ url: originalUrl
13
+ data: params
14
+ type: 'POST'
15
+ dataType: 'json'
16
+ delete params.name
17
+ delete params.value
18
+ delete params.pk
19
+ $.ajax $.extend(ajax_opts, @options.ajaxOptions)
16
20
  @saveWithoutUrlHook(value)
17
21
  EditableForm.prototype.saveWithoutUrlHook = EditableForm.prototype.save
18
22
  EditableForm.prototype.save = EditableForm.prototype.saveWithUrlHook
@@ -22,8 +26,19 @@ $(document).on 'admin:init', (e) ->
22
26
  onblur: 'submit'
23
27
  placement: 'bottom'
24
28
  emptytext: I18n.lookup('admin.js.empty') || 'Empty'
29
+ error: (response, newValue) ->
30
+ log response
31
+ if response.status == 422
32
+ flash JSON.parse(response.responseText).errors.join(', ')
33
+ else
34
+ response.responseText
25
35
  datetimepicker:
26
36
  format: "dd.mm.yyyy hh:ii"
27
37
  autoclose: true
28
38
  todayBtn: true
29
39
  language: I18n.locale
40
+ ajaxOptions:
41
+ xhrFields:
42
+ withCredentials: true
43
+ headers:
44
+ Accept: 'application/json'
@@ -8,8 +8,15 @@ class window.Select2Bridge
8
8
  @initSortable() if @el.data('sortable')
9
9
 
10
10
  initHandlers: ->
11
- @el.select2('container').on 'click', '.select2-choices a', (e) ->
11
+ @el.select2('container').on 'click', '.select2-choices a', (e) =>
12
12
  e.stopPropagation()
13
+ $el = $(e.currentTarget)
14
+ if $el.data('remote')
15
+ e.preventDefault()
16
+ @modal.data('target', this)
17
+ fn = =>
18
+ @runModal()
19
+ $.get $el.attr('href'), {modal: true}, fn, 'script'
13
20
 
14
21
  buildOptions: ->
15
22
  @options = _.defaults(@el.data('select2_opts') || {}, @defaults())
@@ -18,15 +25,27 @@ class window.Select2Bridge
18
25
  if @el.data('tags')
19
26
  @options.tokenSeparators = [',']
20
27
  @options.tags = @el.data('tags')
28
+ if @el.data('data')
29
+ data = @el.data('data')
30
+ data = _.map(data, (el) -> {id: el, text: el.toString()} ) if data[0] && !_.isObject(data[0])
31
+ @options.data = data
21
32
  else if @el.data('collection')
22
33
  @options.data = @el.data('collection')
23
34
  else if @el.data('class')
24
35
  @initAjaxInput()
25
36
  if @el.data('add')
26
- @initCreateChoiseOnce()
27
- @initCreateChoise()
37
+ @initCreateChoiceOnce()
38
+ @initCreateChoice()
39
+ if @el.data('create-search-choice')
40
+ @options.createSearchChoice = (term) ->
41
+ log 'createSearchChoice'
42
+ {id: term, text: term}
28
43
  @options
29
44
 
45
+ runModal: ->
46
+ @el.trigger('select2.modal_open')
47
+ @modal.modal()
48
+
30
49
  initSortable: ->
31
50
  @el.select2('container').find('ul.select2-choices').sortable
32
51
  containment: 'parent'
@@ -35,43 +54,43 @@ class window.Select2Bridge
35
54
  update: =>
36
55
  @el.select2 'onSortEnd'
37
56
 
38
- initCreateChoise: ->
57
+ initCreateChoice: ->
39
58
  @options.createSearchChoice = (term, data) =>
40
- @clearCreateChoise()
59
+ @clearCreateChoice()
41
60
  @cont = @el.select2('container')
42
- @btn_add = $("<div class='btn btn-info btn-mini select2-create-choise'>#{I18n.t('admin.js.add')} - #{term}</div>")
61
+ @btn_add = $("<div class='btn btn-info btn-mini select2-create-choice'>#{I18n.t('admin.js.add')} - #{term}</div>")
43
62
  @btn_add.prependTo @cont
44
63
  @btn_add.click =>
45
64
  @modal.data('target', this)
46
65
  fn = =>
47
66
  $('#modal_form form input[name$="[name]"]').val(term)
48
- @modal.modal()
67
+ @runModal()
49
68
  $.get @el.data('add'), {modal: true}, fn, 'script'
50
69
  null
51
70
 
52
- initCreateChoiseOnce: ->
53
- return if Select2Bridge.initedCreateChoiseOnce
71
+ initCreateChoiceOnce: ->
72
+ return if Select2Bridge.initedCreateChoiceOnce
54
73
  @modal.on 'ajax:success', 'form', =>
55
74
  @modal.modal('hide')
56
75
  that = @modal.data('target')
57
- new_item = window.ab_admin_last_created
58
- that.addItem(new_item)
59
- that.clearCreateChoise()
76
+ item = window.ab_admin_last_created || window.ab_admin_last_updated
77
+ that.addItem(item)
78
+ that.clearCreateChoice()
60
79
  @el.data("select2-change-triggered", true)
61
- @el.trigger('change', [new_item])
80
+ @el.trigger('change', [item])
62
81
  @el.data("select2-change-triggered", false)
63
- Select2Bridge.initedCreateChoiseOnce = true
82
+ Select2Bridge.initedCreateChoiceOnce = true
64
83
 
65
84
  addItem: (item) ->
66
85
  if @el.data('select2').opts.multiple
67
- data = @el.select2('data')
86
+ data = _.reject(@el.select2('data'), (i) -> i.id == item.id)
68
87
  data.push item
69
88
  @el.select2('data', data)
70
89
  else
71
90
  @el.select2('data', item)
72
91
 
73
- clearCreateChoise: ->
74
- @el.select2('container').children('.select2-create-choise').remove()
92
+ clearCreateChoice: ->
93
+ @el.select2('container').children('.select2-create-choice').remove()
75
94
 
76
95
  defaults: ->
77
96
  opts =
@@ -80,12 +99,12 @@ class window.Select2Bridge
80
99
  placeholder: ' '
81
100
  allowClear: true
82
101
  escapeMarkup: (m) -> m
83
- opts.minimumResultsForSearch = 10 unless fv.test || @el.data('add')
102
+ opts.minimumResultsForSearch = 10 unless fv.test || @el.data('add') || @el.data('create-search-choice')
84
103
  opts
85
104
 
86
105
  initAjaxInput: ->
87
106
  if @el.data('image')
88
- @buildimageOptions()
107
+ @buildImageOptions()
89
108
  if @el.data('result')
90
109
  @options.formatResult = (item) => fetchTemplate(@el.data('result'))(item)
91
110
  if @el.data('selection')
@@ -105,7 +124,7 @@ class window.Select2Bridge
105
124
  results: data
106
125
  more: data.length > 0
107
126
 
108
- buildimageOptions: ->
127
+ buildImageOptions: ->
109
128
  @options.formatResult = (item) ->
110
129
  html = '<div class="fancy_select-result">'
111
130
  html += "<img src='#{item.image}' alt='#{item.text}'>" if item.image
@@ -3,7 +3,8 @@ class window.ColumnsHider
3
3
  @store_key = 'cols'
4
4
  @data_el = $('#columns_hider_data')
5
5
  @column_names = @columnNames()
6
- @collection_name = $('html').attr('id').replace(/^controller_/, '')
6
+ @collection_name = window.location.href.match(/admin\/(\w+)/)?[1]
7
+ return unless @collection_name
7
8
  @data = @getData()
8
9
  @initDefaults()
9
10
  @initButtons()
@@ -32,9 +33,6 @@ class window.ColumnsHider
32
33
  data[@collection_name].push(i) if col.disabled
33
34
  data
34
35
 
35
- fetchData: ->
36
- window.localStorage?[@store_key] or $.cookie(@store_key)
37
-
38
36
  initButtons: ->
39
37
  @data_el.empty()
40
38
  for col, i in @column_names
@@ -62,6 +60,7 @@ class window.ColumnsHider
62
60
  @showAll()
63
61
  for i in @data[@collection_name]
64
62
  @hideByIndex(i + 1)
63
+ $(document).trigger('admin:refresh_columns')
65
64
 
66
65
  hideByIndex: (i) ->
67
66
  $("#list > thead > tr > th:nth-child(#{i}), #list > tbody > tr > td:nth-child(#{i})").hide()
@@ -70,4 +69,4 @@ class window.ColumnsHider
70
69
  $("#list > thead > tr > th, #list > tbody > tr > td").show()
71
70
 
72
71
  $ ->
73
- window.columns_hider = new ColumnsHider()
72
+ window.columns_hider = new ColumnsHider()
@@ -6,10 +6,10 @@ $ ->
6
6
  todayBtn: true
7
7
  language: I18n.locale
8
8
 
9
- search_options = _.defaults({pickerPosition: "bottom-left datetimepicker-bottom-left-custom"}, base_options)
10
- $('#search_form input.datepicker').datetimepicker search_options
9
+ search_form_options = _.defaults({pickerPosition: "bottom-left datetimepicker-bottom-left-custom"}, base_options)
10
+ $('#search_form input.datepicker').datetimepicker search_form_options
11
11
 
12
- date_picker_options = _.defaults({format: "dd.mm.yyyy"}, base_options)
12
+ date_picker_options = _.defaults({format: "dd.mm.yyyy", minView: 2}, base_options)
13
13
  $('.simple_form input.date_picker').datetimepicker date_picker_options
14
14
 
15
15
  $('.simple_form input.datetime_picker').datetimepicker base_options
@@ -16,7 +16,6 @@ $baseLineHeight: 18px !default;
16
16
  @import "ab_admin/components/perms";
17
17
  @import "ab_admin/components/admin_comments";
18
18
  @import "ab_admin/components/geo_input";
19
- @import "ab_admin/components/text_styles";
20
19
  @import "ab_admin/components/view_layout";
21
20
  @import "ab_admin/components/columns_hider";
22
21
 
@@ -24,6 +23,10 @@ img {
24
23
  max-width: none;
25
24
  }
26
25
 
26
+ .thumbnail.active {
27
+ @extend a.thumbnail:hover
28
+ }
29
+
27
30
  .pagination a {
28
31
  background-color: white;
29
32
  }
@@ -106,6 +109,7 @@ ul.nav li.dropdown:hover ul.dropdown-menu {
106
109
  margin-bottom: 5px;
107
110
  .nav > li > a {
108
111
  color: #f5f5f5;
112
+ display: inline-block;
109
113
  }
110
114
  .nav .active > a, .nav .active > a:hover {
111
115
  color: #f5f5f5;
@@ -1,5 +1,5 @@
1
1
  #columns_hider {
2
- .btn-group.btn {
2
+ .btn-group .btn {
3
3
  float: left;
4
4
  }
5
5
  }
@@ -131,7 +131,7 @@ textarea {
131
131
  max-height: 500px;
132
132
  }
133
133
 
134
- .select2-create-choise {
134
+ .select2-create-choice {
135
135
  margin-left: 10px;
136
136
  }
137
137
 
@@ -61,7 +61,10 @@ class Admin::AssetsController < ApplicationController
61
61
  end
62
62
 
63
63
  def prepared_data
64
- params[:data].original_filename = "blob.#{params[:data].content_type.split('/').last}" if params[:data].original_filename == 'blob'
64
+ if %w(blob undefined).include? params[:data].original_filename
65
+ extension = params[:data].content_type.split('/').last
66
+ params[:data].original_filename = "original.#{extension}"
67
+ end
65
68
  params[:data]
66
69
  end
67
70
 
@@ -57,7 +57,7 @@ class Admin::BaseController < ::InheritedResources::Base
57
57
  failure.html { render :edit }
58
58
  success.js { render layout: false }
59
59
  failure.js { render :edit, layout: false }
60
- unless Admin::ManagerController.mimes_for_respond_to[:json]
60
+ unless respond_to_format?(:json)
61
61
  success.json { head :no_content }
62
62
  failure.json { head :unprocessable }
63
63
  end
@@ -104,6 +104,10 @@ class Admin::BaseController < ::InheritedResources::Base
104
104
 
105
105
  protected
106
106
 
107
+ def respond_to_format?(format)
108
+ self.class.mimes_for_respond_to[format]
109
+ end
110
+
107
111
  def default_url_options
108
112
  options = {format: nil}
109
113
  options.update instance_exec(&AbAdmin.default_url_options) if AbAdmin.default_url_options
@@ -147,10 +151,14 @@ class Admin::BaseController < ::InheritedResources::Base
147
151
  base.class_eval do
148
152
  before_create :bind_current_user
149
153
  before_save :bind_current_updater
150
- before_save { track_action if settings[:history] }
154
+ before_save :track_current_action
151
155
  end
152
156
  end
153
157
 
158
+ def track_current_action(*)
159
+ track_action if settings[:history]
160
+ end
161
+
154
162
  def interpolation_options
155
163
  return {} if collection_action? || resource.errors.empty?
156
164
  {errors: resource.errors.full_messages.map { |m| "<br/> - #{m}" }.join.html_safe}
@@ -197,7 +205,7 @@ class Admin::BaseController < ::InheritedResources::Base
197
205
  end
198
206
 
199
207
  def button_scopes
200
- self.class.button_scopes ||= self.class.scopes_configuration.except(:ids).find_all{|_, s| s[:type] == :boolean }.to_h
208
+ self.class.button_scopes ||= self.class.scopes_configuration.except(:by_ids).find_all{|_, s| s[:type] == :boolean }.to_h
201
209
  end
202
210
 
203
211
  def add_breadcrumbs
@@ -232,9 +240,9 @@ class Admin::BaseController < ::InheritedResources::Base
232
240
 
233
241
  def search_collection
234
242
  params[:q] ||= {}
235
- params[:q][:s] ||= 'id desc'
243
+ params[:q][:s] ||= settings[:default_order] || 'id desc'
236
244
  @search = end_of_association_chain.accessible_by(current_ability).admin.ransack(params[:q].no_blank)
237
- @search.result(distinct: true)
245
+ @search.result(distinct: @search.object.joins_values.present?)
238
246
  end
239
247
 
240
248
  def collection
@@ -242,11 +250,11 @@ class Admin::BaseController < ::InheritedResources::Base
242
250
  end
243
251
 
244
252
  def per_page
245
- return params[:per_page] if params[:per_page].present?
246
- if current_index_view == 'tree'
247
- params[:per_page] = 1000
253
+ request_per_page = (params[:per_page].presence || cookies[:pp].presence).to_i
254
+ if request_per_page.zero?
255
+ params[:per_page] = current_index_view == 'tree' ? 1000 : 50
248
256
  else
249
- params[:per_page] = cookies[:pp] || 50
257
+ params[:per_page] = request_per_page
250
258
  end
251
259
  end
252
260
 
@@ -281,6 +289,8 @@ class Admin::BaseController < ::InheritedResources::Base
281
289
  new_resource_path(return_to: params[:return_to])
282
290
  elsif params[:_add_edit]
283
291
  edit_resource_path(resource, return_to: params[:return_to])
292
+ elsif params[:_save_and_show]
293
+ resource_path(resource, return_to: params[:return_to])
284
294
  elsif params[:_add_edit_next] || params[:_add_edit_prev]
285
295
  rec = resource.next_prev_by_url(end_of_association_chain.accessible_by(current_ability).unscoped.base, params[:return_to], !!params[:_add_edit_prev])
286
296
  if rec
@@ -302,7 +312,7 @@ class Admin::BaseController < ::InheritedResources::Base
302
312
  fv.env = Rails.env
303
313
  if AbAdmin.test_env?
304
314
  fv.test = true
305
- AbAdmin.test_settings.each { |k, v| fv.set_variable k, v }
315
+ AbAdmin.test_settings.each { |k, v| fv[k] = v }
306
316
  end
307
317
  end
308
318
 
@@ -380,4 +390,12 @@ class Admin::BaseController < ::InheritedResources::Base
380
390
  end
381
391
  end
382
392
 
393
+ def default_serializer_options
394
+ if resource_class
395
+ {root: resource_class.model_name.plural}
396
+ else
397
+ {root: false}
398
+ end
399
+ end
400
+
383
401
  end
@@ -32,7 +32,7 @@ class ::Admin::LocatorsController < ::Admin::BaseController
32
32
 
33
33
  def reload
34
34
  I18n.reload!
35
- Locator.reload_checker.expire
35
+ Locator.reload_checker.expire if Locator.respond_to?(:reload_checker)
36
36
  flash[:notice] = I18n.t('flash.admin.locators.restart')
37
37
  redirect_to admin_locators_path
38
38
  end
@@ -92,13 +92,18 @@ class ::Admin::ManagerController < ::Admin::BaseController
92
92
 
93
93
  def manager
94
94
  @manager ||= begin
95
- manager_instance = "AbAdmin#{resource_class.name}".constantize.instance
95
+ manager_class_name = "AbAdmin#{resource_class.name}"
96
+ manager_instance = manager_class_name.constantize.instance
96
97
  unless manager_instance.allow_action?(action_name)
97
98
  raise ActionController::RoutingError.new("AbAdmin action #{action_name} for #{resource_class.name} not found")
98
99
  end
99
100
  manager_instance
100
101
  rescue NameError => e
101
- raise ActionController::RoutingError.new("AbAdmin manager_model for #{resource_class.name} not found (#{e.message})")
102
+ if e.message.include?(manager_class_name)
103
+ raise ActionController::RoutingError.new("AbAdmin manager_model for #{resource_class.name} not found (#{e.message})")
104
+ else
105
+ raise
106
+ end
102
107
  end
103
108
  end
104
109
 
@@ -1,15 +1,14 @@
1
1
  class Admin::StaticPagesController < Admin::BaseController
2
2
  load_and_authorize_resource
3
3
 
4
- defaults singleton: true
4
+ defaults singleton: true, class_name: 'Structure'
5
5
 
6
- belongs_to :structure
6
+ belongs_to :structure, finder: :friendly_find
7
+
8
+ private
7
9
 
8
10
  def settings
9
11
  {}
10
12
  end
11
13
 
12
- def parent_class
13
- Structure
14
- end
15
14
  end