rails_admin 3.0.0 → 3.1.0.beta

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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Rakefile +2 -0
  4. data/app/controllers/rails_admin/application_controller.rb +2 -0
  5. data/app/controllers/rails_admin/main_controller.rb +7 -13
  6. data/app/helpers/rails_admin/application_helper.rb +8 -4
  7. data/app/helpers/rails_admin/form_builder.rb +10 -0
  8. data/app/helpers/rails_admin/main_helper.rb +2 -0
  9. data/app/views/layouts/rails_admin/_head.html.erb +9 -0
  10. data/app/views/layouts/rails_admin/_secondary_navigation.html.erb +3 -1
  11. data/app/views/layouts/rails_admin/application.html.erb +1 -1
  12. data/app/views/rails_admin/main/_form_filtering_multiselect.html.erb +2 -2
  13. data/app/views/rails_admin/main/_form_filtering_select.html.erb +1 -1
  14. data/app/views/rails_admin/main/index.html.erb +1 -1
  15. data/config/initializers/active_record_extensions.rb +25 -0
  16. data/config/initializers/mongoid_extensions.rb +2 -0
  17. data/config/routes.rb +2 -0
  18. data/lib/generators/rails_admin/importmap_formatter.rb +28 -0
  19. data/lib/generators/rails_admin/install_generator.rb +68 -9
  20. data/lib/generators/rails_admin/templates/rails_admin.js +1 -0
  21. data/lib/generators/rails_admin/templates/rails_admin.scss.erb +1 -0
  22. data/lib/generators/rails_admin/templates/rails_admin.webpacker.js +2 -0
  23. data/lib/generators/rails_admin/utils.rb +2 -0
  24. data/lib/rails_admin/abstract_model.rb +9 -2
  25. data/lib/rails_admin/adapters/active_record/association.rb +10 -0
  26. data/lib/rails_admin/adapters/active_record/object_extension.rb +2 -0
  27. data/lib/rails_admin/adapters/active_record/property.rb +2 -0
  28. data/lib/rails_admin/adapters/active_record.rb +25 -2
  29. data/lib/rails_admin/adapters/composite_primary_keys/association.rb +45 -0
  30. data/lib/rails_admin/adapters/composite_primary_keys.rb +40 -0
  31. data/lib/rails_admin/adapters/mongoid/association.rb +14 -4
  32. data/lib/rails_admin/adapters/mongoid/bson.rb +2 -0
  33. data/lib/rails_admin/adapters/mongoid/extension.rb +2 -0
  34. data/lib/rails_admin/adapters/mongoid/object_extension.rb +2 -0
  35. data/lib/rails_admin/adapters/mongoid/property.rb +2 -0
  36. data/lib/rails_admin/adapters/mongoid.rb +3 -1
  37. data/lib/rails_admin/config/actions/base.rb +2 -0
  38. data/lib/rails_admin/config/actions/bulk_delete.rb +2 -0
  39. data/lib/rails_admin/config/actions/dashboard.rb +2 -0
  40. data/lib/rails_admin/config/actions/delete.rb +2 -0
  41. data/lib/rails_admin/config/actions/edit.rb +2 -0
  42. data/lib/rails_admin/config/actions/export.rb +2 -0
  43. data/lib/rails_admin/config/actions/history_index.rb +2 -0
  44. data/lib/rails_admin/config/actions/history_show.rb +2 -0
  45. data/lib/rails_admin/config/actions/index.rb +2 -0
  46. data/lib/rails_admin/config/actions/new.rb +2 -0
  47. data/lib/rails_admin/config/actions/show.rb +2 -0
  48. data/lib/rails_admin/config/actions/show_in_app.rb +2 -0
  49. data/lib/rails_admin/config/actions.rb +2 -0
  50. data/lib/rails_admin/config/configurable.rb +2 -0
  51. data/lib/rails_admin/config/fields/association.rb +2 -0
  52. data/lib/rails_admin/config/fields/base.rb +24 -8
  53. data/lib/rails_admin/config/fields/factories/action_text.rb +2 -0
  54. data/lib/rails_admin/config/fields/factories/active_storage.rb +2 -0
  55. data/lib/rails_admin/config/fields/factories/association.rb +6 -5
  56. data/lib/rails_admin/config/fields/factories/carrierwave.rb +2 -0
  57. data/lib/rails_admin/config/fields/factories/devise.rb +2 -0
  58. data/lib/rails_admin/config/fields/factories/dragonfly.rb +2 -0
  59. data/lib/rails_admin/config/fields/factories/enum.rb +2 -0
  60. data/lib/rails_admin/config/fields/factories/paperclip.rb +2 -0
  61. data/lib/rails_admin/config/fields/factories/password.rb +2 -0
  62. data/lib/rails_admin/config/fields/factories/shrine.rb +2 -0
  63. data/lib/rails_admin/config/fields/group.rb +2 -0
  64. data/lib/rails_admin/config/fields/types/action_text.rb +2 -0
  65. data/lib/rails_admin/config/fields/types/active_record_enum.rb +2 -0
  66. data/lib/rails_admin/config/fields/types/active_storage.rb +2 -0
  67. data/lib/rails_admin/config/fields/types/all.rb +3 -0
  68. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +3 -5
  69. data/lib/rails_admin/config/fields/types/boolean.rb +3 -1
  70. data/lib/rails_admin/config/fields/types/bson_object_id.rb +2 -0
  71. data/lib/rails_admin/config/fields/types/carrierwave.rb +2 -0
  72. data/lib/rails_admin/config/fields/types/citext.rb +2 -0
  73. data/lib/rails_admin/config/fields/types/ck_editor.rb +2 -0
  74. data/lib/rails_admin/config/fields/types/code_mirror.rb +2 -0
  75. data/lib/rails_admin/config/fields/types/color.rb +2 -0
  76. data/lib/rails_admin/config/fields/types/composite_keys_belongs_to_association.rb +31 -0
  77. data/lib/rails_admin/config/fields/types/date.rb +2 -0
  78. data/lib/rails_admin/config/fields/types/datetime.rb +2 -0
  79. data/lib/rails_admin/config/fields/types/decimal.rb +2 -0
  80. data/lib/rails_admin/config/fields/types/dragonfly.rb +2 -0
  81. data/lib/rails_admin/config/fields/types/enum.rb +2 -0
  82. data/lib/rails_admin/config/fields/types/file_upload.rb +2 -0
  83. data/lib/rails_admin/config/fields/types/float.rb +2 -0
  84. data/lib/rails_admin/config/fields/types/froala.rb +2 -0
  85. data/lib/rails_admin/config/fields/types/has_and_belongs_to_many_association.rb +2 -0
  86. data/lib/rails_admin/config/fields/types/has_many_association.rb +2 -0
  87. data/lib/rails_admin/config/fields/types/has_one_association.rb +3 -1
  88. data/lib/rails_admin/config/fields/types/hidden.rb +2 -0
  89. data/lib/rails_admin/config/fields/types/inet.rb +2 -0
  90. data/lib/rails_admin/config/fields/types/integer.rb +2 -0
  91. data/lib/rails_admin/config/fields/types/json.rb +2 -0
  92. data/lib/rails_admin/config/fields/types/multiple_active_storage.rb +10 -0
  93. data/lib/rails_admin/config/fields/types/multiple_carrierwave.rb +2 -0
  94. data/lib/rails_admin/config/fields/types/multiple_file_upload.rb +2 -0
  95. data/lib/rails_admin/config/fields/types/numeric.rb +2 -0
  96. data/lib/rails_admin/config/fields/types/paperclip.rb +2 -0
  97. data/lib/rails_admin/config/fields/types/password.rb +2 -0
  98. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +2 -0
  99. data/lib/rails_admin/config/fields/types/serialized.rb +2 -0
  100. data/lib/rails_admin/config/fields/types/shrine.rb +2 -0
  101. data/lib/rails_admin/config/fields/types/simple_mde.rb +2 -0
  102. data/lib/rails_admin/config/fields/types/string.rb +2 -0
  103. data/lib/rails_admin/config/fields/types/string_like.rb +2 -0
  104. data/lib/rails_admin/config/fields/types/text.rb +2 -0
  105. data/lib/rails_admin/config/fields/types/time.rb +2 -0
  106. data/lib/rails_admin/config/fields/types/timestamp.rb +2 -0
  107. data/lib/rails_admin/config/fields/types/uuid.rb +2 -0
  108. data/lib/rails_admin/config/fields/types/wysihtml5.rb +2 -0
  109. data/lib/rails_admin/config/fields/types.rb +2 -0
  110. data/lib/rails_admin/config/fields.rb +3 -1
  111. data/lib/rails_admin/config/groupable.rb +2 -0
  112. data/lib/rails_admin/config/has_description.rb +2 -0
  113. data/lib/rails_admin/config/has_fields.rb +3 -1
  114. data/lib/rails_admin/config/has_groups.rb +2 -0
  115. data/lib/rails_admin/config/hideable.rb +2 -0
  116. data/lib/rails_admin/config/inspectable.rb +2 -0
  117. data/lib/rails_admin/config/model.rb +2 -0
  118. data/lib/rails_admin/config/proxyable/proxy.rb +2 -0
  119. data/lib/rails_admin/config/proxyable.rb +2 -0
  120. data/lib/rails_admin/config/sections/base.rb +2 -0
  121. data/lib/rails_admin/config/sections/create.rb +2 -0
  122. data/lib/rails_admin/config/sections/edit.rb +2 -0
  123. data/lib/rails_admin/config/sections/export.rb +2 -0
  124. data/lib/rails_admin/config/sections/list.rb +2 -0
  125. data/lib/rails_admin/config/sections/modal.rb +2 -0
  126. data/lib/rails_admin/config/sections/nested.rb +2 -0
  127. data/lib/rails_admin/config/sections/show.rb +2 -0
  128. data/lib/rails_admin/config/sections/update.rb +2 -0
  129. data/lib/rails_admin/config/sections.rb +2 -0
  130. data/lib/rails_admin/config.rb +7 -1
  131. data/lib/rails_admin/engine.rb +28 -17
  132. data/lib/rails_admin/extension.rb +2 -0
  133. data/lib/rails_admin/extensions/cancancan/authorization_adapter.rb +2 -0
  134. data/lib/rails_admin/extensions/cancancan.rb +2 -0
  135. data/lib/rails_admin/extensions/controller_extension.rb +2 -0
  136. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +3 -1
  137. data/lib/rails_admin/extensions/paper_trail.rb +2 -0
  138. data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +2 -0
  139. data/lib/rails_admin/extensions/pundit.rb +2 -0
  140. data/lib/rails_admin/support/csv_converter.rb +2 -1
  141. data/lib/rails_admin/support/datetime.rb +3 -1
  142. data/lib/rails_admin/support/esmodule_preprocessor.rb +4 -0
  143. data/lib/rails_admin/support/hash_helper.rb +2 -0
  144. data/lib/rails_admin/version.rb +4 -2
  145. data/lib/rails_admin.rb +3 -1
  146. data/lib/tasks/rails_admin.rake +2 -0
  147. data/package.json +1 -1
  148. data/src/rails_admin/base.js +13 -1
  149. data/src/rails_admin/filtering-multiselect.js +5 -10
  150. data/src/rails_admin/filtering-select.js +2 -2
  151. data/src/rails_admin/nested-form-hooks.js +1 -1
  152. data/src/rails_admin/remote-form.js +4 -5
  153. data/src/rails_admin/styles/base/theming.scss +10 -0
  154. data/src/rails_admin/styles/base.scss +5 -5
  155. data/src/rails_admin/ui.js +1 -1
  156. data/src/rails_admin/widgets.js +2 -2
  157. data/vendor/assets/javascripts/rails_admin/jquery3.js +118 -109
  158. metadata +11 -7
  159. data/lib/generators/rails_admin/templates/rails_admin.js.erb +0 -2
  160. data/lib/generators/rails_admin/templates/rails_admin.scss +0 -1
  161. data/lib/generators/rails_admin/templates/webpack.config.js +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a20d0a9cc9b7702c63e5e92918ac89f986b2d3d1e666539fd0c16562508bdf85
