rails_admin 1.4.3 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +12 -4
  3. data/README.md +4 -7
  4. data/app/assets/javascripts/rails_admin/custom/ui.js +1 -0
  5. data/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +1 -1
  6. data/app/assets/javascripts/rails_admin/ra.filtering-select.js +9 -7
  7. data/app/assets/javascripts/rails_admin/ra.i18n.js +28 -0
  8. data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.js +59 -0
  9. data/app/assets/javascripts/rails_admin/ra.sidescroll.js +31 -0
  10. data/app/assets/javascripts/rails_admin/ra.widgets.js +379 -0
  11. data/app/assets/javascripts/rails_admin/rails_admin.js +1 -0
  12. data/app/assets/javascripts/rails_admin/ui.js +135 -0
  13. data/app/assets/stylesheets/rails_admin/ra.sidescroll.scss +29 -0
  14. data/app/assets/stylesheets/rails_admin/ra.widgets.scss +4 -0
  15. data/app/assets/stylesheets/rails_admin/rails_admin.scss.erb +2 -1
  16. data/app/controllers/rails_admin/application_controller.rb +2 -0
  17. data/app/helpers/rails_admin/application_helper.rb +19 -4
  18. data/app/helpers/rails_admin/main_helper.rb +4 -4
  19. data/app/views/layouts/rails_admin/_head.html.haml +7 -0
  20. data/app/views/layouts/rails_admin/_secondary_navigation.html.haml +1 -1
  21. data/app/views/layouts/rails_admin/_sidebar_navigation.html.haml +2 -1
  22. data/app/views/layouts/rails_admin/application.html.haml +3 -11
  23. data/app/views/layouts/rails_admin/pjax.html.haml +1 -5
  24. data/app/views/rails_admin/main/_form_action_text.html.haml +7 -0
  25. data/app/views/rails_admin/main/_form_file_upload.html.haml +4 -4
  26. data/app/views/rails_admin/main/_form_filtering_select.html.haml +1 -1
  27. data/app/views/rails_admin/main/_form_multiple_file_upload.html.haml +7 -5
  28. data/app/views/rails_admin/main/_form_polymorphic_association.html.haml +18 -3
  29. data/app/views/rails_admin/main/dashboard.html.haml +1 -2
  30. data/app/views/rails_admin/main/export.html.haml +2 -2
  31. data/app/views/rails_admin/main/index.html.haml +19 -15
  32. data/app/views/rails_admin/main/show.html.haml +6 -7
  33. data/config/locales/rails_admin.en.yml +3 -0
  34. data/lib/generators/rails_admin/templates/initializer.erb +2 -2
  35. data/lib/rails_admin/abstract_model.rb +3 -3
  36. data/lib/rails_admin/adapters/active_record/abstract_object.rb +2 -2
  37. data/lib/rails_admin/adapters/active_record/property.rb +1 -5
  38. data/lib/rails_admin/adapters/active_record.rb +23 -10
  39. data/lib/rails_admin/adapters/mongoid/association.rb +1 -1
  40. data/lib/rails_admin/adapters/mongoid.rb +30 -13
  41. data/lib/rails_admin/bootstrap-sass/sass_functions.rb +1 -3
  42. data/lib/rails_admin/bootstrap-sass.rb +7 -3
  43. data/lib/rails_admin/config/actions/base.rb +17 -1
  44. data/lib/rails_admin/config/actions/edit.rb +1 -3
  45. data/lib/rails_admin/config/actions/index.rb +3 -3
  46. data/lib/rails_admin/config/actions/new.rb +1 -3
  47. data/lib/rails_admin/config/configurable.rb +6 -4
  48. data/lib/rails_admin/config/fields/association.rb +1 -1
  49. data/lib/rails_admin/config/fields/base.rb +2 -2
  50. data/lib/rails_admin/config/fields/factories/action_text.rb +12 -0
  51. data/lib/rails_admin/config/fields/factories/dragonfly.rb +1 -1
  52. data/lib/rails_admin/config/fields/factories/shrine.rb +27 -0
  53. data/lib/rails_admin/config/fields/types/action_text.rb +30 -0
  54. data/lib/rails_admin/config/fields/types/active_record_enum.rb +3 -19
  55. data/lib/rails_admin/config/fields/types/active_storage.rb +1 -0
  56. data/lib/rails_admin/config/fields/types/all.rb +2 -1
  57. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +4 -0
  58. data/lib/rails_admin/config/fields/types/ck_editor.rb +7 -7
  59. data/lib/rails_admin/config/fields/types/code_mirror.rb +10 -12
  60. data/lib/rails_admin/config/fields/types/color.rb +2 -2
  61. data/lib/rails_admin/config/fields/types/file_upload.rb +6 -2
  62. data/lib/rails_admin/config/fields/types/froala.rb +9 -11
  63. data/lib/rails_admin/config/fields/types/hidden.rb +2 -2
  64. data/lib/rails_admin/config/fields/types/multiple_active_storage.rb +1 -1
  65. data/lib/rails_admin/config/fields/types/multiple_carrierwave.rb +15 -3
  66. data/lib/rails_admin/config/fields/types/multiple_file_upload.rb +17 -3
  67. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +7 -0
  68. data/lib/rails_admin/config/fields/types/shrine.rb +52 -0
  69. data/lib/rails_admin/config/fields/types/simple_mde.rb +8 -5
  70. data/lib/rails_admin/config/fields/types/string.rb +2 -2
  71. data/lib/rails_admin/config/fields/types/string_like.rb +19 -0
  72. data/lib/rails_admin/config/fields/types/text.rb +2 -20
  73. data/lib/rails_admin/config/fields/types/wysihtml5.rb +14 -10
  74. data/lib/rails_admin/config/fields.rb +2 -1
  75. data/lib/rails_admin/config/has_groups.rb +1 -1
  76. data/lib/rails_admin/config/lazy_model.rb +4 -4
  77. data/lib/rails_admin/config/model.rb +5 -4
  78. data/lib/rails_admin/config/proxyable/proxy.rb +7 -9
  79. data/lib/rails_admin/config/proxyable.rb +13 -1
  80. data/lib/rails_admin/config/sections/list.rb +23 -0
  81. data/lib/rails_admin/config.rb +9 -7
  82. data/lib/rails_admin/engine.rb +1 -2
  83. data/lib/rails_admin/extension.rb +16 -4
  84. data/lib/rails_admin/extensions/cancancan/authorization_adapter.rb +45 -21
  85. data/lib/rails_admin/extensions/controller_extension.rb +6 -0
  86. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +27 -10
  87. data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +1 -3
  88. data/lib/rails_admin/support/csv_converter.rb +1 -1
  89. data/lib/rails_admin/version.rb +3 -3
  90. data/lib/rails_admin.rb +0 -1
  91. data/vendor/assets/fonts/rails_admin/FontAwesome.otf +0 -0
  92. data/vendor/assets/fonts/rails_admin/fontawesome-webfont.eot +0 -0
  93. data/vendor/assets/fonts/rails_admin/fontawesome-webfont.svg +2671 -0
  94. data/vendor/assets/fonts/rails_admin/fontawesome-webfont.ttf +0 -0
  95. data/vendor/assets/fonts/rails_admin/fontawesome-webfont.woff +0 -0
  96. data/vendor/assets/fonts/rails_admin/fontawesome-webfont.woff2 +0 -0
  97. data/{app → vendor}/assets/images/rails_admin/bootstrap/glyphicons-halflings-white.png +0 -0
  98. data/{app → vendor}/assets/images/rails_admin/bootstrap/glyphicons-halflings.png +0 -0
  99. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_background.png +0 -0
  100. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_hex.png +0 -0
  101. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_hsb_b.png +0 -0
  102. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_hsb_h.png +0 -0
  103. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_hsb_s.png +0 -0
  104. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_indic.gif +0 -0
  105. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_overlay.png +0 -0
  106. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_rgb_b.png +0 -0
  107. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_rgb_g.png +0 -0
  108. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_rgb_r.png +0 -0
  109. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_select.gif +0 -0
  110. data/{app → vendor}/assets/images/rails_admin/colorpicker/colorpicker_submit.png +0 -0
  111. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_background.png +0 -0
  112. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_hex.png +0 -0
  113. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_hsb_b.png +0 -0
  114. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_hsb_h.png +0 -0
  115. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_hsb_s.png +0 -0
  116. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_indic.gif +0 -0
  117. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_rgb_b.png +0 -0
  118. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_rgb_g.png +0 -0
  119. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_rgb_r.png +0 -0
  120. data/{app → vendor}/assets/images/rails_admin/colorpicker/custom_submit.png +0 -0
  121. data/{app → vendor}/assets/images/rails_admin/colorpicker/select.png +0 -0
  122. data/{app → vendor}/assets/images/rails_admin/colorpicker/select2.png +0 -0
  123. data/{app → vendor}/assets/images/rails_admin/colorpicker/slider.png +0 -0
  124. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-affix.js +0 -0
  125. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-alert.js +0 -0
  126. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-button.js +0 -0
  127. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-carousel.js +0 -0
  128. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-collapse.js +0 -0
  129. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-dropdown.js +0 -0
  130. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-modal.js +0 -0
  131. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-popover.js +0 -0
  132. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-scrollspy.js +0 -0
  133. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-tab.js +0 -0
  134. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-tooltip.js +0 -0
  135. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-transition.js +0 -0
  136. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap-typeahead.js +0 -0
  137. data/{app → vendor}/assets/javascripts/rails_admin/bootstrap/bootstrap.js +0 -0
  138. data/{app → vendor}/assets/javascripts/rails_admin/jquery.colorpicker.js +0 -0
  139. data/{app → vendor}/assets/javascripts/rails_admin/jquery.pjax.js +1 -3
  140. data/vendor/assets/javascripts/rails_admin/moment-with-locales.js +9451 -3263
  141. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_alerts.scss +0 -0
  142. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_badges.scss +0 -0
  143. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_breadcrumbs.scss +0 -0
  144. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_button-groups.scss +0 -0
  145. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_buttons.scss +0 -0
  146. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_carousel.scss +0 -0
  147. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_close.scss +0 -0
  148. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_code.scss +0 -0
  149. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_component-animations.scss +0 -0
  150. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_dropdowns.scss +0 -0
  151. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_forms.scss +0 -0
  152. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_glyphicons.scss +0 -0
  153. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_grid.scss +0 -0
  154. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_input-groups.scss +0 -0
  155. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_jumbotron.scss +0 -0
  156. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_labels.scss +0 -0
  157. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_list-group.scss +0 -0
  158. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_media.scss +0 -0
  159. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_mixins.scss +0 -0
  160. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_modals.scss +0 -0
  161. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_navbar.scss +0 -0
  162. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_navs.scss +0 -0
  163. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_normalize.scss +0 -0
  164. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_pager.scss +0 -0
  165. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_pagination.scss +0 -0
  166. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_panels.scss +0 -0
  167. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_popovers.scss +0 -0
  168. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_print.scss +0 -0
  169. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_progress-bars.scss +0 -0
  170. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_responsive-embed.scss +0 -0
  171. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_responsive-utilities.scss +0 -0
  172. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_scaffolding.scss +0 -0
  173. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_tables.scss +0 -0
  174. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_theme.scss +0 -0
  175. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_thumbnails.scss +0 -0
  176. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_tooltip.scss +0 -0
  177. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_type.scss +0 -0
  178. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_utilities.scss +0 -0
  179. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_variables.scss +0 -0
  180. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/_wells.scss +0 -0
  181. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/bootstrap.scss +0 -0
  182. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_alerts.scss +0 -0
  183. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_background-variant.scss +0 -0
  184. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_border-radius.scss +0 -0
  185. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_buttons.scss +0 -0
  186. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_center-block.scss +0 -0
  187. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_clearfix.scss +0 -0
  188. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_forms.scss +0 -0
  189. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_gradients.scss +0 -0
  190. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_grid-framework.scss +0 -0
  191. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_grid.scss +0 -0
  192. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_hide-text.scss +0 -0
  193. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_image.scss +0 -0
  194. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_labels.scss +0 -0
  195. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_list-group.scss +0 -0
  196. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_nav-divider.scss +0 -0
  197. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_nav-vertical-align.scss +0 -0
  198. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_opacity.scss +0 -0
  199. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_pagination.scss +0 -0
  200. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_panels.scss +0 -0
  201. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_progress-bar.scss +0 -0
  202. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_reset-filter.scss +0 -0
  203. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_resize.scss +0 -0
  204. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_responsive-visibility.scss +0 -0
  205. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_size.scss +0 -0
  206. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_tab-focus.scss +0 -0
  207. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_table-row.scss +0 -0
  208. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_text-emphasis.scss +0 -0
  209. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_text-overflow.scss +0 -0
  210. data/{app → vendor}/assets/stylesheets/rails_admin/bootstrap/mixins/_vendor-prefixes.scss +0 -0
  211. data/vendor/assets/stylesheets/rails_admin/font-awesome.scss +2342 -0
  212. data/{app → vendor}/assets/stylesheets/rails_admin/jquery.colorpicker.scss +0 -0
  213. metadata +163 -170
  214. data/app/assets/javascripts/rails_admin/custom/ui.coffee +0 -1
  215. data/app/assets/javascripts/rails_admin/ra.i18n.coffee +0 -10
  216. data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.coffee +0 -58
  217. data/app/assets/javascripts/rails_admin/ra.widgets.coffee +0 -359
  218. data/app/assets/javascripts/rails_admin/ui.coffee +0 -102
  219. data/lib/rails_admin/config/fields/factories/refile.rb +0 -25
  220. data/lib/rails_admin/config/fields/types/refile.rb +0 -27
  221. data/lib/rails_admin/extensions/cancan/authorization_adapter.rb +0 -57
  222. data/lib/rails_admin/extensions/cancan.rb +0 -3
