ab_admin 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +11 -5
  4. data/app/assets/javascripts/ab_admin/components/admin_assets.js.coffee +0 -25
  5. data/app/assets/javascripts/ab_admin/components/google_translate.js.coffee +3 -5
  6. data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +5 -1
  7. data/app/assets/javascripts/ab_admin/core/columns_hider.js.coffee +24 -23
  8. data/app/assets/javascripts/ab_admin/core/init.js.coffee +6 -2
  9. data/app/assets/javascripts/ab_admin/core/search_form.js.coffee +1 -7
  10. data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +2 -6
  11. data/app/assets/javascripts/ab_admin/core/utils.js.coffee +8 -2
  12. data/app/assets/javascripts/ab_admin/main.js +2 -2
  13. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.scss +35 -10
  14. data/app/assets/stylesheets/ab_admin/components/_base.scss +21 -1
  15. data/app/assets/stylesheets/ab_admin/components/_form.scss +13 -17
  16. data/app/assets/stylesheets/ab_admin/components/_grid_view.scss +2 -2
  17. data/app/assets/stylesheets/ab_admin/components/_locale_tabs.scss +11 -23
  18. data/app/assets/stylesheets/ab_admin/components/_navigation.scss +0 -9
  19. data/app/assets/stylesheets/ab_admin/components/_table_view.scss +10 -2
  20. data/app/assets/stylesheets/ab_admin/components/_tooltip.scss +80 -0
  21. data/app/assets/stylesheets/ab_admin/components/_tree_view.scss +1 -1
  22. data/app/assets/stylesheets/ab_admin/devise.scss +2 -2
  23. data/app/assets/stylesheets/ab_admin/fileupload.scss +2 -9
  24. data/app/assets/stylesheets/ab_admin/main.scss +0 -1
  25. data/app/controllers/admin/base_controller.rb +67 -63
  26. data/app/controllers/admin/dashboards_controller.rb +2 -2
  27. data/app/controllers/admin/locators_controller.rb +8 -6
  28. data/app/controllers/admin/manager_controller.rb +2 -2
  29. data/app/controllers/admin/static_pages_controller.rb +0 -4
  30. data/app/controllers/admin/structures_controller.rb +2 -2
  31. data/app/views/admin/assets/batch_edit.html.slim +1 -1
  32. data/app/views/admin/base/_search_layout.html.slim +6 -5
  33. data/app/views/admin/base/create.js.erb +5 -2
  34. data/app/views/admin/base/index.html.slim +4 -4
  35. data/app/views/admin/base/update.js.erb +5 -0
  36. data/app/views/admin/fileupload/_asset_templates.html.slim +1 -2
  37. data/app/views/admin/fileupload/_image.html.slim +1 -2
  38. data/app/views/admin/locators/edit.html.slim +7 -6
  39. data/app/views/admin/manager/_map.html.slim +4 -0
  40. data/app/views/admin/manager/_table.html.slim +1 -1
  41. data/app/views/admin/shared/_content_actions.html.slim +19 -21
  42. data/app/views/admin/shared/_flash.html.slim +5 -4
  43. data/app/views/admin/shared/_locale_tabs.html.slim +2 -2
  44. data/app/views/admin/shared/_main_menu.html.slim +1 -1
  45. data/app/views/admin/structures/_form.html.slim +1 -1
  46. data/app/views/admin/users/_form.html.slim +1 -1
  47. data/app/views/admin/users/_search_form.html.slim +1 -1
  48. data/app/views/layouts/admin/_footer.html.slim +0 -1
  49. data/app/views/layouts/admin/_navigation.html.slim +1 -1
  50. data/app/views/layouts/admin/application.html.slim +2 -2
  51. data/config/locales/de.yml +1 -2
  52. data/config/locales/en.yml +1 -2
  53. data/config/locales/ru.yml +0 -1
  54. data/config/locales/uk.yml +0 -1
  55. data/lib/ab_admin.rb +34 -33
  56. data/lib/ab_admin/abstract_resource.rb +1 -1
  57. data/lib/ab_admin/carrierwave/base_uploader.rb +1 -2
  58. data/lib/ab_admin/concerns/admin_addition.rb +0 -30
  59. data/lib/ab_admin/concerns/translations_macro.rb +97 -0
  60. data/lib/ab_admin/concerns/utilities.rb +1 -1
  61. data/lib/ab_admin/config/base.rb +7 -0
  62. data/lib/ab_admin/controllers/callbacks.rb +3 -26
  63. data/lib/ab_admin/core_ext/array.rb +4 -48
  64. data/lib/ab_admin/core_ext/hash.rb +2 -31
  65. data/lib/ab_admin/core_ext/other.rb +0 -6
  66. data/lib/ab_admin/core_ext/string.rb +0 -80
  67. data/lib/ab_admin/engine.rb +1 -0
  68. data/lib/ab_admin/hooks/will_paginate_id_prefetch.rb +8 -6
  69. data/lib/ab_admin/hooks/will_paginate_no_uri.rb +1 -1
  70. data/lib/ab_admin/i18n_tools/google_translate.rb +3 -1
  71. data/lib/ab_admin/i18n_tools/model_translator.rb +1 -1
  72. data/lib/ab_admin/models/header.rb +2 -2
  73. data/lib/ab_admin/models/locator.rb +28 -2
  74. data/lib/ab_admin/models/user.rb +12 -48
  75. data/lib/ab_admin/utils/csv_document.rb +5 -3
  76. data/lib/ab_admin/utils/eval_helpers.rb +6 -3
  77. data/lib/ab_admin/utils/xls_document.rb +18 -16
  78. data/lib/ab_admin/version.rb +1 -1
  79. data/lib/ab_admin/views/admin_helpers.rb +10 -12
  80. data/lib/ab_admin/views/admin_navigation_helpers.rb +7 -8
  81. data/lib/ab_admin/views/form_builder.rb +7 -5
  82. data/lib/ab_admin/views/helpers.rb +0 -9
  83. data/lib/ab_admin/views/inputs/ckeditor_input.rb +4 -4
  84. data/lib/ab_admin/views/manager_helpers.rb +8 -5
  85. data/lib/ab_admin/views/search_form_builder.rb +2 -2
  86. data/lib/ab_admin/views/will_paginate_bootstrap_renderer.rb +60 -0
  87. data/lib/generators/ab_admin/glob/glob_generator.rb +4 -5
  88. data/lib/generators/ab_admin/glob/templates/migration.erb +10 -7
  89. data/lib/generators/ab_admin/install/templates/config/ab_admin.rb.erb +1 -1
  90. data/lib/generators/ab_admin/install/templates/models/user.rb +0 -11
  91. data/lib/generators/ab_admin/install/templates/spec/spec_helper.rb +0 -1
  92. data/lib/generators/ab_admin/install/templates/spec/support/database_cleaner.rb +8 -11
  93. data/lib/generators/ab_admin/model/model_generator.rb +3 -4
  94. data/lib/generators/ab_admin/model/templates/resource.erb +5 -2
  95. data/lib/generators/ab_admin/resource/templates/controller.erb +2 -2
  96. metadata +37 -79
  97. data/app/assets/images/admin/Jcrop.gif +0 -0
  98. data/app/assets/images/admin/flags/de.png +0 -0
  99. data/app/assets/images/admin/flags/en.png +0 -0
  100. data/app/assets/images/admin/flags/es.png +0 -0
  101. data/app/assets/images/admin/flags/fr.png +0 -0
  102. data/app/assets/images/admin/flags/it.png +0 -0
  103. data/app/assets/images/admin/flags/ja.png +0 -0
  104. data/app/assets/images/admin/flags/pl.png +0 -0
  105. data/app/assets/images/admin/flags/ru.png +0 -0
  106. data/app/assets/images/admin/flags/uk.png +0 -0
  107. data/app/assets/javascripts/ab_admin/components/croppable_image.js.coffee +0 -33
  108. data/app/assets/stylesheets/ab_admin/components/_columns_hider.scss +0 -5
  109. data/app/assets/stylesheets/ab_admin/components/_perms.scss +0 -39
  110. data/app/views/admin/shared/_columns_hider.html.slim +0 -9
  111. data/lib/ab_admin/hooks/globalize_locale_suffix_accessors.rb +0 -25
  112. data/lib/ab_admin/hooks/globalize_valid_locale.rb +0 -9
  113. data/lib/generators/ab_admin/ckeditor_assets/ckeditor_assets_generator.rb +0 -19
  114. data/lib/generators/template.rb +0 -96