4
- data.tar.gz: 7d5784f25b6a16c0d2a05b827a8bc9990da28d056d34b2569ea628910088ae89
3
+ metadata.gz: 2594ac2920ab0902ebfd266356904760c4cdfe6160dbc0e7a8924a3351e1835a
4
+ data.tar.gz: 252ab9a0d237488762f8a9b7a2c8c91af3dd0e048e598570722c818da78c075b
5
5
  SHA512:
6
- metadata.gz: ea7b4265126ff76473d461cd0630feb1a4e3ad71476d2843577a25fdaea53fed0ca57b06b55dbe63615f5004151796b346f9bca2492ff71175d44faffbe24c38
7
- data.tar.gz: 58fb832bd8e1e7c124e79eabd01393da73217714e0b52a32ea215ef1e1b2d4f33390928ed15686eeed983446d74a914ac947cd709bd67180799bf8bd9017bc4a
6
+ metadata.gz: 5ee9f27798eace802666b89d15cd92fcdf120ba44e317a87f15c5be0971d869fd6a897bbf24d0aab0dcb74859cb3dc450c098ad1af9eae4c51a4919dcd019da7
7
+ data.tar.gz: 7b649a4777d4647b6154f5a35560330200d5203390c5b79771cf0cc95e7ba1aa9eab8d6414f680226f3ccc2e5cbbfb5325f4a8654f5191514214c5880cd8ed59
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gem 'appraisal', '>= 2.0'
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
4
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_admin/abstract_model'
2
4
 
