hyrax 5.1.0.pre.beta1 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.dassie/.env +4 -0
  3. data/.dassie/Gemfile +12 -7
  4. data/.dassie/app/controllers/application_controller.rb +4 -0
  5. data/.dassie/app/helpers/hyrax_helper.rb +4 -0
  6. data/.dassie/app/models/ability.rb +4 -0
  7. data/.dassie/app/models/user.rb +11 -0
  8. data/.dassie/app/views/shared/_footer.html.erb +17 -0
  9. data/.dassie/config/application.rb +1 -1
  10. data/.dassie/config/database.yml +18 -0
  11. data/.dassie/config/environments/production.rb +1 -1
  12. data/.dassie/config/fedora.yml +6 -6
  13. data/.dassie/config/initializers/devise.rb +1 -0
  14. data/.dassie/config/initializers/profiler.rb +5 -0
  15. data/.dassie/config/locales/hyrax.en.yml +1 -1
  16. data/.dassie/config/puma.rb +55 -5
  17. data/.dassie/config/routes.rb +2 -0
  18. data/.dassie/db/migrate/20250328100249_user_roles.rb +20 -0
  19. data/.dassie/db/schema.rb +123 -109
  20. data/.github/workflows/lint-build-test.yml +34 -5
  21. data/.koppie/.env +1 -1
  22. data/.koppie/Gemfile +10 -6
  23. data/.koppie/app/controllers/application_controller.rb +4 -0
  24. data/.koppie/app/helpers/hyrax_helper.rb +4 -0
  25. data/.koppie/app/models/ability.rb +4 -0
  26. data/.koppie/app/models/user.rb +10 -0
  27. data/.koppie/app/views/shared/_footer.html.erb +17 -0
  28. data/.koppie/config/database.yml +2 -9
  29. data/.koppie/config/environments/development.rb +9 -0
  30. data/.koppie/config/environments/production.rb +1 -1
  31. data/.koppie/config/initializers/1_valkyrie.rb +5 -5
  32. data/.koppie/config/initializers/devise.rb +1 -1
  33. data/.koppie/config/initializers/profiler.rb +5 -0
  34. data/.koppie/config/locales/hyrax.en.yml +2 -2
  35. data/.koppie/config/puma.rb +26 -7
  36. data/.koppie/config/routes.rb +2 -0
  37. data/.koppie/db/schema.rb +109 -110
  38. data/CONTAINERS.md +10 -10
  39. data/Dockerfile +108 -50
  40. data/Gemfile +2 -1
  41. data/app/controllers/concerns/hyrax/valkyrie_downloads_controller_behavior.rb +1 -0
  42. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +2 -1
  43. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +4 -4
  44. data/app/controllers/hyrax/file_sets_controller.rb +11 -0
  45. data/app/helpers/hyrax/hyrax_helper_behavior.rb +2 -2
  46. data/app/helpers/hyrax/trophy_helper.rb +1 -1
  47. data/app/jobs/concerns/hyrax/queued_job_behavior.rb +22 -0
  48. data/app/jobs/hyrax/propagate_change_depositor_job.rb +1 -1
  49. data/app/jobs/hyrax/queued_delete_job.rb +11 -0
  50. data/app/jobs/hyrax/queued_indexing_job.rb +11 -0
  51. data/app/jobs/migrate_files_to_valkyrie_job.rb +33 -21
  52. data/app/jobs/migrate_sipity_entity_job.rb +21 -0
  53. data/app/models/concerns/hyrax/ability.rb +4 -2
  54. data/app/models/concerns/hyrax/solr_document_behavior.rb +5 -2
  55. data/app/models/hyrax/file_metadata.rb +22 -7
  56. data/app/services/hyrax/analytics/ga4/base.rb +1 -1
  57. data/app/services/hyrax/analytics/ga4.rb +5 -1
  58. data/app/services/hyrax/change_depositor_service.rb +1 -1
  59. data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +21 -13
  60. data/app/services/hyrax/custom_queries/find_ids_by_model.rb +31 -6
  61. data/app/services/hyrax/edit_permissions_service.rb +9 -8
  62. data/app/services/hyrax/workflow/workflow_factory.rb +3 -3
  63. data/app/services/migrate_resource_service.rb +1 -1
  64. data/app/views/_user_util_links.html.erb +2 -1
  65. data/app/views/hyrax/admin/analytics/collection_reports/_top_collections.html.erb +3 -7
  66. data/app/views/hyrax/admin/analytics/work_reports/_top_file_set_downloads.html.erb +3 -6
  67. data/app/views/hyrax/admin/analytics/work_reports/_top_works.html.erb +2 -3
  68. data/app/views/hyrax/admin/analytics/work_reports/_work_files.html.erb +1 -6
  69. data/app/views/hyrax/base/_social_media.html.erb +2 -0
  70. data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +1 -1
  71. data/app/views/hyrax/dashboard/collections/_show_document_list_menu.html.erb +13 -12
  72. data/app/views/hyrax/my/_admin_set_action_menu.html.erb +31 -27
  73. data/app/views/hyrax/my/_collection_action_menu.html.erb +40 -35
  74. data/app/views/hyrax/my/_work_action_menu.html.erb +23 -22
  75. data/bin/db-migrate-seed.sh +1 -1
  76. data/bin/dev-entrypoint.sh +3 -0
  77. data/config/features.rb +50 -40
  78. data/config/initializers/indexing_adapter_initializer.rb +4 -0
  79. data/config/initializers/new_framework_defaults_7_2.rb +6 -4
  80. data/config/initializers/reform_rails_6_1_monkey_patch.rb +29 -0
  81. data/config/metadata/core_metadata.yaml +1 -0
  82. data/docker-compose-dassie.yml +6 -6
  83. data/docker-compose-koppie.yml +2 -2
  84. data/docker-compose-sirenia.yml +2 -2
  85. data/documentation/developing-your-hyrax-based-app.md +2 -2
  86. data/hyrax.gemspec +3 -3
  87. data/lib/freyja/persister.rb +11 -4
  88. data/lib/generators/hyrax/install_generator.rb +0 -5
  89. data/lib/generators/hyrax/templates/.env +1 -1
  90. data/lib/generators/hyrax/templates/config/initializers/1_valkyrie.rb +21 -19
  91. data/lib/generators/hyrax/templates/db/migrate/20170131142607_add_permission_template_to_sipity_workflow.rb.erb +1 -1
  92. data/lib/generators/hyrax/templates/db/migrate/20170810190549_update_collection_type_column_options.rb.erb +1 -1
  93. data/lib/generators/hyrax/templates/db/migrate/20230821153635_add_fields_to_counter_metric.rb.erb +1 -1
  94. data/lib/hyrax/configuration.rb +22 -7
  95. data/lib/hyrax/controlled_vocabulary/importer/language.rb +5 -1
  96. data/lib/hyrax/transactions/steps/add_file_sets.rb +2 -1
  97. data/lib/hyrax/version.rb +1 -1
  98. data/lib/hyrax.rb +1 -0
  99. data/lib/tasks/workflow.rake +1 -2
  100. data/lib/valkyrie/indexing/redis_queue/indexing_adapter.rb +144 -0
  101. data/lib/wings/valkyrie/query_service.rb +3 -4
  102. data/template.rb +1 -1
  103. metadata +28 -14
  104. data/.github/workflows/main.yml +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08508f785d195263cfe808e128a93f0144a0da56aa7e8d5fbd08a1ddd543c448'