@@ -48,11 +48,7 @@ module RailsAdmin
48
48
  private
49
49
 
50
50
  def serialized?
51
- if Rails.version < '4.2'
52
- model.serialized_attributes[property.name.to_s]
53
- else
54
- model.type_for_attribute(property.name).class == ::ActiveRecord::Type::Serialized
55
- end
51
+ model.type_for_attribute(property.name).class == ::ActiveRecord::Type::Serialized
56
52
  end
57
53
  end
58
54
  end
@@ -64,6 +64,10 @@ module RailsAdmin
64
64
  end
65
65
  end
66
66
 
67
+ def base_class
68
+ model.base_class
69
+ end
70
+
67
71
  delegate :primary_key, :table_name, to: :model, prefix: false
68
72
 
69
73
  def encoding
@@ -101,7 +105,7 @@ module RailsAdmin
101
105
 
102
106
  def add(field, value, operator)
103
107
  field.searchable_columns.flatten.each do |column_infos|
104
- statement, value1, value2 = StatementBuilder.new(column_infos[:column], column_infos[:type], value, operator).to_statement
108
+ statement, value1, value2 = StatementBuilder.new(column_infos[:column], column_infos[:type], value, operator, @scope.connection.adapter_name).to_statement
105
109
  @statements << statement if statement.present?