@@ -1,5 +1,4 @@
1
1
  class Hash
2
-
3
2
  def reverse_deep_merge!(other_hash)
4
3
  other_hash.each_pair do |k, v|
5
4
  tv = self[k]
@@ -68,29 +67,13 @@ class Hash
68
67
  end
69
68
  end
70
69
 
71
- def val(*array)
72
- if array.empty?
73
- self
74
- else
75
- key = array.shift
76
- value = self[key]
77
- if array.empty?
78
- value
79
- elsif value.is_a? Hash
80
- value.val(*array)
81
- else
82
- nil
83
- end
84
- end
85
- end
86
-
87
- def store_multi(value, *keys)
70
+ def dig_store(value, *keys)
88
71
  key = keys.shift
89
72
  self[key] ||= {}
90
73
  if keys.empty?
91
74
  self[key] = value
92
75
  else
93
- self[key] = self[key].store_multi(value, *keys)
76
+ self[key] = self[key].dig_store(value, *keys)
94
77
  end
95
78
  self
96
79
  end
@@ -107,18 +90,6 @@ class Hash
107
90
  reject { |_, v| v.blank? }
108
91
  end
109
92
 
110
- def no_blank
111
- ActiveSupport::Deprecation.warn('`no_blank` is deprecated, use `reject_blank` instead')
112
- reject_blank
113
- end
114
-
115
- def try_keys(*try_keys)
116
- try_keys.each do |k|
117
- return self[k] if self.has_key?(k)
118
- end
119
- default
120
- end
121
-
122
93
  def deep_stringify_keys