4
- data.tar.gz: 0e64095cd09810042c20ade46070ae392a4c0506c14acf5ea99e5fc9453ec8e9
3
+ metadata.gz: 9e0fb614fbcdcb0a429b210b32a8784d0d173f3fe226cce143be9905031b6d75
4
+ data.tar.gz: 87d6ed549b2e8fb4295feb681ea5696f9ad25f511e2da655f0957b195688a751
5
5
  SHA512:
6
- metadata.gz: c7d0e18940b7243f192e9d03c8b59b7918aed1fbead26089a92471731c7affe71dd4a82d1d750ceac28c3577ef75c904eb0255f6ced70453be8433639ba51a8e
7
- data.tar.gz: c76473bb4d5b0f8fc7ab8c795aa2f8f44f392c5f9e6f423767375c5218b4afec97608e40ebb67b232eb9d4e1ae8158e73726f3932e95912bab699bf58dc56cac
6
+ metadata.gz: 44689f87eaf8cdf5089f6fef0eb9f84a8b3a38c5e92dd91984465bb7a4c7ca4a740fb6aecef0f97bab5d207db4a42be8db4ca086e09320dbb28110dc279eaf5a
7
+ data.tar.gz: abaab63cb2a1647f9b72c9e2bf8222dc76a9d48d3e58123636481b285fec9e67b4164b5bcabe68e03cb90fe26a64595d77218d7e21248ced8bba363c9fe1505a
data/.dassie/.env CHANGED
@@ -1,4 +1,5 @@
1
1
  ANALYTICS_START_DATE=2021-08-21
