diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b131018..98574ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - ruby: ['3.0', '3.1', '3.2', head] + ruby: ['3.0', '3.1', '3.2', '3.3', head] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/Gemfile b/Gemfile index a0ccadb..1129dc7 100644 --- a/Gemfile +++ b/Gemfile @@ -10,3 +10,5 @@ gem 'rails', '>= 7.0' gem 'rbs', '>= 3' gem 'steep', '>= 1.4' gem 'minitest' +gem 'abbrev' +gem 'mutex_m' diff --git a/Gemfile.lock b/Gemfile.lock index 7877576..2d0eb26 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,6 +8,7 @@ PATH GEM remote: https://rubygems.org/ specs: + abbrev (0.1.2) actioncable (7.0.5) actionpack (= 7.0.5) activesupport (= 7.0.5) @@ -105,6 +106,7 @@ GEM mini_mime (1.1.2) mini_portile2 (2.8.2) minitest (5.15.0) + mutex_m (0.2.0) net-imap (0.3.4) date net-protocol @@ -189,7 +191,9 @@ PLATFORMS ruby DEPENDENCIES + abbrev minitest + mutex_m rails (>= 7.0) rake (~> 13.0) rbs (>= 3) diff --git a/lib/rbs_rails/active_record.rb b/lib/rbs_rails/active_record.rb index f260497..5ab06af 100644 --- a/lib/rbs_rails/active_record.rb +++ b/lib/rbs_rails/active_record.rb @@ -56,8 +56,16 @@ def generate pk = klass.primary_key return 'top' unless pk - col = klass.columns.find {|col| col.name == pk } - sql_type_to_class(col.type) + if pk.is_a?(Array) + types = pk.map do |_pk| + col = klass.columns.find {|col| col.name == _pk } + sql_type_to_class(col.type) + end + "[ #{types.join(', ')} ]" + else + col = klass.columns.find {|col| col.name == pk } + sql_type_to_class(col.type) + end end private def generated_relation_methods_decl diff --git a/rbs_collection.lock.yaml b/rbs_collection.lock.yaml index b61dd2a..7d83f35 100644 --- a/rbs_collection.lock.yaml +++ b/rbs_collection.lock.yaml @@ -2,7 +2,7 @@ sources: - type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems path: ".gem_rbs_collection" @@ -11,12 +11,20 @@ gems: version: '0' source: type: stdlib +- name: actioncable + version: '7.1' + source: + type: git + name: ruby/gem_rbs_collection + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 + remote: https://github.com/ruby/gem_rbs_collection.git + repo_dir: gems - name: actionmailer version: '7.0' source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: actionpack @@ -24,7 +32,7 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: actionview @@ -32,7 +40,7 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: activejob @@ -40,23 +48,23 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: activemodel - version: '6.0' + version: '7.0' source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: activerecord - version: '6.1' + version: '7.0' source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: activestorage @@ -64,15 +72,15 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: activesupport - version: '6.0' + version: '7.0' source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: cgi @@ -84,19 +92,27 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: date version: '0' source: type: stdlib +- name: erb + version: '0' + source: + type: stdlib +- name: fileutils + version: '0' + source: + type: stdlib - name: globalid version: '1.1' source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: i18n @@ -104,7 +120,7 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: json @@ -120,7 +136,7 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: minitest @@ -148,7 +164,7 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: rails-dom-testing @@ -156,7 +172,7 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: railties @@ -164,7 +180,15 @@ gems: source: type: git name: ruby/gem_rbs_collection - revision: 163126f59d1bb765a6234fc60d3edf21cdfce255 + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 + remote: https://github.com/ruby/gem_rbs_collection.git + repo_dir: gems +- name: rake + version: '13.0' + source: + type: git + name: ruby/gem_rbs_collection + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 remote: https://github.com/ruby/gem_rbs_collection.git repo_dir: gems - name: rbs @@ -175,6 +199,10 @@ gems: version: '0' source: type: stdlib +- name: securerandom + version: '0' + source: + type: stdlib - name: singleton version: '0' source: @@ -183,10 +211,22 @@ gems: version: '0' source: type: stdlib +- name: thor + version: '1.2' + source: + type: git + name: ruby/gem_rbs_collection + revision: 01361bb0fd6e2f3e2da2b11a733ffc938b9047c4 + remote: https://github.com/ruby/gem_rbs_collection.git + repo_dir: gems - name: time version: '0' source: type: stdlib +- name: timeout + version: '0' + source: + type: stdlib - name: tsort version: '0' source: diff --git a/sig/_internal/activerecord.rbs b/sig/_internal/activerecord.rbs index 452cf13..235ca41 100644 --- a/sig/_internal/activerecord.rbs +++ b/sig/_internal/activerecord.rbs @@ -1,4 +1,4 @@ # TODO: Define it in gem_rbs_collection repository class ActiveRecord::Base - def self.primary_key: () -> String + def self.primary_key: () -> (String | Array[bot]) end diff --git a/sig/_internal/fileutils.rbs b/sig/_internal/fileutils.rbs deleted file mode 100644 index 245d073..0000000 --- a/sig/_internal/fileutils.rbs +++ /dev/null @@ -1,4 +0,0 @@ -module FileUtils - def self.cp_r: (Pathname, Pathname) -> untyped - def self.mkdir_p: (String | Array[String], ?untyped) -> Array[String] -end diff --git a/sig/_internal/thor.rbs b/sig/_internal/thor.rbs deleted file mode 100644 index cb4a050..0000000 --- a/sig/_internal/thor.rbs +++ /dev/null @@ -1,5 +0,0 @@ -class Thor - module Actions - def create_file: (String, String) -> void - end -end diff --git a/test/app/Gemfile b/test/app/Gemfile index 6474714..8a9ad47 100644 --- a/test/app/Gemfile +++ b/test/app/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -gem 'rails', '>= 6', '< 7' +gem 'rails', '>= 7', '< 8' gem 'sqlite3' gem 'puma' gem 'bootsnap', require: false diff --git a/test/app/Gemfile.lock b/test/app/Gemfile.lock index 3f44bf9..8fa004b 100644 --- a/test/app/Gemfile.lock +++ b/test/app/Gemfile.lock @@ -8,145 +8,192 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (6.1.3.1) - actionpack (= 6.1.3.1) - activesupport (= 6.1.3.1) + abbrev (0.1.2) + actioncable (7.1.3) + actionpack (= 7.1.3) + activesupport (= 7.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.3.1) - actionpack (= 6.1.3.1) - activejob (= 6.1.3.1) - activerecord (= 6.1.3.1) - activestorage (= 6.1.3.1) - activesupport (= 6.1.3.1) + zeitwerk (~> 2.6) + actionmailbox (7.1.3) + actionpack (= 7.1.3) + activejob (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) mail (>= 2.7.1) - actionmailer (6.1.3.1) - actionpack (= 6.1.3.1) - actionview (= 6.1.3.1) - activejob (= 6.1.3.1) - activesupport (= 6.1.3.1) + net-imap + net-pop + net-smtp + actionmailer (7.1.3) + actionpack (= 7.1.3) + actionview (= 7.1.3) + activejob (= 7.1.3) + activesupport (= 7.1.3) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (6.1.3.1) - actionview (= 6.1.3.1) - activesupport (= 6.1.3.1) - rack (~> 2.0, >= 2.0.9) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.2) + actionpack (7.1.3) + actionview (= 7.1.3) + activesupport (= 7.1.3) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.3.1) - actionpack (= 6.1.3.1) - activerecord (= 6.1.3.1) - activestorage (= 6.1.3.1) - activesupport (= 6.1.3.1) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.3) + actionpack (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) + globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (6.1.3.1) - activesupport (= 6.1.3.1) + actionview (7.1.3) + activesupport (= 7.1.3) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.1.3.1) - activesupport (= 6.1.3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.3) + activesupport (= 7.1.3) globalid (>= 0.3.6) - activemodel (6.1.3.1) - activesupport (= 6.1.3.1) - activerecord (6.1.3.1) - activemodel (= 6.1.3.1) - activesupport (= 6.1.3.1) - activestorage (6.1.3.1) - actionpack (= 6.1.3.1) - activejob (= 6.1.3.1) - activerecord (= 6.1.3.1) - activesupport (= 6.1.3.1) - marcel (~> 1.0.0) - mini_mime (~> 1.0.2) - activesupport (6.1.3.1) + activemodel (7.1.3) + activesupport (= 7.1.3) + activerecord (7.1.3) + activemodel (= 7.1.3) + activesupport (= 7.1.3) + timeout (>= 0.4.0) + activestorage (7.1.3) + actionpack (= 7.1.3) + activejob (= 7.1.3) + activerecord (= 7.1.3) + activesupport (= 7.1.3) + marcel (~> 1.0) + activesupport (7.1.3) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - zeitwerk (~> 2.3) ast (2.4.2) - bcrypt (3.1.16) - bootsnap (1.7.3) - msgpack (~> 1.0) + base64 (0.2.0) + bcrypt (3.1.20) + bigdecimal (3.1.6) + bootsnap (1.18.3) + msgpack (~> 1.2) builder (3.2.4) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) crass (1.0.6) - erubi (1.10.0) - globalid (1.0.1) - activesupport (>= 5.0) - i18n (1.12.0) + date (3.3.4) + drb (2.2.0) + ruby2_keywords + erubi (1.12.0) + globalid (1.2.1) + activesupport (>= 6.1) + i18n (1.14.1) concurrent-ruby (~> 1.0) - loofah (2.21.3) + io-console (0.7.2) + irb (1.11.2) + rdoc + reline (>= 0.4.2) + loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.7.1) + mail (2.8.1) mini_mime (>= 0.1.1) - marcel (1.0.1) - method_source (1.0.0) - mini_mime (1.0.3) - mini_portile2 (2.8.2) - minitest (5.17.0) - msgpack (1.4.2) - nio4r (2.5.8) - nokogiri (1.15.2) + net-imap + net-pop + net-smtp + marcel (1.0.2) + mini_mime (1.1.5) + mini_portile2 (2.8.5) + minitest (5.22.2) + msgpack (1.7.2) + mutex_m (0.2.0) + net-imap (0.4.10) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.4.0.1) + net-protocol + nio4r (2.7.0) + nokogiri (1.16.2) mini_portile2 (~> 2.8.2) racc (~> 1.4) - parser (3.2.2.1) + parser (3.3.0.5) ast (~> 2.4.1) - psych (3.3.2) - puma (5.6.4) + racc + psych (3.3.4) + puma (6.4.2) nio4r (~> 2.0) - racc (1.7.0) - rack (2.2.6.4) - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (6.1.3.1) - actioncable (= 6.1.3.1) - actionmailbox (= 6.1.3.1) - actionmailer (= 6.1.3.1) - actionpack (= 6.1.3.1) - actiontext (= 6.1.3.1) - actionview (= 6.1.3.1) - activejob (= 6.1.3.1) - activemodel (= 6.1.3.1) - activerecord (= 6.1.3.1) - activestorage (= 6.1.3.1) - activesupport (= 6.1.3.1) + racc (1.7.3) + rack (3.0.9) + rack-session (2.0.0) + rack (>= 3.0.0) + rack-test (2.1.0) + rack (>= 1.3) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + rails (7.1.3) + actioncable (= 7.1.3) + actionmailbox (= 7.1.3) + actionmailer (= 7.1.3) + actionpack (= 7.1.3) + actiontext (= 7.1.3) + actionview (= 7.1.3) + activejob (= 7.1.3) + activemodel (= 7.1.3) + activerecord (= 7.1.3) + activestorage (= 7.1.3) + activesupport (= 7.1.3) bundler (>= 1.15.0) - railties (= 6.1.3.1) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 7.1.3) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (6.1.3.1) - actionpack (= 6.1.3.1) - activesupport (= 6.1.3.1) - method_source - rake (>= 0.8.7) - thor (~> 1.0) - rake (13.0.3) - rbs (3.1.0) - sprockets (4.0.2) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.2) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) - sqlite3 (1.4.2) - thor (1.1.0) - tzinfo (2.0.5) + railties (7.1.3) + actionpack (= 7.1.3) + activesupport (= 7.1.3) + irb + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rake (13.1.0) + rbs (3.4.4) + abbrev + rdoc (6.3.3) + reline (0.4.2) + io-console (~> 0.5) + ruby2_keywords (0.0.5) + sqlite3 (1.7.2) + mini_portile2 (~> 2.8.0) + thor (1.3.0) + timeout (0.4.1) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) - websocket-driver (0.7.3) + webrick (1.8.1) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.6.6) + zeitwerk (2.6.13) PLATFORMS ruby @@ -156,7 +203,7 @@ DEPENDENCIES bootsnap psych (< 4) puma - rails (>= 6, < 7) + rails (>= 7, < 8) rbs_rails! sqlite3 diff --git a/test/app/app/models/product.rb b/test/app/app/models/product.rb new file mode 100644 index 0000000..2c58696 --- /dev/null +++ b/test/app/app/models/product.rb @@ -0,0 +1,3 @@ +class Product < ApplicationRecord + self.primary_key = [:store_id, :sku] +end diff --git a/test/app/bin/setup b/test/app/bin/setup index 0e39e8c..b994156 100755 --- a/test/app/bin/setup +++ b/test/app/bin/setup @@ -5,12 +5,12 @@ require 'fileutils' APP_ROOT = File.expand_path('..', __dir__) def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") + system(*args, exception: true) end FileUtils.chdir APP_ROOT do - # This script is a way to setup or update your development environment automatically. - # This script is idempotent, so that you can run it at anytime and get an expectable outcome. + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. puts '== Installing dependencies ==' diff --git a/test/app/config/application.rb b/test/app/config/application.rb index 93e5266..41a226c 100644 --- a/test/app/config/application.rb +++ b/test/app/config/application.rb @@ -22,7 +22,7 @@ module App class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 6.0 + config.load_defaults 7.1 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers diff --git a/test/app/config/boot.rb b/test/app/config/boot.rb index 0cb01c4..30f5120 100644 --- a/test/app/config/boot.rb +++ b/test/app/config/boot.rb @@ -1,5 +1,3 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. -# Disable Bootsnap due to https://github.com/pocke/rbs_rails/pull/198#issuecomment-931215730 -# require 'bootsnap/setup' # Speed up boot time by caching expensive operations. diff --git a/test/app/config/environments/development.rb b/test/app/config/environments/development.rb index 8ea13e4..300e636 100644 --- a/test/app/config/environments/development.rb +++ b/test/app/config/environments/development.rb @@ -1,10 +1,12 @@ +require "active_support/core_ext/integer/time" + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded on - # every request. This slows down response time but is perfect for development + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. - config.cache_classes = false + config.enable_reloading = true # Do not eager load code on boot. config.eager_load = false @@ -12,6 +14,9 @@ # Show full error reports. config.consider_all_requests_local = true + # Enable server timing + config.server_timing = true + # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. if Rails.root.join('tmp', 'caching-dev.txt').exist? @@ -28,20 +33,37 @@ config.cache_store = :null_store end + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true + # Highlight code that enqueued background job in logs. + config.active_job.verbose_enqueue_logs = true + # Raises error for missing translations. - # config.action_view.raise_on_missing_translations = true + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true - # Use an evented file watcher to asynchronously detect changes in source code, - # routes, locales, etc. This feature depends on the listen gem. - # config.file_watcher = ActiveSupport::EventedFileUpdateChecker + # Raise error when a before_action's only/except options reference missing actions + config.action_controller.raise_on_missing_callback_actions = true end diff --git a/test/app/config/environments/production.rb b/test/app/config/environments/production.rb index 65b4844..3ad1a5e 100644 --- a/test/app/config/environments/production.rb +++ b/test/app/config/environments/production.rb @@ -1,8 +1,10 @@ +require "active_support/core_ext/integer/time" + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. - config.cache_classes = true + config.enable_reloading = false # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers @@ -11,87 +13,73 @@ config.eager_load = true # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false + config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] - # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true - # Disable serving static files from the `/public` folder by default since - # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # config.public_file_server.enabled = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = 'http://assets.example.com' + # config.asset_host = "http://assets.example.com" # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local # Mount Action Cable outside main process or domain. # config.action_cable.mount_path = nil - # config.action_cable.url = 'wss://example.com/cable' - # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. + # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true - # Use the lowest log level to ensure availability of diagnostic information - # when problems arise. - config.log_level = :debug + # Log to STDOUT by default + config.logger = ActiveSupport::Logger.new(STDOUT) + .tap { |logger| logger.formatter = ::Logger::Formatter.new } + .then { |logger| ActiveSupport::TaggedLogging.new(logger) } # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] + # "info" includes generic and useful information about system operation, but avoids logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). If you + # want to log everything, set the level to "debug". + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + # Use a different cache store in production. # config.cache_store = :mem_cache_store # Use a real queuing backend for Active Job (and separate queues per environment). - # config.active_job.queue_adapter = :resque + # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "app_production" # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify - - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Use a different logger for distributed setups. - # require 'syslog/logger' - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') - - if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) - end + # Don't log any deprecations. + config.active_support.report_deprecations = false # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false - # Inserts middleware to perform automatic connection switching. - # The `database_selector` hash is used to pass options to the DatabaseSelector - # middleware. The `delay` is used to determine how long to wait after a write - # to send a subsequent read to the primary. - # - # The `database_resolver` class is used by the middleware to determine which - # database is appropriate to use based on the time delay. - # - # The `database_resolver_context` class is used by the middleware to set - # timestamps for the last write to the primary. The resolver uses the context - # class timestamps to determine how long to wait before reading from the - # replica. - # - # By default Rails will store a last write timestamp in the session. The - # DatabaseSelector middleware is designed as such you can define your own - # strategy for connection switching and pass that into the middleware through - # these configuration options. - # config.active_record.database_selector = { delay: 2.seconds } - # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver - # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/test/app/config/environments/test.rb b/test/app/config/environments/test.rb index 06aef36..5d1165b 100644 --- a/test/app/config/environments/test.rb +++ b/test/app/config/environments/test.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/integer/time" + # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped @@ -6,12 +8,14 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - config.cache_classes = true + # While tests run files are not watched, reloading is not necessary. + config.enable_reloading = false - # Do not eager load code on boot. This avoids loading your whole application - # just for the purpose of running a single test. If you are using a tool that - # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false + # Eager loading loads your entire application. When running a single test locally, + # this is usually not necessary, and can slow down your test suite. However, it's + # recommended that you enable it in continuous integration systems to ensure eager + # loading is working properly before deploying your code. + config.eager_load = ENV["CI"].present? # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true @@ -20,19 +24,34 @@ } # Show full error reports and disable caching. - config.consider_all_requests_local = true + config.consider_all_requests_local = true config.action_controller.perform_caching = false config.cache_store = :null_store - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false + # Render exception templates for rescuable exceptions and raise for other exceptions. + config.action_dispatch.show_exceptions = :rescuable # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raises error for missing translations. - # config.action_view.raise_on_missing_translations = true + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true + + # Raise error when a before_action's only/except options reference missing actions + config.action_controller.raise_on_missing_callback_actions = true end diff --git a/test/app/config/initializers/content_security_policy.rb b/test/app/config/initializers/content_security_policy.rb index 41c4301..b3076b3 100644 --- a/test/app/config/initializers/content_security_policy.rb +++ b/test/app/config/initializers/content_security_policy.rb @@ -1,28 +1,25 @@ # Be sure to restart your server when you modify this file. -# Define an application-wide content security policy -# For further information see the following documentation -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header -# Rails.application.config.content_security_policy do |policy| -# policy.default_src :self, :https -# policy.font_src :self, :https, :data -# policy.img_src :self, :https, :data -# policy.object_src :none -# policy.script_src :self, :https -# policy.style_src :self, :https - -# # Specify URI for violation reports -# # policy.report_uri "/csp-violation-report-endpoint" +# Rails.application.configure do +# config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end +# +# # Generate session nonces for permitted importmap, inline scripts, and inline styles. +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src style-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true # end - -# If you are using UJS then enable automatic nonce generation -# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } - -# Set the nonce only to specific directives -# Rails.application.config.content_security_policy_nonce_directives = %w(script-src) - -# Report CSP violations to a specified URI -# For further information see the following documentation: -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only -# Rails.application.config.content_security_policy_report_only = true diff --git a/test/app/config/initializers/filter_parameter_logging.rb b/test/app/config/initializers/filter_parameter_logging.rb index 4a994e1..c2d89e2 100644 --- a/test/app/config/initializers/filter_parameter_logging.rb +++ b/test/app/config/initializers/filter_parameter_logging.rb @@ -1,4 +1,8 @@ # Be sure to restart your server when you modify this file. -# Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password] +# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. +# Use this to limit dissemination of sensitive information. +# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/test/app/config/initializers/permissions_policy.rb b/test/app/config/initializers/permissions_policy.rb new file mode 100644 index 0000000..7db3b95 --- /dev/null +++ b/test/app/config/initializers/permissions_policy.rb @@ -0,0 +1,13 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide HTTP permissions policy. For further +# information see: https://developers.google.com/web/updates/2018/06/feature-policy + +# Rails.application.config.permissions_policy do |policy| +# policy.camera :none +# policy.gyroscope :none +# policy.microphone :none +# policy.usb :none +# policy.fullscreen :self +# policy.payment :self, "https://secure.example.com" +# end diff --git a/test/app/db/migrate/20240214042801_add_status_to_users.rb b/test/app/db/migrate/20240214042801_add_status_to_users.rb new file mode 100644 index 0000000..1ee9e23 --- /dev/null +++ b/test/app/db/migrate/20240214042801_add_status_to_users.rb @@ -0,0 +1,5 @@ +class AddStatusToUsers < ActiveRecord::Migration[7.1] + def change + change_column :users, :status, :integer, default: 1, null: false + end +end diff --git a/test/app/db/migrate/20240214044754_create_products.rb b/test/app/db/migrate/20240214044754_create_products.rb new file mode 100644 index 0000000..2600214 --- /dev/null +++ b/test/app/db/migrate/20240214044754_create_products.rb @@ -0,0 +1,11 @@ +class CreateProducts < ActiveRecord::Migration[7.1] + def change + create_table :products, primary_key: [:store_id, :sku] do |t| + t.integer :store_id, null: false + t.string :sku, null: false + t.text :description + + t.timestamps + end + end +end diff --git a/test/app/db/schema.rb b/test/app/db/schema.rb index 53dea36..9ff32fd 100644 --- a/test/app/db/schema.rb +++ b/test/app/db/schema.rb @@ -10,14 +10,13 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_04_14_110904) do - +ActiveRecord::Schema[7.1].define(version: 2024_02_14_044754) do create_table "blogs", force: :cascade do |t| t.string "title", null: false t.string "description", null: false t.integer "user_id", null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.index ["user_id"], name: "index_blogs_on_user_id" end @@ -26,11 +25,20 @@ t.integer "blog_id", null: false end + create_table "products", primary_key: ["store_id", "sku"], force: :cascade do |t| + t.integer "store_id", null: false + t.string "sku", null: false + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "users", force: :cascade do |t| t.string "name", null: false t.integer "age", null: false - t.datetime "created_at", precision: 6, null: false - t.datetime "updated_at", precision: 6, null: false + t.integer "status", default: 1, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end end diff --git a/test/expectations/product.rbs b/test/expectations/product.rbs new file mode 100644 index 0000000..486c37a --- /dev/null +++ b/test/expectations/product.rbs @@ -0,0 +1,204 @@ +class Product < ::ApplicationRecord + extend ::_ActiveRecord_Relation_ClassMethods[::Product, ::Product::ActiveRecord_Relation, [ ::Integer, ::String ]] + + module GeneratedAttributeMethods + def store_id: () -> ::Integer + + def store_id=: (::Integer) -> ::Integer + + def store_id?: () -> bool + + def store_id_changed?: () -> bool + + def store_id_change: () -> [ ::Integer?, ::Integer? ] + + def store_id_will_change!: () -> void + + def store_id_was: () -> ::Integer? + + def store_id_previously_changed?: () -> bool + + def store_id_previous_change: () -> ::Array[::Integer?]? + + def store_id_previously_was: () -> ::Integer? + + def store_id_before_last_save: () -> ::Integer? + + def store_id_change_to_be_saved: () -> ::Array[::Integer?]? + + def store_id_in_database: () -> ::Integer? + + def saved_change_to_store_id: () -> ::Array[::Integer?]? + + def saved_change_to_store_id?: () -> bool + + def will_save_change_to_store_id?: () -> bool + + def restore_store_id!: () -> void + + def clear_store_id_change: () -> void + + def sku: () -> ::String + + def sku=: (::String) -> ::String + + def sku?: () -> bool + + def sku_changed?: () -> bool + + def sku_change: () -> [ ::String?, ::String? ] + + def sku_will_change!: () -> void + + def sku_was: () -> ::String? + + def sku_previously_changed?: () -> bool + + def sku_previous_change: () -> ::Array[::String?]? + + def sku_previously_was: () -> ::String? + + def sku_before_last_save: () -> ::String? + + def sku_change_to_be_saved: () -> ::Array[::String?]? + + def sku_in_database: () -> ::String? + + def saved_change_to_sku: () -> ::Array[::String?]? + + def saved_change_to_sku?: () -> bool + + def will_save_change_to_sku?: () -> bool + + def restore_sku!: () -> void + + def clear_sku_change: () -> void + + def description: () -> ::String? + + def description=: (::String?) -> ::String? + + def description?: () -> bool + + def description_changed?: () -> bool + + def description_change: () -> [ ::String?, ::String? ] + + def description_will_change!: () -> void + + def description_was: () -> ::String? + + def description_previously_changed?: () -> bool + + def description_previous_change: () -> ::Array[::String?]? + + def description_previously_was: () -> ::String? + + def description_before_last_save: () -> ::String? + + def description_change_to_be_saved: () -> ::Array[::String?]? + + def description_in_database: () -> ::String? + + def saved_change_to_description: () -> ::Array[::String?]? + + def saved_change_to_description?: () -> bool + + def will_save_change_to_description?: () -> bool + + def restore_description!: () -> void + + def clear_description_change: () -> void + + def created_at: () -> ::ActiveSupport::TimeWithZone + + def created_at=: (::ActiveSupport::TimeWithZone) -> ::ActiveSupport::TimeWithZone + + def created_at?: () -> bool + + def created_at_changed?: () -> bool + + def created_at_change: () -> [ ::ActiveSupport::TimeWithZone?, ::ActiveSupport::TimeWithZone? ] + + def created_at_will_change!: () -> void + + def created_at_was: () -> ::ActiveSupport::TimeWithZone? + + def created_at_previously_changed?: () -> bool + + def created_at_previous_change: () -> ::Array[::ActiveSupport::TimeWithZone?]? + + def created_at_previously_was: () -> ::ActiveSupport::TimeWithZone? + + def created_at_before_last_save: () -> ::ActiveSupport::TimeWithZone? + + def created_at_change_to_be_saved: () -> ::Array[::ActiveSupport::TimeWithZone?]? + + def created_at_in_database: () -> ::ActiveSupport::TimeWithZone? + + def saved_change_to_created_at: () -> ::Array[::ActiveSupport::TimeWithZone?]? + + def saved_change_to_created_at?: () -> bool + + def will_save_change_to_created_at?: () -> bool + + def restore_created_at!: () -> void + + def clear_created_at_change: () -> void + + def updated_at: () -> ::ActiveSupport::TimeWithZone + + def updated_at=: (::ActiveSupport::TimeWithZone) -> ::ActiveSupport::TimeWithZone + + def updated_at?: () -> bool + + def updated_at_changed?: () -> bool + + def updated_at_change: () -> [ ::ActiveSupport::TimeWithZone?, ::ActiveSupport::TimeWithZone? ] + + def updated_at_will_change!: () -> void + + def updated_at_was: () -> ::ActiveSupport::TimeWithZone? + + def updated_at_previously_changed?: () -> bool + + def updated_at_previous_change: () -> ::Array[::ActiveSupport::TimeWithZone?]? + + def updated_at_previously_was: () -> ::ActiveSupport::TimeWithZone? + + def updated_at_before_last_save: () -> ::ActiveSupport::TimeWithZone? + + def updated_at_change_to_be_saved: () -> ::Array[::ActiveSupport::TimeWithZone?]? + + def updated_at_in_database: () -> ::ActiveSupport::TimeWithZone? + + def saved_change_to_updated_at: () -> ::Array[::ActiveSupport::TimeWithZone?]? + + def saved_change_to_updated_at?: () -> bool + + def will_save_change_to_updated_at?: () -> bool + + def restore_updated_at!: () -> void + + def clear_updated_at_change: () -> void + end + include GeneratedAttributeMethods + + module GeneratedAssociationMethods + end + include GeneratedAssociationMethods + + module GeneratedRelationMethods + end + + class ActiveRecord_Relation < ::ActiveRecord::Relation + include ::Product::GeneratedRelationMethods + include ::_ActiveRecord_Relation[::Product, [ ::Integer, ::String ]] + include ::Enumerable[::Product] + end + + class ActiveRecord_Associations_CollectionProxy < ::ActiveRecord::Associations::CollectionProxy + include ::Product::GeneratedRelationMethods + include ::_ActiveRecord_Relation[::Product, [ ::Integer, ::String ]] + end +end diff --git a/test/expectations/user.rbs b/test/expectations/user.rbs index d317140..8f96bd9 100644 --- a/test/expectations/user.rbs +++ b/test/expectations/user.rbs @@ -110,6 +110,42 @@ class User < ::ApplicationRecord def clear_age_change: () -> void + def status: () -> ::String + + def status=: (::String) -> ::String + + def status?: () -> bool + + def status_changed?: () -> bool + + def status_change: () -> [ ::String?, ::String? ] + + def status_will_change!: () -> void + + def status_was: () -> ::String? + + def status_previously_changed?: () -> bool + + def status_previous_change: () -> ::Array[::String?]? + + def status_previously_was: () -> ::String? + + def status_before_last_save: () -> ::String? + + def status_change_to_be_saved: () -> ::Array[::String?]? + + def status_in_database: () -> ::String? + + def saved_change_to_status: () -> ::Array[::String?]? + + def saved_change_to_status?: () -> bool + + def will_save_change_to_status?: () -> bool + + def restore_status!: () -> void + + def clear_status_change: () -> void + def created_at: () -> ::ActiveSupport::TimeWithZone def created_at=: (::ActiveSupport::TimeWithZone) -> ::ActiveSupport::TimeWithZone diff --git a/test/rbs_rails/active_record_test.rb b/test/rbs_rails/active_record_test.rb index 61a72b7..620316c 100644 --- a/test/rbs_rails/active_record_test.rb +++ b/test/rbs_rails/active_record_test.rb @@ -23,6 +23,17 @@ def test_user_model_rbs_snapshot assert_equal expect_path.read, rbs_path.read end + def test_product_model_rbs_snapshot + clean_test_signatures + + setup! + + rbs_path = app_dir.join('sig/rbs_rails/app/models/product.rbs') + expect_path = expectations_dir / 'product.rbs' + + assert_equal expect_path.read, rbs_path.read + end + def app_dir Pathname(__dir__).join('../app') end