3
5
  module RailsAdmin
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  class MainController < RailsAdmin::ApplicationController
3
5
  include ActionView::Helpers::TextHelper
@@ -58,23 +60,15 @@ module RailsAdmin
58
60
  end
59
61
 
60
62
  def get_sort_hash(model_config)
61
- abstract_model = model_config.abstract_model
62
63
  field = model_config.list.fields.detect { |f| f.name.to_s == params[:sort] }
64
+ # If no sort param, default to the `sort_by` specified in the list config
65
+ field ||= model_config.list.possible_fields.detect { |f| f.name == model_config.list.sort_by.try(:to_sym) }
63
66
 
64
67
  column =
65
68
  if field.nil? || field.sortable == false # use default sort, asked field does not exist or is not sortable
66
- field = model_config.list.possible_fields.detect { |f| f.name == model_config.list.sort_by.to_sym }
67
- "#{abstract_model.table_name}.#{model_config.list.sort_by}"
68
- elsif field.sortable == true # use the given field
69
- "#{abstract_model.table_name}.#{field.name}"
70
- elsif (field.sortable.is_a?(String) || field.sortable.is_a?(Symbol)) && field.sortable.to_s.include?('.') # just provide sortable, don't do anything smart
71
- field.sortable
72
- elsif field.sortable.is_a?(Hash) # just join sortable hash, don't do anything smart
73
- "#{field.sortable.keys.first}.#{field.sortable.values.first}"
74
- elsif field.association? # use column on target table
75
- "#{field.associated_model_config.abstract_model.table_name}.#{field.sortable}"
76
- else # use described column in the field conf.
77
- "#{abstract_model.table_name}.#{field.sortable}"
69
+ model_config.list.sort_by
70
+ else
71
+ field.sort_column
78
72
  end
