administrate-field-nested_has_many 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -2
  3. data/.ruby-version +1 -1
  4. data/Appraisals +2 -6
  5. data/CHANGELOG.md +37 -0
  6. data/CODE_OF_CONDUCT.md +6 -0
  7. data/CONTRIBUTING.md +38 -0
  8. data/LICENSE.md +21 -0
  9. data/README.md +38 -1
  10. data/SECURITY.md +16 -0
  11. data/administrate-field-nested_has_many.gemspec +2 -3
  12. data/app/views/fields/nested_has_many/_show.html.erb +35 -6
  13. data/bin/build-changelog +24 -0
  14. data/bin/setup +13 -0
  15. data/config/locales/administrate-field-nested_has_many.de.yml +7 -0
  16. data/config/locales/administrate-field-nested_has_many.fr.yml +7 -0
  17. data/gemfiles/{administrate_0.10.gemfile → administrate_0.19.gemfile} +1 -1
  18. data/gemfiles/administrate_0.19.gemfile.lock +260 -0
  19. data/lib/administrate/field/nested_has_many.rb +33 -15
  20. data/spec/dummy/Rakefile +1 -1
  21. data/spec/dummy/app/dashboards/school_dashboard.rb +1 -1
  22. data/spec/dummy/app/models/school.rb +1 -1
  23. data/spec/dummy/bin/rails +2 -2
  24. data/spec/dummy/bin/rake +2 -2
  25. data/spec/dummy/bin/setup +6 -9
  26. data/spec/dummy/config/application.rb +12 -9
  27. data/spec/dummy/config/boot.rb +1 -1
  28. data/spec/dummy/config/environment.rb +1 -1
  29. data/spec/dummy/config/environments/development.rb +16 -4
  30. data/spec/dummy/config/environments/test.rb +19 -6
  31. data/spec/dummy/config/initializers/backtrace_silencers.rb +4 -3
  32. data/spec/dummy/config/initializers/content_security_policy.rb +3 -0
  33. data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
  34. data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
  35. data/spec/dummy/config/locales/en.yml +1 -1
  36. data/spec/dummy/config/puma.rb +13 -4
  37. data/spec/dummy/config/routes.rb +1 -0
  38. data/spec/dummy/config.ru +2 -1
  39. data/spec/dummy/db/schema.rb +10 -6
  40. data/spec/features/has_many_spec.rb +37 -0
  41. metadata +24 -42
  42. data/app/views/fields/nested_has_many/_show_current.html.erb +0 -44
  43. data/app/views/fields/nested_has_many/_show_old.html.erb +0 -36
  44. data/gemfiles/administrate_0.10.gemfile.lock +0 -214
  45. data/gemfiles/administrate_master.gemfile +0 -8
  46. data/gemfiles/administrate_master.gemfile.lock +0 -219
  47. data/spec/dummy/app/mailers/application_mailer.rb +0 -4
  48. data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
  49. data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
  50. data/spec/dummy/config/cable.yml +0 -10
  51. data/spec/dummy/config/storage.yml +0 -34
@@ -15,6 +15,13 @@ module Administrate
15
15
  Administrate::Engine.add_stylesheet(
16
16
  "administrate-field-nested_has_many/application",
17
17
  )
18
+
19
+ initializer "administrate-field-nested_has_many.assets.precompile" do |app|
20
+ app.config.assets.precompile += [
21
+ "administrate-field-nested_has_many/application.js",
22
+ "administrate-field-nested_has_many/application.css",
23
+ ]
24
+ end
18
25
  end
19
26
 
20
27
  DEFAULT_ATTRIBUTES = %i(id _destroy).freeze
@@ -32,7 +39,7 @@ module Administrate
32
39
  next if nested_field.resource.blank?
33
40
 
34
41
  # inject current data into field
