rails_admin 3.0.0 → 3.1.0.beta

Sign up to get free protection for your applications and to get access to all the features.
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