106
110
  @values << value1 unless value1.nil?
107
111
  @values << value2 unless value2.nil?
@@ -118,13 +122,17 @@ module RailsAdmin
118
122
  end
119
123
 
120
124
  def query_scope(scope, query, fields = config.list.fields.select(&:queryable?))
121
- wb = WhereBuilder.new(scope)
122
- fields.each do |field|
123
- value = parse_field_value(field, query)
124
- wb.add(field, value, field.search_operator)
125
+ if config.list.search_by
126
+ scope.send(config.list.search_by, query)
127
+ else
128
+ wb = WhereBuilder.new(scope)
129
+ fields.each do |field|
130
+ value = parse_field_value(field, query)
131
+ wb.add(field, value, field.search_operator)
132
+ end
133
+ # OR all query statements
134
+ wb.build
125
135
  end
126
- # OR all query statements
127
- wb.build
128
136
  end
129
137
 
130
138
  # filters example => {"string_field"=>{"0055"=>{"o"=>"like", "v"=>"test_value"}}, ...}
@@ -136,7 +144,7 @@ module RailsAdmin
136
144
  field = fields.detect { |f| f.name.to_s == field_name }
137
145
  value = parse_field_value(field, filter_dump[:v])
138
146
 
139
- wb.add(field, value, (filter_dump[:o] || 'default'))
147
+ wb.add(field, value, (filter_dump[:o] || RailsAdmin::Config.default_search_operator))
140
148
  # AND current filter statements to other filter statements