79
73
 
80
74
  params[:sort_reverse] ||= 'false'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module ApplicationHelper
3
5
  def authorized?(action_name, abstract_model = nil, object = nil)
@@ -29,7 +31,7 @@ module RailsAdmin
29
31
 
30
32
  if authorized
31
33
  edit_url = rails_admin.url_for(
32
- action_name: edit_action.action_name,
34
+ action: edit_action.action_name,
33
35
  model_name: abstract_model.to_param,
34
36
  controller: 'rails_admin/main',
35
37
  id: _current_user.id,
@@ -118,10 +120,12 @@ module RailsAdmin
118
120
  abstract_model = node.abstract_model
119
121
  model_param = abstract_model.to_param
120
122
  url = rails_admin.url_for(action: :index, controller: 'rails_admin/main', model_name: model_param)
121
- level_class = " nav-level-#{level}" if level > 0
122
123
  nav_icon = node.navigation_icon ? %(<i class="#{node.navigation_icon}"></i>).html_safe : ''
124
+ css_classes = ['nav-link']
125
+ css_classes.push("nav-level-#{level}") if level > 0
126
+ css_classes.push('active') if defined?(@action) && current_action?(@action, model_param)
123
127
  li = content_tag :li, data: {model: model_param} do
124
- link_to nav_icon + node.label_plural, url, class: "nav-link#{level_class}"
128
+ link_to nav_icon + " " + node.label_plural, url, class: css_classes.join(' ')
125
129
  end
126
130
  child_nodes = parent_groups[abstract_model.model_name]
127
131
  child_nodes ? li + navigation(parent_groups, child_nodes, level + 1) : li
@@ -206,7 +210,7 @@ module RailsAdmin
206
210
  yield
207
211
  rescue LoadError => e
208
212
  if /sassc/.match?(e.message)
209
- e = e.exception <<-MSG.gsub(/^\s{10}/, '')
213
+ e = e.exception <<~MSG
210
214
  #{e.message}
211
215
  RailsAdmin requires the gem sassc-rails, make sure to put `gem 'sassc-rails'` to Gemfile.
212
216
  MSG
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nested_form/builder_mixin'
2
4
 
3
5
  module RailsAdmin
@@ -105,6 +107,14 @@ module RailsAdmin
105
107
  (@dom_name ||= {})[field.name] ||= %(#{@object_name}#{options[:index] && "[#{options[:index]}]"}[#{field.method_name}]#{field.is_a?(Config::Fields::Association) && field.multiple? ? '[]' : ''})
106
108
  end
107
109
 
110
+ def hidden_field(method, options = {})
111
+ if method == :id
112
+ super method, {value: object.id.to_s}
113
+ else
114
+ super
115
+ end
116
+ end
117
+
108
118
  protected
109
119
 
110
120
  def generator_action(action, nested)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module MainHelper
3
5
  def rails_admin_form_for(*args, &block)
@@ -15,6 +15,15 @@
15
15
  <% when :webpack %>
16
16
  <%= stylesheet_link_tag "rails_admin.css", media: :all, data: {'turbo-track': 'reload'} %>
17
17
  <%= javascript_include_tag "rails_admin.js", async: true, data: {'turbo-track': 'reload'} %>
18
+ <% when :importmap %>
19
+ <%= stylesheet_link_tag "rails_admin.css", media: :all, data: {'turbo-track': 'reload'} %>
20
+ <%= javascript_inline_importmap_tag(RailsAdmin::Engine.importmap.to_json(resolver: self)) %>
21
+ <%= javascript_importmap_module_preload_tags(RailsAdmin::Engine.importmap) %>
22
+ <%= javascript_importmap_shim_nonce_configuration_tag %>
23
+ <%= javascript_importmap_shim_tag %>
24
+ <%= # Preload jQuery and make it global, unless jQuery UI fails to initialize
25
+ tag.script "import jQuery from 'jquery'; window.jQuery = jQuery;".html_safe, type: "module" %>
26
+ <%= javascript_import_module_tag 'rails_admin' %>
18
27
  <% else
19
28
  raise "Unknown asset_source: #{RailsAdmin::config.asset_source}"
20
29
  end %>
@@ -17,7 +17,9 @@
17
17
  <% end %>
18
18
  <% if logout_path.present? %>
19
19
  <li class="nav-item">
20
- <%= link_to t('admin.misc.log_out'), logout_path, method: logout_method, class: 'nav-link label label-danger', data: {turbo: 'false'} %>
20
+ <%= link_to logout_path, method: logout_method, class: 'nav-link', data: {turbo: 'false'} do %>
21
+ <span class="badge bg-danger"><%= t('admin.misc.log_out') %></span>
22
+ <% end %>
21
23
  </li>
22
24
  <% end %>
23
25
  <% end %>
@@ -5,7 +5,7 @@
5
5
  </head>
6
6
  <body class="rails_admin">
7
7
  <div data-i18n-options="<%= I18n.t("admin.js").to_json %>" id="admin-js"></div>
8
- <nav class="navbar navbar-expand-md fixed-top navbar-dark bg-primary border-bottom">
8
+ <nav class="navbar navbar-expand-md fixed-top <%= RailsAdmin::Config.navbar_css_classes.join(' ') %>">
9
9
  <%= render "layouts/rails_admin/navigation" %>
10
10
  </nav>
11
11
  <div class="container-fluid">
@@ -3,7 +3,7 @@
3
3
  source_abstract_model = RailsAdmin.config(form.object.class).abstract_model
4
4
 
5
5
  selected = form.object.send(field.name)
6
- selected_ids = selected.map{|s| s.send(field.associated_primary_key)}
6
+ selected_ids = selected.map{|s| s.send(field.associated_primary_key).to_s}
7
7
 
8
8
  current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update'
9
9
 
@@ -13,7 +13,7 @@
13
13
  selected.map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
14
14
  else
15
15
  i = 0
16
- controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
16
+ controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key).to_s] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
17
17
  end