2
+ APP_NAME=dassie
2
3
  BUNDLE_GEMFILE=Gemfile.dassie
3
4
  BUNDLE_PATH=/app/bundle
4
5
  CH12N_TOOL=fits_servlet
@@ -38,7 +39,10 @@ SOLR_TEST_URL=http://solr:8983/solr/hyrax_test
38
39
  SOLR_URL=http://solr:8983/solr/hyrax
39
40
  TB_RSPEC_OPTIONS=--force-color --format RspecJunitFormatter --out rspec.xml
40
41
  TB_RSPEC_FORMATTER=progress
42
+ VALKYRIE_FCREPO_URL=http://fedoraAdmin:fedoraAdmin@fedora6:8080/fcrepo/rest
41
43
  VALKYRIE_ID_TYPE=string
44
+ VALKYRIE_METADATA_ADAPTER=pg_metadata
42
45
  VALKYRIE_SOLR_HOST=solr
43
46
  VALKYRIE_SOLR_PORT=8983
47
+ VALKYRIE_STORAGE_ADAPTER=versioned_disk_storage
44
48
  VALKYRIE_TRANSITION=false
data/.dassie/Gemfile CHANGED
@@ -19,24 +19,29 @@ gem 'devise-guests', '~> 0.8'
19
19
  # To install the package in Alpine: `apk add ruby-grpc`
20
20
  # The pinned versions should match the version provided by the Alpine packages.
21
21
 
22
- # Disabled due to dependency mismatches in Alpine packages (grpc 1.62.1 needs protobuf ~> 3.25)
23
- # if RUBY_PLATFORM =~ /musl/
22
+
23
+ if RUBY_PLATFORM =~ /musl/
24
+ # # Disabled due to dependency mismatches in Alpine packages (grpc 1.62.1 needs protobuf ~> 3.25)
24
25
  # path '/usr/lib/ruby/gems/3.3.0' do
25
- # gem 'google-protobuf', '~> 3.24.4', force_ruby_platform: true
26
- # gem 'grpc', '~> 1.62.1', force_ruby_platform: true
26
+ gem 'google-protobuf', force_ruby_platform: true
27
+ gem 'grpc', force_ruby_platform: true
27
28
  # end
28
- # end
29
+ end
29
30
 
31
+ gem 'hydra-role-management'
30
32
  gemspec name: 'hyrax', path: ENV.fetch('HYRAX_ENGINE_PATH', '..')
31
33
  gem 'jbuilder', '~> 2.5'
32
34
  gem 'jquery-rails'
35
+ gem 'okcomputer'
33
36
  gem 'pg', '~> 1.3'
34
37
  gem 'puma'
35
- gem 'rails', '~> 7.2', '< 8.0'
38
+ gem 'rack-mini-profiler', require: ['prepend_net_http_patch']
39
+ gem 'rails', '6.1.7.10'
36
40
  gem 'riiif', '~> 2.1'
37
41
  gem 'rsolr', '>= 1.0', '< 3'
38
42
  gem 'sass-rails', '~> 6.0'
39
- gem 'sidekiq', '~> 6.4'
43
+ gem 'sidekiq', '~> 7.0'
44
+ gem 'stackprof', require: false
40
45
  gem 'turbolinks', '~> 5'
41
46
  gem 'twitter-typeahead-rails', '0.11.1.pre.corejavascript'
42
47
  gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
