diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 69953566d3..cba1105238 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -8,7 +8,10 @@ jobs:
strategy:
fail-fast: false
matrix:
- ruby: ["3.0", 3.1]
+ ruby:
+ - "3.0"
+ - "3.1"
+ - "3.2"
gemfile: [gemfiles/rails_7.0.gemfile]
orm: [active_record]
adapter: [sqlite3]
diff --git a/.rubocop.yml b/.rubocop.yml
index 7d5d5b5f14..7e5adc8643 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -9,6 +9,7 @@ AllCops:
- "node_modules/**/*"
- "spec/dummy_app/bin/**/*"
- "spec/dummy_app/db/schema.rb"
+ - "spec/dummy_app/node_modules/**/*"
- "spec/dummy_app/tmp/**/*"
- "vendor/bundle/**/*"
NewCops: disable
@@ -108,7 +109,7 @@ Metrics/BlockNesting:
Metrics/ClassLength:
CountComments: false
- Max: 132 # TODO: Lower to 100
+ Max: 200 # TODO: Lower to 100
Metrics/CyclomaticComplexity:
Max: 15 # TODO: Lower to 6
@@ -162,9 +163,6 @@ Style/DoubleNegation:
Style/EachWithObject:
Enabled: false
-Style/Encoding:
- Enabled: false
-
Style/EndlessMethod:
Enabled: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e504b6c8e0..ce6fbed3bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,38 @@
## [Unreleased](https://github.com/railsadminteam/rails_admin/tree/HEAD)
-[Full Changelog](https://github.com/railsadminteam/rails_admin/compare/v3.1.0...HEAD)
+[Full Changelog](https://github.com/railsadminteam/rails_admin/compare/v3.1.2...HEAD)
+
+## [3.1.2](https://github.com/railsadminteam/rails_admin/tree/v3.1.2) - 2023-03-23
+
+[Full Changelog](https://github.com/railsadminteam/rails_admin/compare/v3.1.1...v3.1.2)
+
+### Fixed
+
+- Fix install failing with importmap setup ([aca22b6](https://github.com/railsadminteam/rails_admin/commit/aca22b6ba1eca1ac618525334cf14fc946e1c99e), [#3609](https://github.com/railsadminteam/rails_admin/issues/3609))
+- Fix to show non-eager-loaded models which are explicitly configured ([87c9d5b](https://github.com/railsadminteam/rails_admin/commit/87c9d5bc5b6ffb423e72054b3cfe8f949c12c178), [#3604](https://github.com/railsadminteam/rails_admin/issues/3604))
+- Fix `rails_admin.dom_ready` event not triggered with jQuery `on` ([2ee43de](https://github.com/railsadminteam/rails_admin/commit/2ee43deb1fa8d3a9e3ea0e589c1687d684e19ad6), [33773d7](https://github.com/railsadminteam/rails_admin/commit/33773d7f8dd43eeb0f6a7c125c4bee170132e5d2), [#3600](https://github.com/railsadminteam/rails_admin/discussions/3600))
+- Restore caching in RailsAdmin::Config::Model#excluded? ([#3587](https://github.com/railsadminteam/rails_admin/pull/3587))
+- Optimize/simplify viable_models file path to class name logic ([#3589](https://github.com/railsadminteam/rails_admin/pull/3589))
+
+## [3.1.1](https://github.com/railsadminteam/rails_admin/tree/v3.1.1) - 2022-12-18
+
+[Full Changelog](https://github.com/railsadminteam/rails_admin/compare/v3.1.0...v3.1.1)
+
+### Changed
+
+- Relax Font-Awesome dependency to allow Webpacker users to stay on 5.x ([3a7f348](https://github.com/railsadminteam/rails_admin/commit/3a7f34875248e446b48fd76870f0c337fee6dcf9), [#3565](https://github.com/railsadminteam/rails_admin/issues/3565))
+
+### Removed
+
+- Remove unused glphyicon assets ([#3578](https://github.com/railsadminteam/rails_admin/pull/3578))
+
+### Fixed
+
+- Simplify uses of defined? ([#3561](https://github.com/railsadminteam/rails_admin/pull/3561))
+- Define jQuery object in separate file to support esbuild ([#3571](https://github.com/railsadminteam/rails_admin/pull/3571))
+- Fix filter box being duplicated on browser back ([c6b1893](https://github.com/railsadminteam/rails_admin/commit/c6b18934cff3db0768836d799ee1bea54045709c), [#3570](https://github.com/railsadminteam/rails_admin/issues/3570))
+- Fix sidebar menu expanding horizontally, preventing vertical scroll ([9997c10](https://github.com/railsadminteam/rails_admin/commit/9997c1095066aaac39afb27bf8de705cf6ccb1ef), [#3564](https://github.com/railsadminteam/rails_admin/issues/3564))
## [3.1.0](https://github.com/railsadminteam/rails_admin/tree/v3.1.0) - 2022-11-06
@@ -142,7 +173,7 @@
### Added
- Support Mongoid's Storage Field Names ([cefa23c](https://github.com/railsadminteam/rails_admin/commit/cefa23c9d23d06dc1134228e142e6f0aa4655c54), [#1745](https://github.com/railsadminteam/rails_admin/issues/1745))
-- Allow save/delete oprations to be disabled based on an object's `#read_only?` status ([9cd7541](https://github.com/railsadminteam/rails_admin/commit/9cd7541a2e6af4ae4941b200840a1474baeb2f06), [#1684](https://github.com/railsadminteam/rails_admin/issues/1684))
+- Allow save/delete operations to be disabled based on an object's `#read_only?` status ([9cd7541](https://github.com/railsadminteam/rails_admin/commit/9cd7541a2e6af4ae4941b200840a1474baeb2f06), [#1684](https://github.com/railsadminteam/rails_admin/issues/1684))
- Allow customizing model's last created time ([d6d380a](https://github.com/railsadminteam/rails_admin/commit/d6d380a02e955c3b14ff7dc30f1809a2a6cd0f47), [#3010](https://github.com/railsadminteam/rails_admin/issues/3010))
- Add ability to hide the dashboard history section ([#3189](https://github.com/railsadminteam/rails_admin/pull/3189))
- Add model scope configuration option, which enables 'unscoped' mode ([8d905f9](https://github.com/railsadminteam/rails_admin/commit/8d905f9e2f1102e8addf324b496720e3fd47bf1d), [#1348](https://github.com/railsadminteam/rails_admin/issues/1348))
diff --git a/README.md b/README.md
index 3f7672264a..421a70bea7 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
# RailsAdmin
[![Gem Version](https://img.shields.io/gem/v/rails_admin.svg)][gem]
-[![Build Status](https://img.shields.io/github/workflow/status/railsadminteam/rails_admin/Test)][ghactions]
+[![Build Status](https://github.com/railsadminteam/rails_admin/actions/workflows/test.yml/badge.svg)][ghactions]
[![Coverage Status](https://img.shields.io/coveralls/railsadminteam/rails_admin.svg)][coveralls]
[![Code Climate](https://codeclimate.com/github/railsadminteam/rails_admin.svg)][codeclimate]
[![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=rails_admin&package-manager=bundler&version-scheme=semver)][semver]
[gem]: https://rubygems.org/gems/rails_admin
-[ghactions]: https://github.com/railsadminteam/rails_admin/actions
+[ghactions]: https://github.com/railsadminteam/rails_admin/actions/workflows/test.yml
[coveralls]: https://coveralls.io/r/railsadminteam/rails_admin
[codeclimate]: https://codeclimate.com/github/railsadminteam/rails_admin
[semver]: https://dependabot.com/compatibility-score.html?dependency-name=rails_admin&package-manager=bundler&version-scheme=semver
@@ -98,6 +98,8 @@ This library aims to support and is [tested against][ghactions] the following Ru
- Ruby 2.6
- Ruby 2.7
- Ruby 3.0
+- Ruby 3.1
+- Ruby 3.2
- [JRuby][]
[jruby]: http://jruby.org/
diff --git a/app/controllers/rails_admin/main_controller.rb b/app/controllers/rails_admin/main_controller.rb
index 5968bb7bec..af5a69aba3 100644
--- a/app/controllers/rails_admin/main_controller.rb
+++ b/app/controllers/rails_admin/main_controller.rb
@@ -56,7 +56,11 @@ def respond_to_missing?(sym, include_private)
end
def back_or_index
- params[:return_to].presence && params[:return_to].include?(request.host) && (params[:return_to] != request.fullpath) ? params[:return_to] : index_path
+ allowed_return_to?(params[:return_to].to_s) ? params[:return_to] : index_path
+ end
+
+ def allowed_return_to?(url)
+ url != request.fullpath && url.start_with?(request.base_url, '/') && !url.start_with?('//')
end
def get_sort_hash(model_config)
diff --git a/app/helpers/rails_admin/application_helper.rb b/app/helpers/rails_admin/application_helper.rb
index 9432effc7d..147fd7ca3f 100644
--- a/app/helpers/rails_admin/application_helper.rb
+++ b/app/helpers/rails_admin/application_helper.rb
@@ -122,7 +122,7 @@ def navigation(parent_groups, nodes, level = 0)
nav_icon = node.navigation_icon ? %().html_safe : ''
css_classes = ['nav-link']
css_classes.push("nav-level-#{level}") if level > 0
- css_classes.push('active') if defined?(@action) && current_action?(@action, model_param)
+ css_classes.push('active') if @action && current_action?(@action, model_param)
li = content_tag :li, data: {model: model_param} do
link_to nav_icon + " " + node.label_plural, url, class: css_classes.join(' ')
end
diff --git a/app/views/rails_admin/main/delete.html.erb b/app/views/rails_admin/main/delete.html.erb
index 6b08bedce8..94cfcb6130 100644
--- a/app/views/rails_admin/main/delete.html.erb
+++ b/app/views/rails_admin/main/delete.html.erb
@@ -1,6 +1,6 @@
<%= t("admin.form.are_you_sure_you_want_to_delete_the_object", model_name: @abstract_model.pretty_name.downcase) %>
- “<%= @model_config.with(object: @object).object_label %>”
+ <%= @model_config.with(object: @object).object_label %>
<%= t("admin.form.all_of_the_following_related_items_will_be_deleted") %>
diff --git a/lib/generators/rails_admin/importmap_formatter.rb b/lib/generators/rails_admin/importmap_formatter.rb
index 6b40080f2b..40c3f1c7d4 100644
--- a/lib/generators/rails_admin/importmap_formatter.rb
+++ b/lib/generators/rails_admin/importmap_formatter.rb
@@ -11,7 +11,7 @@ def initialize(path = 'confing/importmap.rails_admin.rb')
end
def format
- imports = packager.import("rails_admin@#{RailsAdmin::Version.js}")
+ imports = packager.import("rails_admin@#{RailsAdmin::Version.js}", from: 'jspm.io')
# Use ESM compatible version to work around https://github.com/cljsjs/packages/issues/1579
imports['@popperjs/core'].gsub!('lib/index.js', 'dist/esm/popper.js')
diff --git a/lib/generators/rails_admin/install_generator.rb b/lib/generators/rails_admin/install_generator.rb
index 3e36a46b54..b0c83c4afe 100644
--- a/lib/generators/rails_admin/install_generator.rb
+++ b/lib/generators/rails_admin/install_generator.rb
@@ -64,6 +64,8 @@ def configure_for_webpacker5
run "yarn add rails_admin@#{RailsAdmin::Version.js}"
template 'rails_admin.webpacker.js', 'app/javascript/packs/rails_admin.js'
template 'rails_admin.scss.erb', 'app/javascript/stylesheets/rails_admin.scss'
+ # To work around https://github.com/railsadminteam/rails_admin/issues/3565
+ add_package_json_field('resolutions', {'rails_admin/@fortawesome/fontawesome-free' => '^5.15.0'})
end
def configure_for_webpack
@@ -99,28 +101,29 @@ def setup_css(additional_script_entries = {})
else
add_file 'config/initializers/assets.rb', asset_config
end
- 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'}))
+ add_package_json_field('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'}), <<~INSTRUCTION)
+ Taking 'build:css' as an example, if you're already have application.sass.css for the sass build, the resulting script would look like:
+ 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
+ INSTRUCTION
end
- def add_scripts(entries)
- display 'Add scripts to package.json'
+ def add_package_json_field(name, entries, instruction = nil)
+ display "Add #{name} to package.json"
package = begin
JSON.parse(File.read(File.join(destination_root, 'package.json')))
rescue Errno::ENOENT, JSON::ParserError
{}
end
- if package['scripts'] && (package['scripts'].keys & entries.keys).any?
- say <<-MESSAGE.gsub(/^ {10}/, ''), :red
- You need to merge "scripts": #{JSON.pretty_generate(entries)} into the existing scripts in your package.json .
- Taking 'build:css' as an example, if you're already have application.sass.css for the sass build, the resulting script would look like:
- 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
+ if package[name] && (package[name].keys & entries.keys).any?
+ say <<~MESSAGE, :red
+ You need to merge "#{name}": #{JSON.pretty_generate(entries)} into the existing #{name} in your package.json.#{instruction && "\n#{instruction}"}
MESSAGE
else
- package['scripts'] ||= {}
- entries.each do |entry, build_script|
- package['scripts'][entry] = build_script
+ package[name] ||= {}
+ entries.each do |entry, value|
+ package[name][entry] = value
end
- add_file 'package.json', JSON.pretty_generate(package)
+ add_file 'package.json', "#{JSON.pretty_generate(package)}\n"
end
end
end
diff --git a/lib/generators/rails_admin/templates/rails_admin.scss.erb b/lib/generators/rails_admin/templates/rails_admin.scss.erb
index 6411f72c57..93ba8b9bb6 100644
--- a/lib/generators/rails_admin/templates/rails_admin.scss.erb
+++ b/lib/generators/rails_admin/templates/rails_admin.scss.erb
@@ -1 +1 @@
-<%= instance_variable_defined?(:@fa_font_path) ? %{$fa-font-path: "#{@fa_font_path}";\n} : '' %>@import "rails_admin/src/rails_admin/styles/base";
+<%= @fa_font_path ? %{$fa-font-path: "#{@fa_font_path}";\n} : '' %>@import "rails_admin/src/rails_admin/styles/base";
diff --git a/lib/generators/rails_admin/templates/rails_admin.webpacker.js b/lib/generators/rails_admin/templates/rails_admin.webpacker.js
index a5a3f4cd93..63c31b5973 100644
--- a/lib/generators/rails_admin/templates/rails_admin.webpacker.js
+++ b/lib/generators/rails_admin/templates/rails_admin.webpacker.js
@@ -1,2 +1,2 @@
import "rails_admin/src/rails_admin/base";
-import "../stylesheets/rails_admin.scss";
\ No newline at end of file
+import "../stylesheets/rails_admin.scss";
diff --git a/lib/rails_admin/adapters/active_record.rb b/lib/rails_admin/adapters/active_record.rb
index 1c165d265a..d45d67f26e 100644
--- a/lib/rails_admin/adapters/active_record.rb
+++ b/lib/rails_admin/adapters/active_record.rb
@@ -201,6 +201,8 @@ def unary_operators
case @type
when :boolean
boolean_unary_operators
+ when :uuid
+ uuid_unary_operators
when :integer, :decimal, :float
numeric_unary_operators
else
@@ -230,6 +232,7 @@ def boolean_unary_operators
)
end
alias_method :numeric_unary_operators, :boolean_unary_operators
+ alias_method :uuid_unary_operators, :boolean_unary_operators
def range_filter(min, max)
if min && max && min == max
diff --git a/lib/rails_admin/adapters/active_record/association.rb b/lib/rails_admin/adapters/active_record/association.rb
index c31d00e48f..f0b9c3093e 100644
--- a/lib/rails_admin/adapters/active_record/association.rb
+++ b/lib/rails_admin/adapters/active_record/association.rb
@@ -33,7 +33,7 @@ def field_type
def klass
if options[:polymorphic]
- polymorphic_parents(:active_record, model.name.to_s, name) || []
+ polymorphic_parents(:active_record, association.active_record.name.to_s, name) || []
else
association.klass
end
diff --git a/lib/rails_admin/adapters/mongoid/association.rb b/lib/rails_admin/adapters/mongoid/association.rb
index 726fbd6a24..b04a95f9e1 100644
--- a/lib/rails_admin/adapters/mongoid/association.rb
+++ b/lib/rails_admin/adapters/mongoid/association.rb
@@ -46,7 +46,7 @@ def field_type
def klass
if polymorphic? && %i[referenced_in belongs_to].include?(macro)
- polymorphic_parents(:mongoid, model.name, name) || []
+ polymorphic_parents(:mongoid, association.inverse_class_name, name) || []
else
association.klass
end
diff --git a/lib/rails_admin/config.rb b/lib/rails_admin/config.rb
index 6056953ab9..4d9be5736f 100644
--- a/lib/rails_admin/config.rb
+++ b/lib/rails_admin/config.rb
@@ -364,23 +364,22 @@ def visible_models(bindings)
private
- def lchomp(base, arg)
- base.to_s.reverse.chomp(arg.to_s.reverse).reverse
- end
-
def viable_models
included_models.collect(&:to_s).presence || begin
@@system_models ||= # memoization for tests
([Rails.application] + Rails::Engine.subclasses.collect(&:instance)).flat_map do |app|
(app.paths['app/models'].to_a + app.config.eager_load_paths).collect do |load_path|
Dir.glob(app.root.join(load_path)).collect do |load_dir|
+ path_prefix = "#{app.root.join(load_dir)}/"
Dir.glob("#{load_dir}/**/*.rb").collect do |filename|
# app/models/module/class.rb => module/class.rb => module/class => Module::Class
- lchomp(filename, "#{app.root.join(load_dir)}/").chomp('.rb').camelize
+ filename.delete_prefix(path_prefix).chomp('.rb').camelize
end
end
end
end.flatten.reject { |m| m.starts_with?('Concerns::') } # rubocop:disable Style/MultilineBlockChain
+
+ @@system_models + @registry.keys.collect(&:to_s)
end
end
diff --git a/lib/rails_admin/config/lazy_model.rb b/lib/rails_admin/config/lazy_model.rb
index c96bb4083e..1e7256711e 100644
--- a/lib/rails_admin/config/lazy_model.rb
+++ b/lib/rails_admin/config/lazy_model.rb
@@ -48,7 +48,7 @@ def target
# :
# end
#
- # Thus, sort all blocks to excute for a resource by Proc.source_path,
+ # Thus, sort all blocks to execute for a resource by Proc.source_path,
# to guarantee that blocks from 'config/initializers' evaluate before
# blocks defined within a model class.
unless @deferred_blocks.empty?
diff --git a/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb b/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb
index 635063cee5..a9834aa616 100644
--- a/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb
+++ b/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb
@@ -146,7 +146,7 @@ def listing_for_model_or_object(model, object, query, sort, sort_reverse, all, p
versions = object.nil? ? versions_for_model(model) : object.public_send(model.model.versions_association_name)
versions = versions.where('event LIKE ?', "%#{query}%") if query.present?
versions = versions.order(sort)
- versions = all ? versions : versions.send(Kaminari.config.page_method_name, current_page).per(per_page)
+ versions = versions.send(Kaminari.config.page_method_name, current_page).per(per_page) unless all
paginated_proxies = Kaminari.paginate_array([], total_count: versions.try(:total_count) || versions.count)
paginated_proxies = paginated_proxies.send(
paginated_proxies.respond_to?(Kaminari.config.page_method_name) ? Kaminari.config.page_method_name : :page,
diff --git a/lib/rails_admin/support/csv_converter.rb b/lib/rails_admin/support/csv_converter.rb
index 5bda506360..431fe234b0 100644
--- a/lib/rails_admin/support/csv_converter.rb
+++ b/lib/rails_admin/support/csv_converter.rb
@@ -1,4 +1,3 @@
-# encoding: UTF-8
# frozen_string_literal: true
require 'csv'
diff --git a/lib/rails_admin/support/datetime.rb b/lib/rails_admin/support/datetime.rb
index 87cd7703ac..39345b9d16 100644
--- a/lib/rails_admin/support/datetime.rb
+++ b/lib/rails_admin/support/datetime.rb
@@ -21,6 +21,7 @@ class Datetime
'%-I' => 'h', # Hour of the day, 12-hour clock (1..12)
'%k' => 'H', # Hour of the day, 24-hour clock (0..23)
'%l' => 'h', # Hour of the day, 12-hour clock (1..12)
+ '%-l' => 'h', # Hour of the day, 12-hour clock (1..12)
'%M' => 'i', # Minute of the hour (00..59)
'%-M' => 'i', # Minute of the hour (00..59)
'%m' => 'm', # Month of the year (01..12)
diff --git a/lib/rails_admin/version.rb b/lib/rails_admin/version.rb
index 8f00dd46b3..1b09a721f2 100644
--- a/lib/rails_admin/version.rb
+++ b/lib/rails_admin/version.rb
@@ -4,7 +4,7 @@ module RailsAdmin
class Version
MAJOR = 3
MINOR = 1
- PATCH = 0
+ PATCH = 2
PRE = nil
class << self
diff --git a/package.json b/package.json
index 72fe133c6f..19b126676d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rails_admin",
- "version": "3.1.0",
+ "version": "3.1.2",
"description": "RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.",
"homepage": "https://github.com/railsadminteam/rails_admin",
"license": "MIT",
@@ -15,7 +15,7 @@
},
"dependencies": {
"@babel/runtime": "^7.16.7",
- "@fortawesome/fontawesome-free": "^6.1.1",
+ "@fortawesome/fontawesome-free": ">=5.15.0 <7.0.0",
"@hotwired/turbo-rails": "^7.1.0",
"@popperjs/core": "^2.11.0",
"@rails/ujs": "^6.1.4-1",
diff --git a/rails_admin.gemspec b/rails_admin.gemspec
index 55577acbe3..18fc3166ab 100644
--- a/rails_admin.gemspec
+++ b/rails_admin.gemspec
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
lib = File.expand_path('lib', __dir__)
diff --git a/spec/controllers/rails_admin/application_controller_spec.rb b/spec/controllers/rails_admin/application_controller_spec.rb
index 57498c536d..cb71c2d576 100644
--- a/spec/controllers/rails_admin/application_controller_spec.rb
+++ b/spec/controllers/rails_admin/application_controller_spec.rb
@@ -23,7 +23,7 @@
it 'works for dynamic names in the controller context' do
RailsAdmin.config do |config|
- config.main_app_name = proc { |controller| [Rails.application.engine_name.try(:titleize), controller.params[:action].titleize] }
+ config.main_app_name = proc { |controller| [Rails.application.engine_name&.titleize, controller.params[:action].titleize] }
end
controller.params[:action] = 'dashboard'
expect(controller.send(:_get_plugin_name)).to eq(['Dummy App Application', 'Dashboard'])
diff --git a/spec/controllers/rails_admin/main_controller_spec.rb b/spec/controllers/rails_admin/main_controller_spec.rb
index b1b52bb85e..e6e5d93d84 100644
--- a/spec/controllers/rails_admin/main_controller_spec.rb
+++ b/spec/controllers/rails_admin/main_controller_spec.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
require 'spec_helper'
@@ -471,4 +470,70 @@ def get(action, params)
)
end
end
+
+ describe 'back_or_index' do
+ before do
+ allow(controller).to receive(:index_path).and_return(index_path)
+ end
+
+ let(:index_path) { '/' }
+
+ it 'returns back to index when return_to is not defined' do
+ controller.params = {}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to return_to url when it starts with same protocol and host' do
+ return_to_url = "http://#{request.host}/teams"
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(return_to_url)
+ end
+
+ it 'returns back to return_to url when it contains a path' do
+ return_to_url = '/teams'
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(return_to_url)
+ end
+
+ it 'returns back to index path when return_to path does not start with slash' do
+ return_to_url = 'teams'
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to index path when return_to url does not start with full protocol' do
+ return_to_url = "#{request.host}/teams"
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to index path when return_to url starts with double slash' do
+ return_to_url = "//#{request.host}/teams"
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to index path when return_to url starts with triple slash' do
+ return_to_url = "///#{request.host}/teams"
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to index path when return_to url does not have host' do
+ return_to_url = 'http:///teams'
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to index path when return_to url starts with different protocol' do
+ return_to_url = "other://#{request.host}/teams"
+ controller.params = {return_to: return_to_url}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+
+ it 'returns back to index path when return_to does not start with the same protocol and host' do
+ controller.params = {return_to: "http://google.com?#{request.host}"}
+ expect(controller.send(:back_or_index)).to eq(index_path)
+ end
+ end
end
diff --git a/spec/dummy_app/Rakefile b/spec/dummy_app/Rakefile
old mode 100755
new mode 100644
index dc38fb4849..566ac3f002
--- a/spec/dummy_app/Rakefile
+++ b/spec/dummy_app/Rakefile
@@ -1,4 +1,3 @@
-#!/usr/bin/env rake
# frozen_string_literal: true
# Add your own tasks in files placed in lib/tasks ending in .rake,
diff --git a/spec/dummy_app/app/active_record/carrierwave_uploader.rb b/spec/dummy_app/app/active_record/carrierwave_uploader.rb
index 6762c2b41d..e4b50dbbd0 100644
--- a/spec/dummy_app/app/active_record/carrierwave_uploader.rb
+++ b/spec/dummy_app/app/active_record/carrierwave_uploader.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
require 'mini_magick'
diff --git a/spec/dummy_app/app/active_record/field_test.rb b/spec/dummy_app/app/active_record/field_test.rb
index 5677d51f1c..8e4452c248 100644
--- a/spec/dummy_app/app/active_record/field_test.rb
+++ b/spec/dummy_app/app/active_record/field_test.rb
@@ -30,7 +30,7 @@ class FieldTest < ActiveRecord::Base
attr_accessor :remove_active_storage_assets
after_save do
- Array(remove_active_storage_assets).each { |id| active_storage_assets.find_by_id(id).try(:purge) }
+ Array(remove_active_storage_assets).each { |id| active_storage_assets.find_by_id(id)&.purge }
end
end
diff --git a/spec/dummy_app/app/active_record/team.rb b/spec/dummy_app/app/active_record/team.rb
index b8d183049b..f4cc9f727e 100644
--- a/spec/dummy_app/app/active_record/team.rb
+++ b/spec/dummy_app/app/active_record/team.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
class Team < ActiveRecord::Base
diff --git a/spec/dummy_app/app/assets/javascripts/rails_admin/custom/ui.js b/spec/dummy_app/app/assets/javascripts/rails_admin/custom/ui.js
new file mode 100644
index 0000000000..44506531d1
--- /dev/null
+++ b/spec/dummy_app/app/assets/javascripts/rails_admin/custom/ui.js
@@ -0,0 +1,9 @@
+window.domReadyTriggered = [];
+
+document.addEventListener("rails_admin.dom_ready", function () {
+ window.domReadyTriggered.push("plainjs/dot");
+});
+
+$(document).on("rails_admin.dom_ready", function () {
+ window.domReadyTriggered.push("jquery/dot");
+});
diff --git a/spec/dummy_app/app/javascript/rails_admin.js b/spec/dummy_app/app/javascript/rails_admin.js
index c45b2a786d..038a150f86 100644
--- a/spec/dummy_app/app/javascript/rails_admin.js
+++ b/spec/dummy_app/app/javascript/rails_admin.js
@@ -4,3 +4,13 @@ import "trix";
import "@rails/actiontext";
import * as ActiveStorage from "@rails/activestorage";
ActiveStorage.start();
+
+window.domReadyTriggered = [];
+
+document.addEventListener("rails_admin.dom_ready", function () {
+ window.domReadyTriggered.push("plainjs/dot");
+});
+
+$(document).on("rails_admin.dom_ready", function () {
+ window.domReadyTriggered.push("jquery/dot");
+});
diff --git a/spec/dummy_app/app/mongoid/carrierwave_uploader.rb b/spec/dummy_app/app/mongoid/carrierwave_uploader.rb
index 6762c2b41d..e4b50dbbd0 100644
--- a/spec/dummy_app/app/mongoid/carrierwave_uploader.rb
+++ b/spec/dummy_app/app/mongoid/carrierwave_uploader.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
require 'mini_magick'
diff --git a/spec/dummy_app/app/mongoid/field_test.rb b/spec/dummy_app/app/mongoid/field_test.rb
index 93201d7348..57834e2ee5 100644
--- a/spec/dummy_app/app/mongoid/field_test.rb
+++ b/spec/dummy_app/app/mongoid/field_test.rb
@@ -65,7 +65,7 @@ class FieldTest
mount_uploader :carrierwave_asset, CarrierwaveUploader
# carrierwave-mongoid does not support mount_uploaders yet:
# https://github.com/carrierwaveuploader/carrierwave-mongoid/issues/138
- mount_uploader :carrierwave_assets, CarrierwaveUploader
+ mount_uploaders :carrierwave_assets, CarrierwaveUploader
validates :short_text, length: {maximum: 255}
end
diff --git a/spec/dummy_app/app/mongoid/team.rb b/spec/dummy_app/app/mongoid/team.rb
index 3281fe5524..190c567d14 100644
--- a/spec/dummy_app/app/mongoid/team.rb
+++ b/spec/dummy_app/app/mongoid/team.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
class Team
diff --git a/spec/dummy_app/package.json b/spec/dummy_app/package.json
index 19d9c2c706..348aedd3ea 100644
--- a/spec/dummy_app/package.json
+++ b/spec/dummy_app/package.json
@@ -3,6 +3,8 @@
"private": true,
"version": "0.1.0",
"dependencies": {
+ "@babel/plugin-proposal-private-methods": "^7.18.6",
+ "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@rails/actiontext": "^7.0.3-1",
"@rails/activestorage": "^7.0.3-1",
"@rails/webpacker": "5.4.3",
diff --git a/spec/factories.rb b/spec/factories.rb
index c28bf291a4..0e1bbe8a32 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
FactoryBot.define do
diff --git a/spec/integration/actions/history_index_spec.rb b/spec/integration/actions/history_index_spec.rb
index f3d2048739..58cbe70430 100644
--- a/spec/integration/actions/history_index_spec.rb
+++ b/spec/integration/actions/history_index_spec.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
require 'spec_helper'
diff --git a/spec/integration/actions/history_show_spec.rb b/spec/integration/actions/history_show_spec.rb
index f9c185357c..d1b3462550 100644
--- a/spec/integration/actions/history_show_spec.rb
+++ b/spec/integration/actions/history_show_spec.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
require 'spec_helper'
diff --git a/spec/integration/actions/index_spec.rb b/spec/integration/actions/index_spec.rb
index 2da0cc05c9..44ba1d44ca 100644
--- a/spec/integration/actions/index_spec.rb
+++ b/spec/integration/actions/index_spec.rb
@@ -1,4 +1,3 @@
-# coding: utf-8
# frozen_string_literal: true
require 'spec_helper'
diff --git a/spec/integration/rails_admin_spec.rb b/spec/integration/rails_admin_spec.rb
index bb6ccc37f9..8040dcc826 100644
--- a/spec/integration/rails_admin_spec.rb
+++ b/spec/integration/rails_admin_spec.rb
@@ -206,6 +206,13 @@
end
end
+ describe 'dom_ready events', js: true do
+ it 'trigger properly' do
+ visit dashboard_path
+ expect(evaluate_script('domReadyTriggered')).to match_array %w[plainjs/dot jquery/dot]
+ end
+ end
+
context 'with invalid model name' do
it "redirects to dashboard and inform the user the model wasn't found" do
visit '/admin/whatever'
diff --git a/spec/rails_admin/adapters/active_record/association_spec.rb b/spec/rails_admin/adapters/active_record/association_spec.rb
index d0b1cc5bc4..2d24126ca2 100644
--- a/spec/rails_admin/adapters/active_record/association_spec.rb
+++ b/spec/rails_admin/adapters/active_record/association_spec.rb
@@ -215,6 +215,18 @@ class FieldTestWithSymbolForeignKey < FieldTest
expect(@category.associations.detect { |a| a.name == :librarian }.klass).to eq [ARUser]
expect(@blog.associations.detect { |a| a.name == :librarian }.klass).to eq [ARProfile]
end
+
+ describe 'on a subclass' do
+ before do
+ class ARReview < ARComment; end
+ allow(RailsAdmin::Config).to receive(:models_pool).and_return(%w[ARBlog ARPost ARCategory ARUser ARProfile ARComment ARReview])
+ end
+ subject { RailsAdmin::AbstractModel.new(ARReview).associations.detect { |a| a.name == :commentable } }
+
+ it 'returns correct target klasses' do
+ expect(subject.klass).to eq [ARBlog, ARPost]
+ end
+ end
end
describe 'polymorphic inverse has_many association' do
diff --git a/spec/rails_admin/adapters/active_record_spec.rb b/spec/rails_admin/adapters/active_record_spec.rb
index b2b5eb6cbd..b91427f00b 100644
--- a/spec/rails_admin/adapters/active_record_spec.rb
+++ b/spec/rails_admin/adapters/active_record_spec.rb
@@ -575,9 +575,47 @@ def build_statement(type, value, operator)
end
end
- it 'supports uuid type query' do
- uuid = SecureRandom.uuid
- expect(build_statement(:uuid, uuid, nil)).to eq(['(field = ?)', uuid])
+ describe 'uuid type queries' do
+ it 'supports uuid type query' do
+ uuid = SecureRandom.uuid
+ expect(build_statement(:uuid, uuid, nil)).to eq(['(field = ?)', uuid])
+ end
+
+ it "supports '_blank' operator" do
+ [['_blank', ''], ['', '_blank']].each do |value, operator|
+ expect(build_statement(:uuid, value, operator)).to eq(['(field IS NULL)'])
+ end
+ end
+
+ it "supports '_present' operator" do
+ [['_present', ''], ['', '_present']].each do |value, operator|
+ expect(build_statement(:uuid, value, operator)).to eq(['(field IS NOT NULL)'])
+ end
+ end
+
+ it "supports '_null' operator" do
+ [['_null', ''], ['', '_null']].each do |value, operator|
+ expect(build_statement(:uuid, value, operator)).to eq(['(field IS NULL)'])
+ end
+ end
+
+ it "supports '_not_null' operator" do
+ [['_not_null', ''], ['', '_not_null']].each do |value, operator|
+ expect(build_statement(:uuid, value, operator)).to eq(['(field IS NOT NULL)'])
+ end
+ end
+
+ it "supports '_empty' operator" do
+ [['_empty', ''], ['', '_empty']].each do |value, operator|
+ expect(build_statement(:uuid, value, operator)).to eq(['(field IS NULL)'])
+ end
+ end
+
+ it "supports '_not_empty' operator" do
+ [['_not_empty', ''], ['', '_not_empty']].each do |value, operator|
+ expect(build_statement(:uuid, value, operator)).to eq(['(field IS NOT NULL)'])
+ end
+ end
end
end
diff --git a/spec/rails_admin/adapters/mongoid/association_spec.rb b/spec/rails_admin/adapters/mongoid/association_spec.rb
index 0bde4f1b30..94e8004f76 100644
--- a/spec/rails_admin/adapters/mongoid/association_spec.rb
+++ b/spec/rails_admin/adapters/mongoid/association_spec.rb
@@ -168,6 +168,18 @@ class MongoNote
expect(subject.read_only?).to be_falsey
expect(subject.nested_options).to be_nil
end
+
+ describe 'on a subclass' do
+ before do
+ class MongoReview < MongoComment; end
+ allow(RailsAdmin::Config).to receive(:models_pool).and_return(%w[MongoBlog MongoPost MongoCategory MongoUser MongoProfile MongoComment MongoReview])
+ end
+ subject { RailsAdmin::AbstractModel.new(MongoReview).associations.detect { |a| a.name == :commentable } }
+
+ it 'returns correct target klasses' do
+ expect(subject.klass).to eq [MongoBlog, MongoPost]
+ end
+ end
end
describe 'polymorphic inverse has_many association' do
diff --git a/spec/rails_admin/config/fields/types/multiple_carrierwave_spec.rb b/spec/rails_admin/config/fields/types/multiple_carrierwave_spec.rb
index 5c1d3ef627..979d3110c8 100644
--- a/spec/rails_admin/config/fields/types/multiple_carrierwave_spec.rb
+++ b/spec/rails_admin/config/fields/types/multiple_carrierwave_spec.rb
@@ -8,7 +8,6 @@
describe '#thumb_method' do
before do
- allow_any_instance_of(CarrierwaveUploader).to receive(:cache!)
RailsAdmin.config FieldTest do
field :carrierwave_assets, :multiple_carrierwave
end
diff --git a/spec/rails_admin/config/model_spec.rb b/spec/rails_admin/config/model_spec.rb
index cd84084b26..c3e6534231 100644
--- a/spec/rails_admin/config/model_spec.rb
+++ b/spec/rails_admin/config/model_spec.rb
@@ -11,8 +11,21 @@
end
it 'returns false when included, true otherwise' do
- expect(RailsAdmin.config(Player).excluded?).to be_truthy
- expect(RailsAdmin.config(Comment).excluded?).to be_falsey
+ allow(RailsAdmin::AbstractModel).to receive(:all).and_call_original
+
+ player_config = RailsAdmin.config(Player)
+ expect(player_config.excluded?).to be_truthy
+ expect(RailsAdmin::AbstractModel).to have_received(:all).once
+ # Calling a second time uses the cached value.
+ expect(player_config.excluded?).to be_truthy
+ expect(RailsAdmin::AbstractModel).to have_received(:all).once
+
+ comment_config = RailsAdmin.config(Comment)
+ expect(comment_config.excluded?).to be_falsey
+ expect(RailsAdmin::AbstractModel).to have_received(:all).twice
+ # Calling a second time uses the cached value.
+ expect(comment_config.excluded?).to be_falsey
+ expect(RailsAdmin::AbstractModel).to have_received(:all).twice
end
end
diff --git a/spec/rails_admin/config_spec.rb b/spec/rails_admin/config_spec.rb
index cabae96792..9b075ac7b4 100644
--- a/spec/rails_admin/config_spec.rb
+++ b/spec/rails_admin/config_spec.rb
@@ -264,6 +264,14 @@ class RecursivelyEmbedsMany
it 'includes models in the directory added by config.eager_load_paths' do
expect(RailsAdmin::Config.models_pool).to include('Basketball')
end
+
+ it 'should include a model which was configured explicitly' do
+ RailsAdmin::Config.model 'PaperTrail::Version' do
+ visible false
+ end
+
+ expect(RailsAdmin::Config.models_pool).to include('PaperTrail::Version')
+ end
end
describe '.parent_controller' do
diff --git a/spec/rails_admin/support/csv_converter_spec.rb b/spec/rails_admin/support/csv_converter_spec.rb
index c5a4c418db..21be44fe65 100644
--- a/spec/rails_admin/support/csv_converter_spec.rb
+++ b/spec/rails_admin/support/csv_converter_spec.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
require 'spec_helper'
diff --git a/spec/rails_admin/support/datetime_spec.rb b/spec/rails_admin/support/datetime_spec.rb
index 1c915629cd..27bfe757e5 100644
--- a/spec/rails_admin/support/datetime_spec.rb
+++ b/spec/rails_admin/support/datetime_spec.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
require 'spec_helper'
@@ -14,6 +13,7 @@
'%Y-%m-%dT%H:%M:%S%:z' => 'Y-m-d\TH:i:S+00:00',
'%HH%MM%SS' => 'H\Hi\MS\S',
'a%-Ha%-Ma%-Sa%:za' => '\aH\ai\as\a+00:00\a',
+ '%B %-d at %-l:%M %p' => 'F j \a\t h:i K',
}.each do |strftime_format, flatpickr_format|
it "convert strftime_format to flatpickr_format - example #{strftime_format}" do
expect(RailsAdmin::Support::Datetime.to_flatpickr_format(strftime_format)).to eq flatpickr_format
diff --git a/spec/rails_admin/support/hash_helper_spec.rb b/spec/rails_admin/support/hash_helper_spec.rb
index 8e828d521e..52e52c7d10 100644
--- a/spec/rails_admin/support/hash_helper_spec.rb
+++ b/spec/rails_admin/support/hash_helper_spec.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
require 'spec_helper'
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index bb0da02c86..96846770d8 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# Configure Rails Envinronment
+# Configure Rails Environment
ENV['RAILS_ENV'] = 'test'
CI_ORM = (ENV['CI_ORM'] || :active_record).to_sym
CI_TARGET_ORMS = %i[active_record mongoid].freeze
diff --git a/src/rails_admin/base.js b/src/rails_admin/base.js
index 49020f81cc..ff7bba76cc 100644
--- a/src/rails_admin/base.js
+++ b/src/rails_admin/base.js
@@ -1,6 +1,6 @@
import Rails from "@rails/ujs";
import "@hotwired/turbo-rails";
-import jQuery from "jquery";
+import "./jquery";
import "./vendor/jquery_nested_form";
import "bootstrap";
@@ -27,4 +27,3 @@ import "./ui";
import "./widgets";
Rails.start();
-window.$ = window.jQuery = jQuery;
diff --git a/src/rails_admin/jquery.js b/src/rails_admin/jquery.js
new file mode 100644
index 0000000000..40a3ce4f74
--- /dev/null
+++ b/src/rails_admin/jquery.js
@@ -0,0 +1,3 @@
+import jQuery from "jquery";
+
+window.$ = window.jQuery = jQuery;
diff --git a/src/rails_admin/ui.js b/src/rails_admin/ui.js
index 3fcb4030cd..243e7b59aa 100644
--- a/src/rails_admin/ui.js
+++ b/src/rails_admin/ui.js
@@ -88,7 +88,7 @@ import I18n from "./i18n";
$(document).ready(triggerDomReady);
document.addEventListener("turbo:render", triggerDomReady);
- document.addEventListener("rails_admin.dom_ready", function () {
+ document.addEventListener("rails_admin.dom_ready", function (event) {
$(".nav.nav-pills li.active").removeClass("active");
$(
'.nav.nav-pills li[data-model="' + $(".page-header").data("model") + '"]'
@@ -129,6 +129,12 @@ import I18n from "./i18n";
$("a[data-method]").on("click", function (event) {
window.Turbo.session.drive = false;
});
+
+ // Trigger via jQuery for compatibility with existing user codes
+ $(document).trigger(
+ "rails_admin.dom_ready",
+ event.detail ? [event.detail] : null
+ );
});
$(document).on("click", ".bulk-link", function (event) {
diff --git a/vendor/assets/images/rails_admin/bootstrap/glyphicons-halflings-white.png b/vendor/assets/images/rails_admin/bootstrap/glyphicons-halflings-white.png
deleted file mode 100755
index 2cb5a5833c..0000000000
Binary files a/vendor/assets/images/rails_admin/bootstrap/glyphicons-halflings-white.png and /dev/null differ
diff --git a/vendor/assets/images/rails_admin/bootstrap/glyphicons-halflings.png b/vendor/assets/images/rails_admin/bootstrap/glyphicons-halflings.png
deleted file mode 100644
index f241c76f9a..0000000000
Binary files a/vendor/assets/images/rails_admin/bootstrap/glyphicons-halflings.png and /dev/null differ