123
94
  inject({}) { |result, (key, value)|
124
95
  value = value.deep_stringify_keys if value.is_a?(Hash)
@@ -1,9 +1,3 @@
1
- class NilClass
2
- def val(*args)
3
- self
4
- end
5
- end
6
-
7
1
  class TrueClass
8
2
  def to_i
9
3
  1
@@ -1,41 +1,4 @@
1
1
  class String
2
- # http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html
3
- #LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|`|"|~|\?|:|\\|\/)/
4
- #LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|`|"|~|\?|:|\\|\s)/
5
-
6
- KEYBOARDS = {
7
- en: 'qwertyuiop[]asdfghjkl;\'zxcvbnm,./',
8
- ru: 'йцукенгшщзхъфывапролджэячсмитьбю/'
9
- }
10
-
11
- unless defined? LUCENE_ESCAPE_REGEX
12
- LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|\^|"|~|\*|\?|:|\\|\/)/
13
-
14
- def lucene_escape
15
- self.gsub(LUCENE_ESCAPE_REGEX, "\\\\\\1")
16
- end
17
- end
18
-
19
- def capitalize_first
20
- self.mb_chars[0].capitalize + self.mb_chars[1..-1]
21
- end
22
-
23
- def is_int?
24
- self =~ /^[-+]?[0-9]+$/
25
- end
26
-
27
- def is_number?
28
- self =~ /^[-+]?[0-9]+(\.[0-9]+)?$/
29
- end
30
-
31
- def to_utc
32
- begin
33
- Time.zone.parse(self).utc
34
- rescue
35
- Time.now.utc
36
- end
37
- end
38
-
39
2
  def no_html
40
3
  str = self.dup
41
4
  str.gsub!(/<br\/?>/, ' ')
@@ -44,49 +7,6 @@ class String
44
7
  str.gsub!('&nbsp;', ' ')
45
8
  str
46
9
  end
47
-
48
- def tr_lang(from=nil, to=nil)
49
- return '' if self.blank?
50
-
51
- unless from || to
52
- if KEYBOARDS[:en].index(self[0])
53
- from, to = :en, :ru
54
- elsif KEYBOARDS[:ru].index(self[0])
55
- from, to = :ru, :en
56
- else
57
- from, to = :en, :ru
58
- end
59
- end
60
-
61
- self.tr(KEYBOARDS[from], KEYBOARDS[to])
62
- end
63
-
64
- def count_words
65
- clean_text.scan(/(\p{Alnum}+([-'.]\p{Alnum}+)*)/u).size
66
- end
67
-
68
- def words_count
69
- frequencies = Hash.new(0)
70
- downcase.scan(/(\w+([-'.]\w+)*)/) { |word, ignore| frequencies[word] += 1 }
71
- frequencies
72
- end
73
-
74
- def self.randomize(length = 8)
75
- Array.new(length) { (rand(122-97) + 97).chr }.join
76
- end
77
-
78
- def clean_text
79
- coder = HTMLEntities.new
80
- coder.decode(self.no_html)
81
- end
82
-
83
- def mb_upcase
84
- mb_chars.upcase.to_s
85
- end
86
-
87
- def mb_downcase
88
- mb_chars.downcase.to_s
89
- end
90
10
  end
91
11
 
92
12
  unless ''.respond_to?(:each)
@@ -19,6 +19,7 @@ module AbAdmin
19
19
  ActiveRecord::Base.send :extend, AbAdmin::Concerns::Silencer
20
20
  ActiveRecord::Base.send :include, AbAdmin::Concerns::Validations
21
21
  ActiveRecord::Base.send :include, AbAdmin::Concerns::Fileuploads
22
+ ActiveRecord::Base.send :extend, AbAdmin::Concerns::TranslationsMacro
22
23
  ActiveRecord::Base.send :extend, EnumField::EnumeratedAttribute
23
24
  end
24
25
 
@@ -1,3 +1,5 @@
1
+ require 'will_paginate/active_record'
2
+
1
3
  # add `:large` option with make pagination on large tables easier, because `SELECT *` is slow with large `OFFSET`:
2
4
  # first it fetch ids of the records using `SELECT id`
3
5
  # and in the second query it fetch records
@@ -10,7 +12,7 @@ module WillPaginate
10
12
  if value.nil?
11
13
  paginate_limit || limit_value
12
14
  else
13
- limit(value)
15
+ limit(value.to_i)
14
16
  end
15
17
  end
16
18
 
@@ -18,7 +20,7 @@ module WillPaginate
18
20
  if value.nil?
19
21
  paginate_offset || offset_value
20
22
  else
21
- super(value)
23
+ super(value.to_i)
22
24
  end
23
25
  end
24
26
  end
@@ -26,8 +28,8 @@ module WillPaginate
26
28
  module Pagination
27
29
  def paginate(options)
28
30
  options = options.dup
29
- page_number = options.fetch(:page) { raise ArgumentError, ':page parameter required' }
30
- per_page = options.delete(:per_page) || self.per_page
31
+ page_number = [1, options[:page].to_i].max
32
+ per_page = (options.delete(:per_page) || self.per_page).to_i
31
33
  total = options.delete(:total_entries)
32
34
  large = options.delete(:large)
33
35
 
@@ -40,8 +42,8 @@ module WillPaginate
40
42
  rel.total_entries = total.to_i unless total.blank?
41
43
 
42
44
  if large
43
- ids = rel.except(:includes).pluck(Arel.sql("#{quoted_table_name}.id"))
44
- new_rel = rel.except(:limit, :offset, :where).where(id: ids)
45
+ ids = rel.except(:includes).pluck(Arel.sql("#{quoted_table_name}.#{primary_key}"))
46
+ new_rel = rel.except(:limit, :offset, :where).where(primary_key => ids)
45
47
  new_rel.paginate_limit = rel.limit_value.to_i
46
48
  new_rel.paginate_offset = rel.offset_value.to_i
47
49
  new_rel.total_entries = rel.total_entries
@@ -1,6 +1,6 @@
1
- # add `:no_uri` options to skip query params in pagination urls
2
1
  require 'will_paginate/view_helpers/action_view'
3
2
 
3
+ # add `:no_uri` options to skip query params in pagination urls
4
4
  WillPaginate::ViewHelpers.pagination_options[:no_uri] = false
5
5
  WillPaginate::ActionView::LinkRenderer.class_exec do
6
6
  def url(page)
@@ -19,7 +19,9 @@ module AbAdmin
19
19
 
20
20
  if response.code == 200
21
21
  json = MultiJson.decode(response)
22
- json['data']['translations'][0]['translatedText']
22
+ res = json['data']['translations'][0]['translatedText'].to_s.gsub(/%\s{/, ' %{')
23
+ res = "#{res[0].upcase}#{res[1..-1]}" if text.first[/[[:upper:]]/]
24
+ res
23
25
  else
24
26
  raise StandardError, response.inspect
25
27
  end
@@ -7,7 +7,7 @@ module AbAdmin
7
7
 
8
8
  def initialize(options: {})
9
9
  @options = options
10
- @locales = Globalize.available_locales
10
+ @locales = AbAdmin.translated_locales
11
11
  @models = AbAdmin.translate_models.map{|m| m.constantize }
12
12
  @models_i18n_hash = {}
13
13
  end
@@ -24,12 +24,12 @@ module AbAdmin
24
24
  end
25
25
 
26
26
  def normalize_html
27
- ::Globalize.available_locales.each do |loc|
27
+ AbAdmin.translated_locales.each do |loc|
28
28
  %w(title h1 keywords description).each do |attr|
29
29
  send("#{attr}_#{loc}=", send("#{attr}_#{loc}").to_s.no_html)
30
30
  end
31
31
  end
32
- ::Globalize.available_locales.each do |loc|
32
+ AbAdmin.translated_locales.each do |loc|
33
33
  send("seo_block_#{loc}=", sanitize(send("seo_block_#{loc}").to_s))
34
34
  end
35
35
  end
@@ -58,12 +58,38 @@ module AbAdmin
58
58
  csv_data.each do |d|
59
59
  key_parts = [l.to_s] + d[0].split('.')
60
60
  raise "Invalid key #{d[0]}" unless data.dig(*key_parts)
61
- data.store_multi(d[i], *key_parts)
61
+ data.dig_store(d[i], *key_parts)
62
62
  end
63
63
  save path, data
64
64
  end
65
65
  end
66
66
 
67
+ INTERPOLATION_REGEXP = /%{[^}]+}/
68
+ def csv_errors(csv)
69
+ return ['CSV blank'] if csv.blank?
70
+ csv_data = CSV.parse(csv)
71
+ errors = []
72
+ csv_data.shift.each_with_index do |l, i|
73
+ next if i.zero?
74
+ unless I18n.available_locales.include?(l.to_sym)
75
+ errors << "Unknown locale #{l}"
76
+ next
77
+ end
78
+ csv_data.each do |d|
79
+ key = d[0]
80
+ next if d[i].blank?
81
+ if translations.dig(I18n.default_locale, key)
82
+ unless translations.dig(I18n.default_locale, key).scan(INTERPOLATION_REGEXP).sort == d[i].scan(INTERPOLATION_REGEXP).sort
83
+ errors << "Wrong interpolations #{I18n.default_locale}:'#{translations.dig(I18n.default_locale, key)}' #{l}:#{d[i]}"
84
+ end
85
+ else
86
+ errors << "Extra interpolations #{l}:#{d[i]}" if d[i].scan(INTERPOLATION_REGEXP).present?
87
+ end
88
+ end
89
+ end
90
+ errors
91
+ end
92
+
67
93
  def translations
68
94
  @translations ||= I18n.backend.send(:translations).slice(*I18n.available_locales).transform_values{|v| v.flatten_hash.transform_keys{|k| k.join('.') } }
69
95
  end
@@ -93,7 +119,7 @@ module AbAdmin
93
119
  message = nil
94
120
  locale_replace_regexp = Regexp.new("(^#{I18n.default_locale}|(?<=\.)#{I18n.default_locale}(?=\.yml))")
95
121
 
96
- locale_files = @files.map { |path| self.class.prepare_data(path) }
122
+ locale_files = @files.find_all{|f| f =~ /\/\w+(\.readonly)?\.yml/ }.map { |path| self.class.prepare_data(path) }
97
123
  main_locale_files = locale_files.find_all { |file| file.locale == I18n.default_locale }
98
124
 
99
125
  main_locale_files.each do |main_file|
@@ -6,17 +6,14 @@ module AbAdmin
6
6
  included do
7
7
  has_one :avatar, as: :assetable, dependent: :destroy, autosave: true
8
8
 
9
- scope :managers, -> { where(user_role_id: [::UserRoleType.admin.id, ::UserRoleType.moderator.id]) }
10
9
  scope :active, -> { where(locked_at: nil) }
11
10
  scope :admin, proc { includes(:avatar) }
12
11
 
13
- after_initialize :init
14
- before_validation :generate_login
15
- before_validation :set_default_role, unless: :user_role_id?
16
-
17
- validate :check_role
18
-
19
12
  enumerated_attribute :user_role_type, id_attribute: :user_role_id, class: ::UserRoleType
13
+ delegate *UserRoleType.codes.map{|code| "#{code}?" }, to: :user_role_type
14
+ end
15
+
16
+ def admin_menu_builder
20
17
  end
21
18
 
22
19
  def name
@@ -40,6 +37,10 @@ module AbAdmin
40
37
  active_for_authentication?
41
38
  end
42
39
 
40
+ def admin_access?
41
+ admin? || moderator?
42
+ end
43
+
43
44
  def generate_password!
44
45
  raw_password = AbAdmin.test_env? ? '654321' : AbAdmin.friendly_token
45
46
  self.password = self.password_confirmation = raw_password
@@ -47,47 +48,10 @@ module AbAdmin
47
48
  raw_password
48
49
  end
49
50
 
50
- def admin_access?
51
- moderator?
52
- end
53
-
54
- def default?
55
- has_role?(:default)
56
- end
57
-
58
- def redactor?
59
- has_role?(:redactor)
60
- end
61
-
62
- def moderator?
63
- has_role?(:admin) || has_role?(:moderator)
64
- end
65
-
66
- def admin?
67
- has_role?(:admin)
68
- end
69
-
70
- def has_role?(role_name)
71
- user_role_type.code == role_name
72
- end
73
-
74
- def set_default_role
75
- self.user_role_id ||= ::UserRoleType.default.id
76
- end
77
-
78
- protected
79
-
80
- def generate_login
81
- self.login ||= begin
82
- unless email.blank?
83
- tmp_login = email.split('@').first
84
- tmp_login.parameterize.downcase.gsub(/[^A-Za-z0-9-]+/, '-').gsub(/-+/, '-')
85
- end
86
- end
87
- end
88
-
89
- def check_role
90
- errors.add(:user_role_id, :invalid) unless ::UserRoleType.valid?(user_role_id)
51
+ def password_required?
52
+ return true if password.present?
53
+ return false if persisted? && password.blank?
54
+ super
91
55
  end
92
56
  end
93
57
  end
@@ -27,12 +27,14 @@ module AbAdmin
27
27
  @filename ||= [@options[:filename] || "#{@klass.model_name.plural}-#{Time.now.strftime('%Y-%m-%d')}", '.csv'].join
28
28
  end
29
29
 
30
- def render
30
+ def render(context=nil, options={})
31
31
  ::CSV.generate(col_sep: @options[:column_separator] || ',') do |csv|
32
32
  csv << columns_names
33
33
 
34
- each_record do |item|
35
- csv << column_data.map { |column| AbAdmin.pretty_data call_method_or_proc_on(item, column, exec: false) }
34
+ I18n.with_locale options[:locale] do
35
+ each_record do |item|
36
+ csv << column_data.map { |column| AbAdmin.pretty_data call_method_or_proc_on(item, column, context: context) }
37
+ end
36
38
  end
37
39
  end
38
40
  end
@@ -85,15 +85,18 @@ module AbAdmin
85
85
  end
86
86
 
87
87
  def call_method_or_proc_on(obj, symbol_or_proc, options = {})
88
- exec = options[:exec].nil? ? true : options[:exec]
88
+ options.reverse_merge!(exec: true)
89
89
  case symbol_or_proc
90
90
  when String
91
- ActiveSupport::Deprecation.warn('`call_method_or_proc_on` don\'t accept method name as String, use Symbol instead') if symbol_or_proc =~ /\A\w+\z/
92
91
  symbol_or_proc
93
92
  when Symbol
94
93
  obj.public_send(symbol_or_proc.to_sym, *options[:attrs])
95
94
  when Proc
96
- exec ? obj.instance_exec(&symbol_or_proc) : symbol_or_proc.call(obj)
95
+ if options[:context]
96
+ options[:context].instance_exec(obj, &symbol_or_proc)
97
+ else
98
+ options[:exec] ? obj.instance_exec(&symbol_or_proc) : symbol_or_proc.call(obj)
99
+ end
97
100
  end
98
101
  end
99
102
  end
@@ -49,25 +49,27 @@ module AbAdmin
49
49
  @filename ||= [@options[:filename] || "#{@klass.model_name.plural}-#{Time.now.strftime('%Y-%m-%d')}", '.xlsx'].join
50
50
  end
51
51
 
52
- def render
52
+ def render(context, options={})
53
53
  date_format = workbook.add_format(num_format: 'dd.mm.yyyy')
54
54
  time_format = workbook.add_format(num_format: 'dd.mm.yyyy HH:MM')
55
55
 
56
- each_with_index do |item, index|
57
- row = index + 1
58
-
59
- column_data.each_with_index do |column, num|
60
- value = call_method_or_proc_on(item, column, exec: false)
61
-
62
- case value
63
- when Date
64
- worksheet.write_string(row, num, value.strftime('%Y-%m-%dT'), date_format)
65
- when DateTime, Time
66
- worksheet.write_date_time(row, num, value.strftime('%Y-%m-%dT%H:%M:%S.%L'), time_format)
67
- when String
68
- worksheet.write_string(row, num, value)
69
- else
70
- worksheet.write(row, num, AbAdmin.pretty_data(value))
56
+ I18n.with_locale options[:locale] do
57
+ each_with_index do |item, index|
58
+ row = index + 1
59
+
60
+ column_data.each_with_index do |column, num|
61
+ value = call_method_or_proc_on(item, column, context: context)
62
+
63
+ case value
64
+ when Date
65
+ worksheet.write_string(row, num, value.strftime('%Y-%m-%dT'), date_format)
66
+ when DateTime, Time
67
+ worksheet.write_date_time(row, num, value.strftime('%Y-%m-%dT%H:%M:%S.%L'), time_format)
68
+ when String
69
+ worksheet.write_string(row, num, value)
70
+ else
71
+ worksheet.write(row, num, AbAdmin.pretty_data(value))
72
+ end
71
73
  end
72
74
  end
73
75
  end