18
18
 
19
19
  js_data = {
@@ -8,7 +8,7 @@
8
8
 
9
9
  xhr = !field.associated_collection_cache_all
10
10
 
11
- collection = xhr ? [[field.formatted_value, field.selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
11
+ collection = xhr ? [[field.formatted_value, field.selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key).to_s] }
12
12
 
13
13
  js_data = {
14
14
  xhr: xhr,
@@ -140,7 +140,7 @@
140
140
  <tr class="<%= @abstract_model.param_key %>_row <%= @model_config.list.with(object: object).row_css_class %>">
141
141
  <% if checkboxes %>
142
142
  <td class="sticky">
143
- <%= check_box_tag "bulk_ids[]", object.id, false %>
143
+ <%= check_box_tag "bulk_ids[]", object.id.to_s, false %>
144
144
  </td>
145
145
  <% end %>
146
146
  <% properties.map{ |property| property.bind(:object, object) }.each do |property| %>
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ActiveSupport.on_load(:active_record) do
2
4
  module ActiveRecord
3
5
  class Base
@@ -20,4 +22,27 @@ ActiveSupport.on_load(:active_record) do
20
22
  end
21
23
  end
22
24
  end
25
+
26
+ if defined?(CompositePrimaryKeys)
27
+ # Apply patch until the fix is released:
28
+ # https://github.com/composite-primary-keys/composite_primary_keys/pull/572
29
+ CompositePrimaryKeys::CompositeKeys.class_eval do
30
+ alias_method :to_param, :to_s
31
+ end
32
+
33
+ CompositePrimaryKeys::CollectionAssociation.prepend(Module.new do
34
+ def ids_writer(ids)
35
+ if reflection.association_primary_key.is_a? Array
36
+ ids = CompositePrimaryKeys.normalize(Array(ids).reject(&:blank?), reflection.association_primary_key.size)
37
+ reflection.association_primary_key.each_with_index do |primary_key, i|
38
+ pk_type = klass.type_for_attribute(primary_key)
39
+ ids.each do |id|
40
+ id[i] = pk_type.cast(id[i]) if id.is_a? Array
41
+ end
42
+ end
43
+ end
44
+ super ids
45
+ end
46
+ end)
47
+ end
23
48
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(::Mongoid::Document)
2
4
  require 'rails_admin/adapters/mongoid/extension'
3
5
  Mongoid::Document.include RailsAdmin::Adapters::Mongoid::Extension
data/config/routes.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RailsAdmin::Engine.routes.draw do
2
4
  controller 'main' do
3
5
  RailsAdmin::Config::Actions.all(:root).each { |action| match "/#{action.route_fragment}", action: action.action_name, as: action.action_name, via: action.http_methods }
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'importmap/packager'
4
+
5
+ module RailsAdmin
6
+ class ImportmapFormatter
7
+ attr_reader :packager
8
+
9
+ def initialize(path = 'confing/importmap.rails_admin.rb')
10
+ @packager = Importmap::Packager.new(path)
11
+ end
12
+
13
+ def format
14
+ imports = packager.import("rails_admin@#{RailsAdmin::Version.js}")
15
+
16
+ # Use ESM compatible version to work around https://github.com/cljsjs/packages/issues/1579
17
+ imports['@popperjs/core'].gsub!('lib/index.js', 'dist/esm/popper.js')
18
+
19
+ # Tidy up jQuery UI dependencies
20
+ jquery_uis = imports.keys.filter { |key, _| key =~ /jquery-ui/ }
21
+ imports['jquery-ui/'] = imports[jquery_uis.first].gsub(%r{(@[^/@]+)/[^@]+$}, '\1/')
22
+ imports.reject! { |key, _| jquery_uis.include? key }
23
+
24
+ pins = ['pin "rails_admin", preload: true', packager.pin_for('rails_admin/src/rails_admin/base', imports.delete('rails_admin'))]
25
+ (pins + imports.map { |package, url| packager.pin_for(package, url) }).join("\n")
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/generators'
2
4
  require 'rails_admin/version'
3
5
  require File.expand_path('utils', __dir__)
@@ -8,7 +10,7 @@ module RailsAdmin
8
10
  include Generators::Utils::InstanceMethods
9
11
 
10
12
  argument :_namespace, type: :string, required: false, desc: 'RailsAdmin url namespace'
11
- class_option :asset, type: :string, required: false, default: nil, desc: 'Asset delivery method [options: webpacker, sprockets]'
13
+ class_option :asset, type: :string, required: false, default: nil, desc: 'Asset delivery method [options: webpacker, webpack, sprockets, importmap]'
12
14
  desc 'RailsAdmin installation generator'
13
15
 
14
16
  def install
@@ -27,10 +29,14 @@ module RailsAdmin
27
29
  case asset
28
30
  when 'webpack'
29
31
  configure_for_webpack
32
+ when 'importmap'
33
+ configure_for_importmap
30
34
  when 'webpacker'
31
35
  configure_for_webpacker5
32
36
  when 'sprockets'
33
37
  configure_for_sprockets
38
+ else
39
+ raise "Unknown asset source: #{asset}"
34
40
  end
35
41
  end
36
42
 
@@ -41,6 +47,10 @@ module RailsAdmin
41
47
 
42
48
  if defined?(Webpacker)
43
49
  'webpacker'
50
+ elsif Rails.root.join('webpack.config.js').exist?
51
+ 'webpack'
52
+ elsif Rails.root.join('config/importmap.rb').exist?
53
+ 'importmap'
44
54
  else
45
55
  'sprockets'
46
56
  end
@@ -52,17 +62,66 @@ module RailsAdmin
52
62
 
53
63
  def configure_for_webpacker5
54
64
  run "yarn add rails_admin@#{RailsAdmin::Version.js}"
55
- @scss_relative_dir = '../stylesheets/'
56
- template 'rails_admin.js.erb', 'app/javascript/packs/rails_admin.js'
57
- template 'rails_admin.scss', 'app/javascript/stylesheets/rails_admin.scss'
65
+ template 'rails_admin.webpacker.js', 'app/javascript/packs/rails_admin.js'
66
+ template 'rails_admin.scss.erb', 'app/javascript/stylesheets/rails_admin.scss'
58
67
  end
59
68
 
60
69
  def configure_for_webpack
61
- run "yarn add rails_admin@#{RailsAdmin::Version.js} css-loader mini-css-extract-plugin sass sass-loader"
62
- @scss_relative_dir = './'
63
- template 'rails_admin.js.erb', 'app/javascript/rails_admin.js'
64
- template 'rails_admin.scss', 'app/javascript/rails_admin.scss'
65
- template 'webpack.config.js', 'webpack.config.js'
70
+ run "yarn add rails_admin@#{RailsAdmin::Version.js}"
71
+ template 'rails_admin.js', 'app/javascript/rails_admin.js'
72
+ webpack_config = File.join(destination_root, 'webpack.config.js')
73
+ marker = %r{application: ["']./app/javascript/application.js["']}
74
+ if File.exist?(webpack_config) && File.read(webpack_config) =~ marker
75
+ insert_into_file 'webpack.config.js', %(,\n rails_admin: "./app/javascript/rails_admin.js"), after: marker
76
+ else
77
+ say 'Add `rails_admin: "./app/javascript/rails_admin.js"` to the entry section in your webpack.config.js.', :red
78
+ end
79
+ setup_css({'build' => 'webpack --config webpack.config.js'})
80
+ end
81
+
82
+ def configure_for_importmap
83
+ run "yarn add rails_admin@#{RailsAdmin::Version.js}"
84
+ template 'rails_admin.js', 'app/javascript/rails_admin.js'
85
+ require_relative 'importmap_formatter'
86
+ add_file 'config/importmap.rails_admin.rb', ImportmapFormatter.new.format
87
+ setup_css
88
+ end
89
+
90
+ def setup_css(additional_script_entries = {})
91
+ gem 'cssbundling-rails'
92
+ rake 'css:install:sass'
93
+
94
+ @fa_font_path = '.'
95
+ template 'rails_admin.scss.erb', 'app/assets/stylesheets/rails_admin.scss'
96
+ asset_config = %{Rails.application.config.assets.paths << Rails.root.join("node_modules/@fortawesome/fontawesome-free/webfonts")\n}
97
+ if File.exist? File.join(destination_root, 'config/initializers/assets.rb')
98
+ append_to_file 'config/initializers/assets.rb', asset_config
99
+ else
100
+ add_file 'config/initializers/assets.rb', asset_config
101
+ end
102
+ add_scripts(additional_script_entries.merge({'build:css' => 'sass ./app/assets/stylesheets/rails_admin.scss:./app/assets/builds/rails_admin.css --no-source-map --load-path=node_modules'}))
103
+ end
104
+
105
+ def add_scripts(entries)
106
+ display 'Add scripts to package.json'
107
+ package = begin
108
+ JSON.parse(File.read(File.join(destination_root, 'package.json')))
109
+ rescue Errno::ENOENT, JSON::ParserError
110
+ {}
111
+ end
112
+ if package['scripts'] && (package['scripts'].keys & entries.keys).any?
113
+ say <<-MESSAGE.gsub(/^ {10}/, ''), :red
114
+ You need to merge "scripts": #{JSON.pretty_generate(entries)} into the existing scripts in your package.json .
115
+ Taking 'build:css' as an example, if you're already have application.sass.css for the sass build, the resulting script would look like:
116
+ sass ./app/assets/stylesheets/application.sass.scss:./app/assets/builds/application.css ./app/assets/stylesheets/rails_admin.scss:./app/assets/builds/rails_admin.css --no-source-map --load-path=node_modules
117
+ MESSAGE
118
+ else
119
+ package['scripts'] ||= {}
120
+ entries.each do |entry, build_script|
121
+ package['scripts'][entry] = build_script
122
+ end
123
+ add_file 'package.json', JSON.pretty_generate(package)
124
+ end
66
125
  end
67
126
  end
68
127
  end
@@ -0,0 +1 @@
1
+ import "rails_admin/src/rails_admin/base";
@@ -0,0 +1 @@
1
+ <%= instance_variable_defined?(:@fa_font_path) ? %{$fa-font-path: "#{@fa_font_path}";\n} : '' %>@import "rails_admin/src/rails_admin/styles/base";
@@ -0,0 +1,2 @@
1
+ import "rails_admin/src/rails_admin/base";
2
+ import "../stylesheets/rails_admin.scss";
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Generators
3
5
  module Utils
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_admin/support/datetime'
2
4
 
3
5
  module RailsAdmin
@@ -99,8 +101,13 @@ module RailsAdmin
99
101
 
100
102
  def initialize_active_record
101
103
  @adapter = :active_record
102
- require 'rails_admin/adapters/active_record'
103
- extend Adapters::ActiveRecord
104
+ if defined?(::CompositePrimaryKeys)
105
+ require 'rails_admin/adapters/composite_primary_keys'
106
+ extend Adapters::CompositePrimaryKeys
107
+ else
108
+ require 'rails_admin/adapters/active_record'
109
+ extend Adapters::ActiveRecord
110
+ end
104
111
  end
105
112
 
106
113
  def initialize_mongoid
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module ActiveRecord
@@ -21,6 +23,14 @@ module RailsAdmin
21
23
  association.macro
22
24
  end
23
25
 
26
+ def field_type
27
+ if polymorphic?
28
+ :polymorphic_association
29
+ else
30
+ :"#{association.macro}_association"
31
+ end
32
+ end
33
+
24
34
  def klass
25
35
  if options[:polymorphic]
26
36
  polymorphic_parents(:active_record, model.name.to_s, name) || []
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module ActiveRecord
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module ActiveRecord
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
  require 'rails_admin/adapters/active_record/association'
3
5
  require 'rails_admin/adapters/active_record/object_extension'
@@ -31,11 +33,11 @@ module RailsAdmin
31
33
  scope ||= scoped
32
34
  scope = scope.includes(options[:include]) if options[:include]
33
35
  scope = scope.limit(options[:limit]) if options[:limit]
34
- scope = scope.where(primary_key => options[:bulk_ids]) if options[:bulk_ids]
36
+ scope = bulk_scope(scope, options) if options[:bulk_ids]
35
37
  scope = query_scope(scope, options[:query]) if options[:query]
36
38
  scope = filter_scope(scope, options[:filters]) if options[:filters]
37
39
  scope = scope.send(Kaminari.config.page_method_name, options[:page]).per(options[:per]) if options[:page] && options[:per]
38
- scope = scope.reorder("#{options[:sort]} #{options[:sort_reverse] ? 'asc' : 'desc'}") if options[:sort]
40
+ scope = sort_scope(scope, options) if options[:sort]
39
41
  scope
40
42
  end
41
43
 
@@ -105,6 +107,27 @@ module RailsAdmin
105
107
  true
106
108
  end
107
109
 
110
+ private
111
+
112
+ def bulk_scope(scope, options)
113
+ scope.where(primary_key => options[:bulk_ids])
114
+ end
115
+
116
+ def sort_scope(scope, options)
117
+ direction = options[:sort_reverse] ? :asc : :desc
118
+ case options[:sort]
119
+ when String, Symbol
120
+ scope.reorder("#{options[:sort]} #{direction}")
121
+ when Array
122
+ scope.reorder(options[:sort].zip(Array.new(options[:sort].size) { direction }).to_h)
123
+ when Hash
124
+ scope.reorder(options[:sort].map { |table_name, column| "#{table_name}.#{column}" }.
125
+ zip(Array.new(options[:sort].size) { direction }).to_h)
126
+ else
127
+ raise ArgumentError.new("Unsupported sort value: #{options[:sort]}")
128
+ end
129
+ end
130
+
108
131
  class WhereBuilder
109
132
  def initialize(scope)
110
133
  @statements = []
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsAdmin
4
+ module Adapters
5
+ module CompositePrimaryKeys
6
+ class Association < RailsAdmin::Adapters::ActiveRecord::Association
7
+ def field_type
8
+ if type == :belongs_to && association.foreign_key.is_a?(Array)
9
+ :composite_keys_belongs_to_association
10
+ else
11
+ super
12
+ end
13
+ end
14
+
15
+ def primary_key
16
+ return nil if polymorphic?
17
+
18
+ value = association.association_primary_key
19
+
20
+ if value.is_a? Array
21
+ :id
22
+ else
23
+ value.to_sym
24
+ end
25
+ end
26
+
27
+ def foreign_key
28
+ if association.foreign_key.is_a? Array
29
+ association.foreign_key.map(&:to_sym)
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ def key_accessor
36
+ if type == :belongs_to && foreign_key.is_a?(Array)
37
+ :"#{name}_id"
38
+ else
39
+ super
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_admin/adapters/active_record'
4
+ require 'rails_admin/adapters/composite_primary_keys/association'
5
+
6
+ module RailsAdmin
7
+ module Adapters
8
+ module CompositePrimaryKeys
9
+ include RailsAdmin::Adapters::ActiveRecord
10
+
11
+ def get(id, scope = scoped)
12
+ begin
13
+ object = scope.find(id)
14
+ rescue ::ActiveRecord::RecordNotFound
15
+ return nil
16
+ end
17
+
18
+ object.extend(RailsAdmin::Adapters::ActiveRecord::ObjectExtension)
19
+ end
20
+
21
+ def associations
22
+ model.reflect_on_all_associations.collect do |association|
23
+ RailsAdmin::Adapters::CompositePrimaryKeys::Association.new(association, model)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def bulk_scope(scope, options)
30
+ if primary_key.is_a? Array
31
+ options[:bulk_ids].map do |id|
32
+ scope.where(primary_key.zip(::CompositePrimaryKeys::CompositeKeys.parse(id)).to_h)
33
+ end.reduce(&:or)
34
+ else
35
+ super
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module Mongoid
@@ -34,6 +36,14 @@ module RailsAdmin
34
36
  end
35
37
  end
36
38
 
39
+ def field_type
40
+ if polymorphic?
41
+ :polymorphic_association
42
+ else
43
+ :"#{type}_association"
44
+ end
45
+ end
46
+
37
47
  def klass
38
48
  if polymorphic? && %i[referenced_in belongs_to].include?(macro)
39
49
  polymorphic_parents(:mongoid, model.name, name) || []
@@ -111,10 +121,10 @@ module RailsAdmin
111
121
  def nested_options
112
122
  nested = nested_attributes_options.try { |o| o[name] }
113
123
  if !nested && %i[embeds_one embeds_many].include?(macro.to_sym) && !cyclic?
114
- raise <<-MSG.gsub(/^\s+/, '')
115
- Embbeded association without accepts_nested_attributes_for can't be handled by RailsAdmin,
116
- because embedded model doesn't have top-level access.
117
- Please add `accepts_nested_attributes_for :#{association.name}' line to `#{model}' model.
124
+ raise <<~MSG
125
+ Embedded association without accepts_nested_attributes_for can't be handled by RailsAdmin,
126
+ because embedded model doesn't have top-level access.
127
+ Please add `accepts_nested_attributes_for :#{association.name}' line to `#{model}' model.
118
128
  MSG
119
129
  end
120
130