141
149
  scope = wb.build
142
150
  end
@@ -145,10 +153,15 @@ module RailsAdmin
145
153
  end
146
154
 
147
155
  def build_statement(column, type, value, operator)
148
- StatementBuilder.new(column, type, value, operator).to_statement
156
+ StatementBuilder.new(column, type, value, operator, model.connection.adapter_name).to_statement
149
157
  end
150
158
 
151
159
  class StatementBuilder < RailsAdmin::AbstractModel::StatementBuilder
160
+ def initialize(column, type, value, operator, adapter_name)
161
+ super column, type, value, operator
162
+ @adapter_name = adapter_name
163
+ end
164
+
152
165
  protected
153
166
 
154
167
  def unary_operators
@@ -261,7 +274,7 @@ module RailsAdmin
261
274
  end
262
275
 
263
276
  def ar_adapter
264
- ::ActiveRecord::Base.connection.adapter_name.downcase
277
+ @adapter_name.downcase
265
278
  end
266
279
  end
267
280
  end
@@ -41,7 +41,7 @@ module RailsAdmin
41
41
  end
42
42
 
43
43
  def primary_key
44
- :_id
44
+ association.primary_key.to_sym rescue :_id
45
45
  end
46
46
 
47
47
  def foreign_key
@@ -42,13 +42,21 @@ module RailsAdmin
42
42
  scope = scope.includes(*options[:include]) if options[:include]
43
43
  scope = scope.limit(options[:limit]) if options[:limit]
44
44
  scope = scope.any_in(_id: options[:bulk_ids]) if options[:bulk_ids]
45
- scope = scope.where(query_conditions(options[:query])) if options[:query]
46
- scope = scope.where(filter_conditions(options[:filters])) if options[:filters]
45
+ scope = query_scope(scope, options[:query]) if options[:query]
46
+ scope = filter_scope(scope, options[:filters]) if options[:filters]
47
47
  if options[:page] && options[:per]
48
48
  scope = scope.send(Kaminari.config.page_method_name, options[:page]).per(options[:per])
49
49
  end
50
50
  scope = sort_by(options, scope) if options[:sort]
51
51
  scope
52
+ rescue NoMethodError => e
53
+ if e.message =~ /page/
54
+ e = e.exception <<-EOM.gsub(/^\s{12}/, '')
55
+ #{e.message}
56
+ If you don't have kaminari-mongoid installed, add `gem 'kaminari-mongoid'` to your Gemfile.
57
+ EOM
58
+ end
59
+ raise e
52
60
  end
53
61
 
54
62
  def count(options = {}, scope = nil)
@@ -74,6 +82,12 @@ module RailsAdmin
74
82
  fields.collect { |_name, field| Property.new(field, model) }
75
83
  end
76
84
 
85
+ def base_class
86
+ klass = model
87
+ klass = klass.superclass while klass.hereditary?
88
+ klass
89
+ end
90
+
77
91
  def table_name
78
92
  model.collection_name.to_s
79
93
  end
@@ -104,7 +118,6 @@ module RailsAdmin
104
118
  conditions_per_collection = {}
105
119
  field.searchable_columns.each do |column_infos|
106
120
  collection_name, column_name = parse_collection_name(column_infos[:column])
107
- value = parse_field_value(field, value)
108
121
  statement = build_statement(column_name, column_infos[:type], value, operator)
109
122
  next unless statement
110
123
  conditions_per_collection[collection_name] ||= []
@@ -113,21 +126,25 @@ module RailsAdmin
113
126
  conditions_per_collection
114
127
  end
115
128
 
116
- def query_conditions(query, fields = config.list.fields.select(&:queryable?))
117
- statements = []
129
+ def query_scope(scope, query, fields = config.list.fields.select(&:queryable?))
130
+ if config.list.search_by
131
+ scope.send(config.list.search_by, query)
132
+ else
133
+ statements = []
118
134
 
119
- fields.each do |field|
120
- value = parse_field_value(field, query)
121
- conditions_per_collection = make_field_conditions(field, value, field.search_operator)
122
- statements.concat make_condition_for_current_collection(field, conditions_per_collection)
123
- end
135
+ fields.each do |field|
136
+ value = parse_field_value(field, query)
137
+ conditions_per_collection = make_field_conditions(field, value, field.search_operator)
138
+ statements.concat make_condition_for_current_collection(field, conditions_per_collection)
139
+ end
124
140
 