@@ -9,4 +9,8 @@ class ApplicationController < ActionController::Base
9
9
  include Hyrax::ThemedLayoutController
10
10
 
11
11
  with_themed_layout '1_column'
12
+
13
+ before_action do
14
+ Rack::MiniProfiler.authorize_request if current_user&.admin?
15
+ end
12
16
  end
@@ -3,4 +3,8 @@ module HyraxHelper
3
3
  include ::BlacklightHelper
4
4
  include Hyrax::BlacklightOverride
5
5
  include Hyrax::HyraxHelperBehavior
6
+
7
+ def application_name
8
+ ENV.fetch('APP_NAME') { super }.titleize
9
+ end
6
10
  end
@@ -17,5 +17,9 @@ class Ability
17
17
  # if user_groups.include? 'special_group'
18
18
  # can [:create], ActiveFedora::Base
19
19
  # end
20
+
21
+ if current_user.admin?
22
+ can [:create, :show, :add_user, :remove_user, :index, :edit, :update, :destroy], Role
23
+ end
20
24
  end
21
25
  end
@@ -1,6 +1,10 @@
1
1
  class User < ApplicationRecord
2
2
  # Connects this user object to Hydra behaviors.
3
3
  include Hydra::User
4
+
5
+ # Connects this user object to Role-management behaviors.
6
+ include Hydra::RoleManagement::UserRoles
7
+
4
8
  # Connects this user object to Hyrax behaviors.
5
9
  include Hyrax::User
6
10
  include Hyrax::UserUsageStats
@@ -18,4 +22,11 @@ class User < ApplicationRecord
18
22
  def to_s
19
23
  email
20
24
  end
25
+
26
+ # Groups include roles and those set by #groups= (especially in specs)
27
+ def groups
28
+ g = roles.map(&:name)
29
+ g += group_service.fetch_groups(user: self)
30
+ g
31
+ end
21
32
  end
@@ -0,0 +1,17 @@
1
+ <footer class="navbar navbar-dark bg-dark site-footer">
2
+ <div class="container-fluid">
3
+ <div class="navbar-text text-left">
4
+ <p><%= t('hyrax.footer.service_html') %> <%= t('hyrax.product_name') %> v<%= Hyrax::VERSION %></p>
5
+ <p>Commit <%= link_to ENV.fetch('BUILD_GITSHA', "Unknown")[0..6],
6
+ "https://github.com/samvera/hyrax/commit/#{ENV.fetch('BUILD_GITSHA', 'main')}" %>
7
+ Built at <%= ENV.fetch('BUILD_TIMESTAMP', 'Unknown') %>
8
+ </p>
9
+ </div>
10
+ <div class="navbar-right">
11
+ <div class="navbar-text text-right">
12
+ <p><%= t('hyrax.footer.copyright_html', current_year: Time.current.year) %></p>
13
+ <p><%= t('hyrax.background_attribution_html') %></p>
14
+ </div>
15
+ </div>
16
+ </div>
17
+ </footer>
@@ -9,7 +9,7 @@ Bundler.require(*Rails.groups)
9
9
  module Dassie
10
10
  class Application < Rails::Application
11
11
  # Initialize configuration defaults for originally generated Rails version.
12
- config.load_defaults 7.2
12
+ config.load_defaults 6.1
13
13
  config.add_autoload_paths_to_load_path = true
14
14
 
15
15
  # Settings in config/environments/* take precedence over those specified here.
@@ -0,0 +1,18 @@
1
+ default: &default
2
+ adapter: postgresql
3
+ url: <%= ENV.fetch('DATABASE_URL') %>
4
+
5
+ development:
6
+ <<: *default
7
+
8
+ # Warning: The database defined as "test" will be erased and
9
+ # re-generated from your development database when you run "rake".
10
+ # Do not set this db to the same as development or production.
11
+ test:
12
+ <<: *default
13
+ url: <%= ENV.fetch('DATABASE_TEST_URL') { ENV.fetch('DATABASE_URL') } %>
14
+
15
+ production:
16
+ <<: *default
17
+ encoding: unicode
18
+ pool: 50
@@ -53,7 +53,7 @@ Rails.application.configure do
53
53
 