35
- resource = nested_field.resource[form_builder.index]
42
+ resource = data[form_builder.index]
36
43
  nested_field.instance_variable_set(
37
44
  "@data",
38
45
  resource.send(nested_field.attribute),
@@ -44,40 +51,51 @@ module Administrate
44
51
  data
45
52
  end
46
53
 
47
- def self.dashboard_for_resource(resource, options)
48
- class_name = options && options[:class_name] || resource.to_s.classify
49
- "#{class_name}Dashboard".constantize
54
+ def self.dashboard_for_resource(resource_class, attr)
55
+ "#{associated_class_name(resource_class, attr)}Dashboard".constantize
50
56
  end
51
57
 
52
- def self.associated_attributes(associated_resource, options)
53
- dashboard_class = dashboard_for_resource(associated_resource, options)
58
+ def self.associated_attributes(resource_class, attr)
59
+ dashboard_class = dashboard_for_resource(resource_class, attr)
54
60
  DEFAULT_ATTRIBUTES + dashboard_class.new.permitted_attributes
55
61
  end
56
62
 
57
- def self.permitted_attribute(associated_resource, options = nil)
63
+ def self.permitted_attribute(attr, options = {})
64
+ given_class_name = options[:class_name]
65
+ _resource_class =
66
+ if given_class_name
67
+ Administrate.warn_of_deprecated_option(:class_name)
68
+ given_class_name.classify
69
+ else
70
+ options[:resource_class]
71
+ end
72
+
58
73
  {
59
- "#{associated_resource}_attributes".to_sym =>
60
- associated_attributes(associated_resource, options),
74
+ "#{attr}_attributes".to_sym =>
75
+ associated_attributes(_resource_class, attr),
61
76
  }
62
77
  end
63
78
 
64
79
  def associated_class_name
65
- options.fetch(:class_name, attribute.to_s.singularize.camelcase)
80
+ self.class.associated_class_name(resource.class, attribute)
66
81
  end
67
82
 
68
83
  def association_name
69
- options.fetch(
70
- :association_name,
71
- associated_class_name.underscore.pluralize[/([^\/]*)$/, 1],
72
- )
84
+ options.fetch(:association_name) do
85
+ associated_class_name.underscore.pluralize[/([^\/]*)$/, 1]
86
+ end
73
87
  end
74
88
 
75
89
  def associated_form
76
- Administrate::Page::Form.new(associated_dashboard, data)
90
+ Administrate::Page::Form.new(associated_dashboard, new_resource)
77
91
  end
78
92
 
79
93
  private
80
94
 
95
+ def new_resource
96
+ @new_resource ||= associated_class.new
97
+ end
98
+
81
99
  def skipped_fields
82
100
  Array(options[:skip])
83
101
  end
data/spec/dummy/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
2
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
3
 
4
- require_relative 'config/application'
4
+ require_relative "config/application"
5
5
 
6
6
  Rails.application.load_tasks
@@ -10,7 +10,7 @@ class SchoolDashboard < Administrate::BaseDashboard
10
10
  ATTRIBUTE_TYPES = {
11
11
  id: Field::Number,
12
12
  name: Field::String,
13
- students: Field::NestedHasMany.with_options(class_name: "Foo::Student"),
13
+ students: Field::NestedHasMany,
14
14
  created_at: Field::DateTime,
15
15
  updated_at: Field::DateTime,
16
16
  }.freeze
@@ -1,4 +1,4 @@
1
1
  class School < ApplicationRecord
2
2
  has_many :students, class_name: "Foo::Student"
3
- accepts_nested_attributes_for :students
3
+ accepts_nested_attributes_for :students, allow_destroy: true
4
4
  end
data/spec/dummy/bin/rails CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  APP_PATH = File.expand_path('../config/application', __dir__)
3
- require_relative '../config/boot'
4
- require 'rails/commands'
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
data/spec/dummy/bin/rake CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require_relative '../config/boot'
3
- require 'rake'
2
+ require_relative "../config/boot"
3
+ require "rake"
4
4
  Rake.application.run
data/spec/dummy/bin/setup CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require 'fileutils'
3
- include FileUtils
2
+ require "fileutils"
4
3
 
5
4
  # path to your application root.
6
5
  APP_ROOT = File.expand_path('..', __dir__)
@@ -9,24 +8,22 @@ def system!(*args)
9
8
  system(*args) || abort("\n== Command #{args} failed ==")
10
9
  end
11
10
 
12
- chdir APP_ROOT do
13
- # This script is a starting point to setup your application.
11
+ FileUtils.chdir APP_ROOT do
12
+ # This script is a way to set up or update your development environment automatically.
13
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14
14
  # Add necessary setup steps to this file.
15
15
 
16
16
  puts '== Installing dependencies =='
17
17
  system! 'gem install bundler --conservative'
18
18
  system('bundle check') || system!('bundle install')
19
19
 
20
- # Install JavaScript dependencies if using Yarn
21
- # system('bin/yarn')
22
-
23
20
  # puts "\n== Copying sample files =="
24
21
  # unless File.exist?('config/database.yml')
25
- # cp 'config/database.yml.sample', 'config/database.yml'
22
+ # FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
26
23
  # end
27
24
 
28
25
  puts "\n== Preparing database =="
29
- system! 'bin/rails db:setup'
26
+ system! 'bin/rails db:prepare'
30
27
 
31
28
  puts "\n== Removing old logs and tempfiles =="
32
29
  system! 'bin/rails log:clear tmp:clear'
@@ -1,18 +1,21 @@
1
- require_relative 'boot'
1
+ require_relative "boot"
2
2
 
3
- require 'rails/all'
3
+ require "rails/all"
4
4
 
5
+ # Require the gems listed in Gemfile, including any gems
6
+ # you've limited to :test, :development, or :production.
5
7
  Bundler.require(*Rails.groups)
6
8
 
7
9
  module Dummy
8
10
  class Application < Rails::Application
9
- # Initialize configuration defaults for originally generated Rails version.
10
- config.load_defaults 5.2
11
+ config.load_defaults Rails::VERSION::STRING.to_f
11
12
 
12
- # Settings in config/environments/* take precedence over those specified here.
13
- # Application configuration can go into files in config/initializers
14
- # -- all .rb files in that directory are automatically loaded after loading
15
- # the framework and any gems in your application.
13
+ # Configuration for the application, engines, and railties goes here.
14
+ #
15
+ # These settings can be overridden in specific environments using the files
16
+ # in config/environments, which are processed later.
17
+ #
18
+ # config.time_zone = "Central Time (US & Canada)"
19
+ # config.eager_load_paths << Rails.root.join("extras")
16
20
  end
17
21
  end
18
-
@@ -1,5 +1,5 @@
1
1
  # Set up gems listed in the Gemfile.
2
2
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
3
 
4
- require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
4
+ require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
5
5
  $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -1,5 +1,5 @@
1
1
  # Load the Rails application.
2
- require_relative 'application'
2
+ require_relative "application"
3
3
 
4
4
  # Initialize the Rails application.
5
5
  Rails.application.initialize!
@@ -1,8 +1,10 @@
1
+ require "active_support/core_ext/integer/time"
2
+
1
3
  Rails.application.configure do
2
4
  # Settings specified here will take precedence over those in config/application.rb.
3
5
 
4
- # In the development environment your application's code is reloaded on
5
- # every request. This slows down response time but is perfect for development
6
+ # In the development environment your application's code is reloaded any time
7
+ # it changes. This slows down response time but is perfect for development
6
8
  # since you don't have to restart the web server when you make code changes.
7
9
  config.cache_classes = false
8
10
 
@@ -16,6 +18,7 @@ Rails.application.configure do
16
18
  # Run rails dev:cache to toggle caching.
17
19
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
18
20
  config.action_controller.perform_caching = true
21
+ config.action_controller.enable_fragment_cache_logging = true
19
22
 
20
23
  config.cache_store = :memory_store
21
24
  config.public_file_server.headers = {
@@ -30,6 +33,12 @@ Rails.application.configure do
30
33
  # Print deprecation notices to the Rails logger.
31
34
  config.active_support.deprecation = :log
32
35
 
36
+ # Raise exceptions for disallowed deprecations.
37
+ config.active_support.disallowed_deprecation = :raise
38
+
39
+ # Tell Active Support which deprecation messages to disallow.
40
+ config.active_support.disallowed_deprecation_warnings = []
41
+
33
42
  # Raise an error on page load if there are pending migrations.
34
43
  config.active_record.migration_error = :page_load
35
44
 
@@ -44,8 +53,11 @@ Rails.application.configure do
44
53
  # Suppress logger output for asset requests.
45
54
  config.assets.quiet = true
46
55
 
47
- # Raises error for missing translations
48
- # config.action_view.raise_on_missing_translations = true
56
+ # Raises error for missing translations.
57
+ # config.i18n.raise_on_missing_translations = true
58
+
59
+ # Annotate rendered view with file names.
60
+ # config.action_view.annotate_rendered_view_with_filenames = true
49
61
 
50
62
  # Use an evented file watcher to asynchronously detect changes in source code,
51
63
  # routes, locales, etc. This feature depends on the listen gem.
@@ -1,10 +1,13 @@
1
+ require "active_support/core_ext/integer/time"
2
+
3
+ # The test environment is used exclusively to run your application's
4
+ # test suite. You never need to work with it otherwise. Remember that
5
+ # your test database is "scratch space" for the test suite and is wiped
6
+ # and recreated between test runs. Don't rely on the data there!
7
+
1
8
  Rails.application.configure do
2
9
  # Settings specified here will take precedence over those in config/application.rb.
3
10
 
4
- # The test environment is used exclusively to run your application's
5
- # test suite. You never need to work with it otherwise. Remember that
6
- # your test database is "scratch space" for the test suite and is wiped
7
- # and recreated between test runs. Don't rely on the data there!
8
11
  config.cache_classes = true
9
12
 
10
13
  # Do not eager load code on boot. This avoids loading your whole application
@@ -21,6 +24,7 @@ Rails.application.configure do
21
24
  # Show full error reports and disable caching.
22
25
  config.consider_all_requests_local = true
23
26
  config.action_controller.perform_caching = false
27
+ config.cache_store = :null_store
24
28
 
25
29
  # Raise exceptions instead of rendering exception templates.
26
30
  config.action_dispatch.show_exceptions = false
@@ -31,6 +35,15 @@ Rails.application.configure do
31
35
  # Print deprecation notices to the stderr.
32
36
  config.active_support.deprecation = :stderr
33
37
 
34
- # Raises error for missing translations
35
- # config.action_view.raise_on_missing_translations = true
38
+ # Raise exceptions for disallowed deprecations.
39
+ config.active_support.disallowed_deprecation = :raise
40
+
41
+ # Tell Active Support which deprecation messages to disallow.
42
+ config.active_support.disallowed_deprecation_warnings = []
43
+
44
+ # Raises error for missing translations.
45
+ # config.i18n.raise_on_missing_translations = true
46
+
47
+ # Annotate rendered view with file names.
48
+ # config.action_view.annotate_rendered_view_with_filenames = true
36
49
  end
@@ -1,7 +1,8 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
3
  # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
- # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
4
+ # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
5
5
 
6
- # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
- # Rails.backtrace_cleaner.remove_silencers!
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
7
+ # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
8
+ Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
@@ -19,6 +19,9 @@
19
19
  # If you are using UJS then enable automatic nonce generation
20
20
  # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
21
21
 
22
+ # Set the nonce only to specific directives
23
+ # Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
24
+
22
25
  # Report CSP violations to a specified URI
23
26
  # For further information see the following documentation:
24
27
  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
@@ -1,4 +1,6 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
3
  # Configure sensitive parameters which will be filtered from the log file.
4
- Rails.application.config.filter_parameters += [:password]
4
+ Rails.application.config.filter_parameters += [
5
+ :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
6
+ ]
@@ -0,0 +1,11 @@
1
+ # Define an application-wide HTTP permissions policy. For further
2
+ # information see https://developers.google.com/web/updates/2018/06/feature-policy
3
+ #
4
+ # Rails.application.config.permissions_policy do |f|
5
+ # f.camera :none
6
+ # f.gyroscope :none
7
+ # f.microphone :none
8
+ # f.usb :none
9
+ # f.fullscreen :self
10
+ # f.payment :self, "https://secure.example.com"
11
+ # end
@@ -27,7 +27,7 @@
27
27
  # 'true': 'foo'
28
28
  #
29
29
  # To learn more, please read the Rails Internationalization guide
30
- # available at http://guides.rubyonrails.org/i18n.html.
30
+ # available at https://guides.rubyonrails.org/i18n.html.
31
31
 
32
32
  en:
33
33
  hello: "Hello world"
@@ -4,19 +4,28 @@
4
4
  # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
5
  # and maximum; this matches the default thread size of Active Record.
6
6
  #
7
- threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8
- threads threads_count, threads_count
7
+ max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
8
+ min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
9
+ threads min_threads_count, max_threads_count
10
+
11
+ # Specifies the `worker_timeout` threshold that Puma will use to wait before
12
+ # terminating a worker in development environments.
13
+ #
14
+ worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
9
15
 
10
16
  # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11
17
  #
12
- port ENV.fetch("PORT") { 3000 }
18
+ port ENV.fetch("PORT") { 3000 }
13
19
 
14
20
  # Specifies the `environment` that Puma will run in.
15
21
  #
16
22
  environment ENV.fetch("RAILS_ENV") { "development" }
17
23
 
24
+ # Specifies the `pidfile` that Puma will use.
25
+ pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
26
+
18
27
  # Specifies the number of `workers` to boot in clustered mode.
19
- # Workers are forked webserver processes. If using threads and workers together
28
+ # Workers are forked web server processes. If using threads and workers together
20
29
  # the concurrency of the application would be max `threads` * `workers`.
21
30
  # Workers do not work on JRuby or Windows (both of which do not support
22
31
  # processes).
@@ -1,4 +1,5 @@
1
1
  Rails.application.routes.draw do
2
+ root to: redirect("/admin/schools")
2
3
  namespace :admin do
3
4
  root to: redirect("/admin/schools")
4
5
  resources :schools
data/spec/dummy/config.ru CHANGED
@@ -1,5 +1,6 @@
1
1
  # This file is used by Rack-based servers to start the application.
2
2
 
3
- require_relative 'config/environment'
3
+ require_relative "config/environment"
4
4
 
5
5
  run Rails.application
6
+ Rails.application.load_server
@@ -2,16 +2,19 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # Note that this schema.rb definition is the authoritative source for your
6
- # database schema. If you need to create the application database on another
7
- # system, you should be using db:schema:load, not running all the migrations
8
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
- # you'll amass, the slower it'll run and the greater likelihood for issues).
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
+ # be faster and is potentially less error prone than running all of your
8
+ # migrations from scratch. Old migrations may fail to apply correctly if those
9
+ # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
13
  ActiveRecord::Schema.define(version: 2018_09_07_104703) do
14
14
 
15
+ # These are extensions that must be enabled in order to support this database
16
+ enable_extension "plpgsql"
17
+
15
18
  create_table "schools", force: :cascade do |t|
16
19
  t.string "name"
17
20
  t.datetime "created_at", null: false
@@ -20,10 +23,11 @@ ActiveRecord::Schema.define(version: 2018_09_07_104703) do
20
23
 
21
24
  create_table "students", force: :cascade do |t|
22
25
  t.string "name"
23
- t.integer "school_id"
26
+ t.bigint "school_id"
24
27
  t.datetime "created_at", null: false
25
28
  t.datetime "updated_at", null: false
26
29
  t.index ["school_id"], name: "index_students_on_school_id"
27
30
  end
28
31
 
32
+ add_foreign_key "students", "schools"
29
33
  end
@@ -19,6 +19,16 @@ feature "Has many" do
19
19
  expect(page).to have_content("John Doe")
20
20
  end
21
21
 
22
+ scenario "pagination" do
23
+ FactoryBot.create_list(:student, 10, school: school)
24
+
25
+ visit admin_school_path(school)
26
+
27
+ expect(page.html).to have_css("nav[role=navigation]")
28
+ expect(page.html).to have_content("Last")
29
+ expect(page.html).to have_content("Next")
30
+ end
31
+
22
32
  scenario "new" do
23
33
  visit new_admin_school_path
24
34
  expect(page).to have_content("New Schools")
@@ -38,4 +48,31 @@ feature "Has many" do
38
48
  expect(page).to have_text("La Ferme du Bec Hellouin")
39
49
  expect(page).to have_text("Sébastien")
40
50
  end
51
+
52
+ scenario "edit" do
53
+ school = FactoryBot.create(:school)
54
+ FactoryBot.create_list(:student, 2, school: school)
55
+ visit edit_admin_school_path(school)
56
+ expect(page).to have_content("Edit #{school.name}")
57
+ end
58
+
59
+ scenario "update", js: true do
60
+ school = FactoryBot.create(:school)
61
+ student = FactoryBot.create(:student, school: school)
62
+ visit edit_admin_school_path(school)
63
+ click_link "Add Foo/Student"
64
+
65
+ within(all(".nested-fields").last) do
66
+ fill_in "Name", with: "Sébastien"
67
+ end
68
+
69
+ within(all(".nested-fields").first) do
70
+ click_link "Remove Foo/Student"
71
+ end
72
+
73
+ click_button "Update School"
74
+
75
+ expect(page).to have_text("Sébastien")
76
+ expect(page).not_to have_text(student.name)
77
+ end
41
78
  end