125
- statements.any? ? {'$or' => statements} : {}
141
+ scope.where(statements.any? ? {'$or' => statements} : {})
142
+ end
126
143
  end
127
144
 
128
145
  # filters example => {"string_field"=>{"0055"=>{"o"=>"like", "v"=>"test_value"}}, ...}
129
146
  # "0055" is the filter index, no use here. o is the operator, v the value
130
- def filter_conditions(filters, fields = config.list.fields.select(&:filterable?))
147
+ def filter_scope(scope, filters, fields = config.list.fields.select(&:filterable?))
131
148
  statements = []
132
149
 
133
150
  filters.each_pair do |field_name, filters_dump|
@@ -145,7 +162,7 @@ module RailsAdmin
145
162
  end
146
163
  end
147
164
 
148
- statements.any? ? {'$and' => statements} : {}
165
+ scope.where(statements.any? ? {'$and' => statements} : {})
149
166
  end
150
167
 
151
168
  def parse_collection_name(column)
@@ -1,5 +1,3 @@
1
- require 'sass'
2
-
3
1
  module Sass
4
2
  module Script
5
3
  module Functions
@@ -12,7 +10,7 @@ module Sass
12
10
  alphastr = alpha.to_s(16).rjust(2, '0')
13
11
  Sass::Script::String.new("##{alphastr}#{color.send(:hex_str)[1..-1]}".upcase)
14
12
  end
15
- declare :ie_hex_str, [:color]
13
+ declare :ie_hex_str, [:color] if respond_to?(:declare)
16
14
  end
17
15
  end
18
16
  end
@@ -11,14 +11,18 @@ module RailsAdmin
11
11
  require 'rails_admin/bootstrap-sass/sass_functions'
12
12
  end
13
13
 
14
- require 'sass-rails' if rails?
14
+ require 'sassc-rails' if rails?
15
15
 
16
16
  unless rails? || compass?
17
17
  raise(Bootstrap::FrameworkNotFound.new('bootstrap-sass requires either Rails > 3.1 or Compass, neither of which are loaded'))
18
18
  end
19
19
 
20
- stylesheets = File.expand_path(File.join('..', 'vendor', 'assets', 'stylesheets'))
21
- ::Sass.load_paths << stylesheets
20
+ if defined?(::Sass) && ::Sass.respond_to?(:load_paths)
21
+ stylesheets = File.expand_path(File.join('..', 'vendor', 'assets', 'stylesheets'))
22
+ fonts = File.expand_path(File.join('..', 'vendor', 'assets', 'fonts'))
23
+ ::Sass.load_paths << stylesheets
24
+ ::Sass.load_paths << fonts
25
+ end
22
26
  end
23
27
 
24
28
  def self.asset_pipeline?
@@ -18,6 +18,22 @@ module RailsAdmin
18
18
  []
19
19
  end
20
20
 
21
+ register_instance_option :show_in_navigation do
22
+ root?
23
+ end
24
+
25
+ register_instance_option :show_in_sidebar do
26
+ !show_in_navigation
27
+ end
28
+
29
+ register_instance_option :show_in_menu do
30
+ true
31
+ end
32
+
33
+ register_instance_option :sidebar_label do
34
+ nil
35
+ end
36
+
21
37
  # http://getbootstrap.com/2.3.2/base-css.html#icons
22
38
  register_instance_option :link_icon do
23
39
  'icon-question-sign'
@@ -83,7 +99,7 @@ module RailsAdmin
83
99
  key.to_sym
84
100
  end
85
101
 
86
- # For Cancan and the like
102
+ # For CanCanCan and the like
87
103
  register_instance_option :authorization_key do
88
104
  key.to_sym
89
105
  end
@@ -25,9 +25,7 @@ module RailsAdmin
25
25
  sanitize_params_for!(request.xhr? ? :modal : :update)
26
26
 
27
27
  @object.set_attributes(params[@abstract_model.param_key])
28
- @authorization_adapter && @authorization_adapter.attributes_for(:update, @abstract_model).each do |name, value|
29
- @object.send("#{name}=", value)
30
- end
28
+ @authorization_adapter && @authorization_adapter.authorize(:update, @abstract_model, @object)
31
29
  changes = @object.changes
32
30
  if @object.save
33
31
  @auditing_adapter && @auditing_adapter.update_object(@object, @abstract_model, _current_user, changes)
@@ -1,3 +1,5 @@
1
+ require 'activemodel-serializers-xml'
2
+
1
3
  module RailsAdmin
2
4
  module Config
3
5
  module Actions
@@ -76,10 +78,8 @@ module RailsAdmin
76
78
  send_data output,
77
79
  type: "text/csv; charset=#{encoding}; #{'header=present' if header}",
78
80
  disposition: "attachment; filename=#{params[:model_name]}_#{DateTime.now.strftime('%Y-%m-%d_%Hh%Mm%S')}.csv"
79
- elsif Rails.version.to_s >= '5'
80
- render plain: output
81
81
  else
82
- render text: output
82
+ render plain: output
83
83
  end
84
84
  end
85
85
  end