54
54
  # Use the lowest log level to ensure availability of diagnostic information
55
55
  # when problems arise.
56
- config.log_level = :debug
56
+ config.log_level = ENV.fetch("RAILS_LOG_LEVEL", :debug).to_sym
57
57
 
58
58
  # Prepend all log lines with the following tags.
59
59
  config.log_tags = [ :request_id ]
@@ -1,15 +1,15 @@
1
1
  development:
2
2
  user: fedoraAdmin
3
3
  password: fedoraAdmin
4
- url: http://<%= ENV['FCREPO_HOST'] || 'localhost' %>:<%= ENV['FCREPO_DEVELOPMENT_PORT'] || ENV['FCREPO_PORT'] || 8984 %>/<%= ENV['FCREPO_REST_PATH'] || 'rest' %>
5
- base_path: <%= ENV['FCREPO_DEV_BASE_PATH'] || ENV['FCREPO_BASE_PATH'] || '/dev' %>
4
+ url: <%= ENV.fetch('FEDORA_URL') { "http://#{ENV['FCREPO_HOST'] || 'localhost'}:#{ENV['FCREPO_DEVELOPMENT_PORT'] || ENV['FCREPO_PORT'] || 8984 }/#{ENV['FCREPO_REST_PATH'] || 'rest'}" } %>
5
+ base_path: <%= ENV['FEDORA_BASE_PATH'] || ENV['FCREPO_DEV_BASE_PATH'] || ENV['FCREPO_BASE_PATH'] || '/dev' %>
6
6
  test:
7
7
  user: fedoraAdmin
8
8
  password: fedoraAdmin
9
- url: http://<%= ENV['FCREPO_HOST'] || 'localhost' %>:<%= ENV['FCREPO_DEVELOPMENT_PORT'] || ENV['FCREPO_PORT'] || 8986 %>/<%= ENV['FCREPO_REST_PATH'] || 'rest' %>
10
- base_path: <%= ENV['FCREPO_TEST_BASE_PATH'] || ENV['FCREPO_BASE_PATH'] || '/test' %>
9
+ url: <%= ENV.fetch('FEDORA_URL') { "http://#{ENV['FCREPO_HOST'] || 'localhost'}:#{ENV['FCREPO_DEVELOPMENT_PORT'] || ENV['FCREPO_PORT'] || 8986 }/#{ENV['FCREPO_REST_PATH'] || 'rest'}" } %>
10
+ base_path: <%= ENV['FEDORA_BASE_PATH'] || ENV['FCREPO_TEST_BASE_PATH'] || ENV['FCREPO_BASE_PATH'] || '/test' %>
11
11
  production:
12
12
  user: fedoraAdmin
13
13
  password: fedoraAdmin
14
- url: http://<%= ENV['FCREPO_HOST'] || 'localhost' %>:<%= ENV['FCREPO_DEVELOPMENT_PORT'] || ENV['FCREPO_PORT'] || 8983 %>/<%= ENV['FCREPO_REST_PATH'] || 'rest' %>
15
- base_path: <%= ENV['FCREPO_BASE_PATH'] || '/prod' %>
14
+ url: <%= ENV.fetch('FEDORA_URL') { "http://#{ENV['FCREPO_HOST'] || 'localhost'}:#{ENV['FCREPO_PORT'] || 8984 }/#{ENV['FCREPO_REST_PATH'] || 'rest'}" } %>
15
+ base_path: <%= ENV['FEDORA_BASE_PATH'] || ENV['FCREPO_BASE_PATH'] || '/prod' %>
@@ -10,4 +10,5 @@ Devise.setup do |config|
10
10
  config.password_length = 6..128
11
11
  config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
12
12
  config.reset_password_within = 6.hours
13
+ config.sign_out_via = :delete
13
14
  end
@@ -0,0 +1,5 @@
1
+ require 'stackprof'
2
+ require 'rack-mini-profiler'
3
+
4
+ # initialization is skipped so trigger it
5
+ Rack::MiniProfilerRails.initialize!(Rails.application)
@@ -50,7 +50,7 @@ en:
50
50
  directory:
51
51
  suffix: "@example.org"
52
52
  footer:
53
- copyright_html: "<strong>Copyright &copy; 2018 Samvera</strong> Licensed under the Apache License, Version 2.0"
53
+ copyright_html: "<strong>Copyright &copy; %{current_year} Samvera</strong> Licensed under the Apache License, Version 2.0"
54
54
  service_html: A service of <a href="http://samvera.org/" class="navbar-link" target="_blank">Samvera</a>.
55
55
  institution_name: Institution
56
56
  institution_name_full: The Institution Name
@@ -1,6 +1,56 @@
1
- threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
2
- threads threads_count, threads_count
3
- port ENV.fetch("PORT") { 3000 }
4
- environment ENV.fetch("RAILS_ENV") { "development" }
5
- pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
1
+ # Puma can serve each request in a thread from an internal thread pool.
2
+ # The `threads` method setting takes two numbers: a minimum and maximum.
3
+ # Any libraries that use thread pools should be configured to match
4
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
+ # and maximum; this matches the default thread size of Active Record.
6
+ #
7
+ threads_count = ENV.fetch("RAILS_MAX_THREADS", 5).to_i
8
+ threads 1, threads_count - 2
9
+
10
+ # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11
+ #
12
+ port ENV.fetch("PORT", 3000)
13
+
14
+ # Specifies the `environment` that Puma will run in.
15
+ #
16
+ rails_env = ENV.fetch("RAILS_ENV", 'development')
17
+ environment rails_env
18
+
19
+ # Specifies the `pidfile` that Puma will use.
20
+ pidfile ENV.fetch("PIDFILE", 'tmp/pids/server.pid')
21
+
22
+ # Specifies the number of `workers` to boot in clustered mode.
23
+ # Workers are forked webserver processes. If using threads and workers together
24
+ # the concurrency of the application would be max `threads` * `workers`.
25
+ # Workers do not work on JRuby or Windows (both of which do not support
26
+ # processes).
27
+ #
28
+ workers ENV.fetch('WEB_CONCURRENCY', 1)
29
+
30
+ # Use the `preload_app!` method when specifying a `workers` number.
31
+ # This directive tells Puma to first boot the application and load code
32
+ # before forking the application. This takes advantage of Copy On Write
33
+ # process behavior so workers use less memory.
34
+ #
35
+ preload_app!
36
+
37
+ # Allow puma to be restarted by `rails restart` command.
6
38
  plugin :tmp_restart
39
+
40
+ # Embedded Sidekiq https://github.com/sidekiq/sidekiq/wiki/Embedding
41
+ if ENV.fetch('SIDEKIQ_MODE', false) == 'embed'
42
+ embedded_sidekiq = nil
43
+
44
+ on_worker_boot do
45
+ embedded_sidekiq = Sidekiq.configure_embed do |config|
46
+ config.logger.level = ENV.fetch("RAILS_LOG_LEVEL", 'debug')
47
+ config.queues = %w[ingest batch default]
48
+ config.concurrency = ENV.fetch('SIDEKIQ_WORKERS', 2) # Adjust max `threads` above accordingly
49
+ end
50
+ embedded_sidekiq.run
51
+ end
52
+
53
+ on_worker_shutdown do
54
+ embedded_sidekiq&.stop
55
+ end
56
+ end
@@ -13,6 +13,8 @@ Rails.application.routes.draw do
13
13
  concerns :searchable
14
14
  end
15
15
  devise_for :users
16
+ mount Hydra::RoleManagement::Engine => '/'
17
+
16
18
  mount Qa::Engine => '/authorities'
17
19
  mount Hyrax::Engine, at: '/'
18
20
  resources :welcome, only: 'index'
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserRoles < ActiveRecord::Migration[5.0]
4
+ def up
5
+ create_table :roles do |t|
6
+ t.string :name
7
+ end
8
+ create_table :roles_users, id: false do |t|
9
+ t.references :role
10
+ t.references :user
11
+ end
12
+ add_index :roles_users, %i[role_id user_id]
13
+ add_index :roles_users, %i[user_id role_id]
14
+ end
15
+
16
+ def down
17
+ drop_table :roles_users
18
+ drop_table :roles
19
+ end
20
+ end