@@ -36,9 +36,7 @@ module RailsAdmin
36
36
  sanitize_params_for!(request.xhr? ? :modal : :create)
37
37
 
38
38
  @object.set_attributes(params[@abstract_model.param_key])
39
- @authorization_adapter && @authorization_adapter.attributes_for(:create, @abstract_model).each do |name, value|
40
- @object.send("#{name}=", value)
41
- end
39
+ @authorization_adapter && @authorization_adapter.authorize(:create, @abstract_model, @object)
42
40
 
43
41
  if @object.save
44
42
  @auditing_adapter && @auditing_adapter.create_object(@object, @abstract_model, _current_user)
@@ -7,7 +7,7 @@ module RailsAdmin
7
7
  base.send :extend, ClassMethods
8
8
  end
9
9
 
10
- def has_option?(name) # rubocop:disable PredicateName
10
+ def has_option?(name) # rubocop:disable Naming/PredicateName
11
11
  options = self.class.instance_variable_get('@config_options')
12
12
  options && options.key?(name)
13
13
  end
@@ -30,14 +30,16 @@ module RailsAdmin
30
30
  # and allows configurations such as
31
31
  # label { "#{label}".upcase }
32
32
  # This will use the default definition when called recursively.
33
- if instance_variable_get("@#{option_name}_recurring")
33
+ Thread.current[:rails_admin_recurring] ||= {}
34
+ Thread.current[:rails_admin_recurring][self] ||= {}
35
+ if Thread.current[:rails_admin_recurring][self][option_name]
34
36
  instance_eval(&default_proc)
35
37
  else
36
- instance_variable_set("@#{option_name}_recurring", true)
38
+ Thread.current[:rails_admin_recurring][self][option_name] = true
37
39
  instance_eval(&value_proc)
38
40
  end
39
41
  ensure
40
- instance_variable_set("@#{option_name}_recurring", false)
42
+ Thread.current[:rails_admin_recurring].delete(self)
41
43
  end
42
44
 
43
45
  module ClassMethods
@@ -78,7 +78,7 @@ module RailsAdmin
78
78
 
79
79
  # Reader for associated primary key
80
80
  def associated_primary_key
81
- @associated_primary_key ||= association.primary_key
81
+ @associated_primary_key ||= associated_model_config.abstract_model.primary_key
82
82
  end
83
83
 
84
84
  # Reader for the association's key
@@ -7,7 +7,7 @@ require 'rails_admin/config/inspectable'
7
7
  module RailsAdmin
8
8
  module Config
9
9
  module Fields
10
- class Base # rubocop:disable ClassLength
10
+ class Base # rubocop:disable Metrics/ClassLength
11
11
  include RailsAdmin::Config::Proxyable
12
12
  include RailsAdmin::Config::Configurable
13
13
  include RailsAdmin::Config::Hideable
@@ -20,7 +20,7 @@ module RailsAdmin
20
20
 
21
21
  NAMED_INSTANCE_VARIABLES = [
22
22
  :@parent, :@root, :@section, :@children_fields_registered,
23
- :@associated_model_config, :@group, :@bindings
23
+ :@associated_model_config, :@group
24
24
  ].freeze
25
25
 
26
26
  def initialize(parent, name, properties)
@@ -0,0 +1,12 @@
1
+ require 'rails_admin/config/fields'
2
+ require 'rails_admin/config/fields/types'
3
+
4
+ RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
5
+ if defined?(::ActionText) && properties.try(:association?) && (match = /\Arich_text_(.+)\Z/.match properties.name) && properties.klass.to_s == 'ActionText::RichText'
6
+ field = RailsAdmin::Config::Fields::Types.load(:action_text).new(parent, match[1], properties)
7
+ fields << field
8
+ true
9
+ else
10
+ false
11
+ end
12
+ end
@@ -4,7 +4,7 @@ require 'rails_admin/config/fields/types/file_upload'
4
4
 
5
5
  RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
6
6
  extensions = [:name, :uid]
7
- if (properties.name.to_s =~ /^(.+)_uid$/) && defined?(::Dragonfly) && parent.abstract_model.model.dragonfly_attachment_classes.collect(&:attribute).include?(attachment_name = Regexp.last_match[1].to_sym)
7
+ if (properties.name.to_s =~ /^(.+)_uid$/) && defined?(::Dragonfly) && parent.abstract_model.model.respond_to?(:dragonfly_attachment_classes) && parent.abstract_model.model.dragonfly_attachment_classes.collect(&:attribute).include?(attachment_name = Regexp.last_match[1].to_sym)
8
8
  field = RailsAdmin::Config::Fields::Types.load(:dragonfly).new(parent, attachment_name, properties)
9
9
  children_fields = []
10
10
  extensions.each do |ext|
@@ -0,0 +1,27 @@
1
+ require 'rails_admin/config/fields'
2
+ require 'rails_admin/config/fields/types'
3
+ require 'rails_admin/config/fields/types/file_upload'
4
+
5
+ RailsAdmin::Config::Fields.register_factory do |parent, properties, fields|
6
+ next false unless defined?(::Shrine)
7
+
8
+ attachment_names = parent.abstract_model.model.ancestors.select { |m| m.is_a?(Shrine::Attachment) }.map { |a| a.instance_variable_get("@name") }
9
+ next false if attachment_names.blank?
10
+
11
+ attachment_name = attachment_names.detect { |a| a == properties.name.to_s.chomp('_data').to_sym }
12
+ next false unless attachment_name
13
+
14
+ field = RailsAdmin::Config::Fields::Types.load(:shrine).new(parent, attachment_name, properties)
15
+ fields << field
16
+
17
+ data_field_name = "#{attachment_name}_data".to_sym
18
+ child_properties = parent.abstract_model.properties.detect { |p| p.name == data_field_name }
19
+ next true unless child_properties
20
+
21
+ children_field = fields.detect { |f| f.name == data_field_name } || RailsAdmin::Config::Fields.default_factory.call(parent, child_properties, fields)
22
+ children_field.hide unless field == children_field
23
+ children_field.filterable(false) unless field == children_field
24
+
25
+ field.children_fields([data_field_name])
26
+ true
27
+ end
@@ -0,0 +1,30 @@
1
+ require 'rails_admin/config/fields/types/text'
2
+
3
+ module RailsAdmin
4
+ module Config
5
+ module Fields
6
+ module Types
7
+ class ActionText < Text
8
+ # Register field type for the type loader
9
+ RailsAdmin::Config::Fields::Types.register(self)
10
+
11
+ register_instance_option :version do
12
+ '1.1.1'
13
+ end
14
+
15
+ register_instance_option :css_location do
16
+ "https://cdnjs.cloudflare.com/ajax/libs/trix/#{version}/trix.css"
17
+ end
18
+
19
+ register_instance_option :js_location do
20
+ "https://cdnjs.cloudflare.com/ajax/libs/trix/#{version}/trix.js"
21
+ end
22
+
23
+ register_instance_option :partial do
24
+ :form_action_text
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -29,15 +29,7 @@ module RailsAdmin
29
29
 
30
30
  def parse_value(value)
31
31
  return unless value.present?
32
- if ::Rails.version >= '5'
33
- abstract_model.model.attribute_types[name.to_s].serialize(value)
34
- else
35
- # Depending on the colum type and AR version, we might get a
36
- # string or an integer, so we need to handle both cases.
37
- enum.fetch(value) do
38
- type_cast_value(value)
39
- end
40
- end
32
+ abstract_model.model.attribute_types[name.to_s].serialize(value)
41
33
  end
42
34
 
43
35
  def parse_input(params)
@@ -53,19 +45,11 @@ module RailsAdmin
53
45
  private
54
46
 
55
47
  def parse_input_value(value)
56
- if ::Rails.version >= '5'
57
- abstract_model.model.attribute_types[name.to_s].deserialize(value)
58
- else
59
- enum.invert[type_cast_value(value)]
60
- end
48
+ abstract_model.model.attribute_types[name.to_s].deserialize(value)
61
49
  end
62
50
 
63
51
  def type_cast_value(value)
64
- if ::Rails.version >= '4.2'
65
- abstract_model.model.column_types[name.to_s].type_cast_from_user(value)
66
- else
67
- abstract_model.model.column_types[name.to_s].type_cast(value)
68
- end
52
+ abstract_model.model.column_types[name.to_s].type_cast_from_user(value)
69
53
  end
70
54
  end
71
55
  end
@@ -24,6 +24,7 @@ module RailsAdmin
24
24
  def resource_url(thumb = false)
25
25
  return nil unless value
26
26
  if thumb && value.variable?
27
+ thumb = thumb_method if thumb == true
27
28
  variant = value.variant(thumb)
28
29
  Rails.application.routes.url_helpers.rails_blob_representation_path(
29
30
  variant.blob.signed_id, variant.variation.key, variant.blob.filename, only_path: true
@@ -1,3 +1,4 @@
1
+ require 'rails_admin/config/fields/types/action_text'
1
2
  require 'rails_admin/config/fields/types/active_record_enum'
2
3
  require 'rails_admin/config/fields/types/active_storage'
3
4
  require 'rails_admin/config/fields/types/belongs_to_association'
@@ -11,7 +12,6 @@ require 'rails_admin/config/fields/types/enum'
11
12
  require 'rails_admin/config/fields/types/file_upload'
12
13
  require 'rails_admin/config/fields/types/paperclip'
13
14
  require 'rails_admin/config/fields/types/carrierwave'
14
- require 'rails_admin/config/fields/types/refile'
15
15
  require 'rails_admin/config/fields/types/multiple_file_upload'
16
16
  require 'rails_admin/config/fields/types/multiple_active_storage'
17
17
  require 'rails_admin/config/fields/types/multiple_carrierwave'
@@ -26,6 +26,7 @@ require 'rails_admin/config/fields/types/string'
26
26
  require 'rails_admin/config/fields/types/hidden'
27
27
  require 'rails_admin/config/fields/types/text'
28
28
  require 'rails_admin/config/fields/types/serialized'
29
+ require 'rails_admin/config/fields/types/shrine'
29
30
  require 'rails_admin/config/fields/types/time'
30
31
  require 'rails_admin/config/fields/types/timestamp'
31
32
  require 'rails_admin/config/fields/types/color'
@@ -35,6 +35,10 @@ module RailsAdmin
35
35
  true
36
36
  end
37
37
 
38
+ def associated_primary_key
39
+ @associated_primary_key ||= association.primary_key
40
+ end
41
+
38
42
  def selected_id
39
43
  bindings[:object].send(foreign_key)
40
44
  end
@@ -1,13 +1,17 @@
1
- require 'rails_admin/config/fields/base'
1
+ require 'rails_admin/config/fields/types/text'
2
2
 
3
3
  module RailsAdmin
4
4
  module Config
5
5
  module Fields
6
6
  module Types
7
- class CKEditor < RailsAdmin::Config::Fields::Types::Text
7
+ class CKEditor < Text
8
8
  # Register field type for the type loader
9
9
  RailsAdmin::Config::Fields::Types.register(self)
10
10
 
11
+ register_instance_option :version do
12
+ '4.11.4'
13
+ end
14
+
11
15
  # If you want to have a different toolbar configuration for CKEditor
12
16
  # create your own custom config.js and override this configuration
13
17
  register_instance_option :config_js do
@@ -21,16 +25,12 @@ module RailsAdmin
21
25
 
22
26
  # Use this if you want to point to a cloud instances of the base CKeditor
23
27
  register_instance_option :base_location do
24
- "#{Rails.application.config.assets.prefix}/ckeditor/"
28
+ "https://cdnjs.cloudflare.com/ajax/libs/ckeditor/#{version}/"
25
29
  end
26
30
 
27
31
  register_instance_option :partial do
28
32
  :form_ck_editor
29
33
  end
30
-
31
- [:base_location, :config_js, :location].each do |key|
32
- register_deprecated_instance_option :"ckeditor_#{key}", key
33
- end
34
34
  end
35
35
  end
36
36
  end
@@ -1,10 +1,10 @@
1
- require 'rails_admin/config/fields/base'
1
+ require 'rails_admin/config/fields/types/text'
2
2
 
3
3
  module RailsAdmin
4
4
  module Config
5
5
  module Fields
6
6
  module Types
7
- class CodeMirror < RailsAdmin::Config::Fields::Types::Text
7
+ class CodeMirror < Text
8
8
  # Register field type for the type loader
9
9
  RailsAdmin::Config::Fields::Types.register(self)
10
10
 
@@ -16,31 +16,29 @@ module RailsAdmin
16
16
  }
17
17
  end
18
18
 
19
+ register_instance_option :version do
20
+ '5.46.0'
21
+ end
22
+
19
23
  # Pass the location of the theme and mode for Codemirror
20
24
  register_instance_option :assets do
21
25
  {
22
- mode: ::ActionController::Base.helpers.asset_path('codemirror/modes/css.js'),
23
- theme: ::ActionController::Base.helpers.asset_path('codemirror/themes/night.css'),
26
+ mode: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/#{version}/mode/css/css.min.js",
27
+ theme: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/#{version}/theme/night.min.css",
24
28
  }
25
29
  end
26
30
 
27
- # Use this if you want to point to a cloud instances of CodeMirror
28
31
  register_instance_option :js_location do
29
- ::ActionController::Base.helpers.asset_path('codemirror.js')
32
+ "https://cdnjs.cloudflare.com/ajax/libs/codemirror/#{version}/codemirror.min.js"
30
33
  end
31
34
 
32
- # Use this if you want to point to a cloud instances of CodeMirror
33
35
  register_instance_option :css_location do
34
- ::ActionController::Base.helpers.asset_path('codemirror.css')
36
+ "https://cdnjs.cloudflare.com/ajax/libs/codemirror/#{version}/codemirror.min.css"
35
37
  end
36
38
 
37
39
  register_instance_option :partial do
38
40
  :form_code_mirror
39
41
  end
40
-
41
- [:assets, :config, :css_location, :js_location].each do |key|
42
- register_deprecated_instance_option :"codemirror_#{key}", key
43
- end
44
42
  end
45
43
  end
46
44
  end
@@ -1,10 +1,10 @@
1
- require 'rails_admin/config/fields/base'
1
+ require 'rails_admin/config/fields/types/string_like'
2
2
 
3
3
  module RailsAdmin
4
4
  module Config
5
5
  module Fields
6
6
  module Types
7
- class Color < RailsAdmin::Config::Fields::Base
7
+ class Color < StringLike
8
8
  RailsAdmin::Config::Fields::Types.register(self)
9
9
 
10
10
  register_instance_option :pretty_value do
@@ -23,6 +23,10 @@ module RailsAdmin
23
23
  nil
24
24
  end
25
25
 
26
+ register_instance_option :cache_value do
27
+ bindings[:object].public_send(cache_method) if cache_method
28
+ end
29
+
26
30
  register_instance_option :export_value do
27
31
  resource_url.to_s
28
32
  end
@@ -34,9 +38,9 @@ module RailsAdmin
34
38
  if image
35
39
  thumb_url = resource_url(thumb_method)
36
40
  image_html = v.image_tag(thumb_url, class: 'img-thumbnail')
37
- url != thumb_url ? v.link_to(image_html, url, target: '_blank') : image_html
41
+ url != thumb_url ? v.link_to(image_html, url, target: '_blank', rel: 'noopener noreferrer') : image_html
38
42
  else
39
- v.link_to(value, url, target: '_blank')
43
+ v.link_to(value, url, target: '_blank', rel: 'noopener noreferrer')
40
44
  end
41
45
  end
42
46
  end