diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..83e16f8
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+--require spec_helper
diff --git a/.rspec_parallel b/.rspec_parallel
new file mode 100644
index 0000000..7430f49
--- /dev/null
+++ b/.rspec_parallel
@@ -0,0 +1,8 @@
+--color
+--require spec_helper
+--format progress
+--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
+--format progress
+--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log
+--format progress
+--format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..7324c13
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,38 @@
+inherit_mode:
+ merge:
+ - Exclude
+
+require:
+ - rubocop-factory_bot
+ - rubocop-performance
+ - rubocop-rails
+ - rubocop-rspec
+ - rubocop-rspec_rails
+
+inherit_from:
+ - .rubocop/base.yml # cross-repo rubocop config based on OC Ruby Style Guide
+ - .rubocop/rails.yml # cross-repo rubocop-rails config
+ - .rubocop/rails_5.yml # cross-repo rubocop-rails version 5 config
+ - .rubocop/rspec.yml # cross-repo rubocop-rspec config
+ - .rubocop/factory_bot.yml # cross-repo rubocop-factory_bot config
+ - .rubocop/local.yml # local repo rubocop config
+ - .rubocop/strict.yml # strict cops - any offenses are not tolerated - needs to be at end of inherit_from list
+
+AllCops:
+ TargetRubyVersion: 2.7
+ NewCops: enable
+ Exclude:
+ # Rubocop does not support .erb out of the box
+ - app/views/**/*
+ - bin/**/*
+ - client/**/*
+ - db/**/*
+ - log/**/*
+ - node_modules/**/*
+ - script/**/*
+ - vendor/**/*
+
+# list of files/cops that caused errors when running rubocop
+Style/SuperArguments:
+ Exclude:
+ - app/helpers/tracking_httparty.rb # 2024-07-05
diff --git a/.rubocop/base.yml b/.rubocop/base.yml
new file mode 100644
index 0000000..c5d3ab3
--- /dev/null
+++ b/.rubocop/base.yml
@@ -0,0 +1,101 @@
+# Cross-Repository Rubcop conguration based on Owens Corning Ruby Style Guide
+
+Layout/LineLength:
+ AutoCorrect: true
+ Max: 120
+
+Metrics/BlockLength:
+ # This exclusion is aimed for RSpec DSL blocks
+ AllowedMethods: ['describe', 'context']
+ Exclude:
+ - config/routes.rb
+
+Metrics/ClassLength:
+ # Matches with requirements for working on legacy code base.
+ Max: 250
+
+Metrics/MethodLength:
+ # Matches with requirements for working on legacy code base.
+ Max: 20
+
+Metrics/AbcSize:
+ # Matches with requirements for working on legacy code base.
+ Max: 25
+
+Metrics/CyclomaticComplexity:
+ # Matches with requirements for working on legacy code base.
+ Max: 12
+
+Naming/MemoizedInstanceVariableName:
+ # There should be clear distionction between explicit instance
+ # variables and memoized method result. Using underscore before
+ # name of the variable makes it less likely to confuse those two.
+ # This convention @_calculate_data also makes it more clear, that
+ # the variable should _not_ be referenced directly.
+ EnforcedStyleForLeadingUnderscores: optional
+
+Style/ClassAndModuleChildren:
+ # Our codebase is full of compact style namespaces. We had several issues
+ # following incorrect fix for this cop (mixed Module with Class). Let's
+ # disable this for now, until figure out a better way to introduce this
+ # cop, perhaps with a bit better test coverage.
+ Enabled: false
+
+Style/Documentation:
+ # Don't require comments as documentation.
+ # They're optional though. Prefer readable code.
+ Enabled: false
+
+Style/DoubleNegation:
+ # Allow double negation.
+ # (If enabled, this Cop warns when we use it.)
+ Enabled: false
+
+Style/FrozenStringLiteralComment:
+ # This Cop adds a comment to the top of every file
+ # to enable a new ruby feature: immutable strings.
+ #
+ # The Ruby creator said this feature would be enabled
+ # by default on Ruby 3.
+ # Switching from Ruby 2 to 3 would be painful if the
+ # codebase was not prepared for it, so one way to prepare
+ # was to enable this optional feature.
+ #
+ # However, this plan was canceled.
+ # See https://bugs.ruby-lang.org/issues/11473#note-53
+ #
+ # Disable the Cop, we can opt-in on a case-by-case basis.
+ Enabled: false
+
+Style/NumericLiterals:
+ # It's trivial to fix this issue globally, but the value seems to be minimal.
+ # I am disabling for now, until we decide this is worth pursuing.
+ Enabled: false
+
+Style/PercentLiteralDelimiters:
+ Enabled: false
+
+Style/StringLiterals:
+ # Allow single or double quotes.
+ # There's times when one or the other makes sense.
+ # Please try to be consistent within the same file, though.
+ Enabled: false
+
+# Disabling any kinds of enforcement on Trailing argument, are there
+# seem to be disagreement on which way we should go. Defaults are
+# to remove those, but trailing commans in multiline definitions are very
+# useful, as they help to reduce diff churn and make code reviews easier.
+# Perhaps we should enforce the trailing on multiline at some later time.
+# Let's just prevent corrections in the wrong direction for now.
+
+Style/TrailingCommaInArguments:
+ # See comment above
+ Enabled: false
+
+Style/TrailingCommaInArrayLiteral:
+ # See comment above
+ Enabled: false
+
+Style/TrailingCommaInHashLiteral:
+ # See comment above
+ Enabled: false
diff --git a/.rubocop/factory_bot.yml b/.rubocop/factory_bot.yml
new file mode 100644
index 0000000..465860b
--- /dev/null
+++ b/.rubocop/factory_bot.yml
@@ -0,0 +1,5 @@
+# Cross-Repository conguration for Cops of the rubocop-factory_bot extension
+
+FactoryBot:
+ Include:
+ - spec/factories/**/*
diff --git a/.rubocop/local.yml b/.rubocop/local.yml
new file mode 100644
index 0000000..f9ae78d
--- /dev/null
+++ b/.rubocop/local.yml
@@ -0,0 +1,26 @@
+# Repository individual configurations
+
+Metrics/BlockLength:
+ Exclude:
+ - config/routes.rb
+ - Gemfile
+Naming/VariableNumber:
+ Enabled: true
+ AllowedIdentifiers: [
+ 'street_1',
+ 'street_2',
+ 'ship_to_address_line_1',
+ 'ship_to_address_line_2',
+ 'ship_to_address_line_3',
+ 'shipping_point_address_line_1',
+ 'shipping_point_address_line_2',
+ 'shipping_point_address_line_3',
+ ]
+Lint/MissingSuper:
+ AllowedParentClasses: [
+ 'Bazaarvoice::BaseService',
+ 'BaseService'
+ ]
+Rails/DynamicFindBy:
+ Whitelist:
+ - find_by_ums_guid
diff --git a/.rubocop/rails.yml b/.rubocop/rails.yml
new file mode 100644
index 0000000..89cb815
--- /dev/null
+++ b/.rubocop/rails.yml
@@ -0,0 +1,24 @@
+# Cross-Repository conguration for Cops of the rubocop-rails extension
+
+Rails/BelongsTo:
+ # This is about changing "required: true" to "optional: false". Wording of
+ # this warning is a bit unfortunate, as it suggest the option is not needed
+ # at all:
+ #
+ # C: [Correctable] Rails/BelongsTo: You specified required: true, in Rails
+ # > 5.0 the required option is deprecated and you want to use optional:
+ # false. In most configurations, this is the default and you can omit this
+ # option altogether
+ #
+ # This is only true, if framework defaults for 5.0 are loaded or special
+ # option config.active_record.belongs_to_required_by_default is set to true.
+ #
+ # None of those are set in MDMS, so lets remove this cop, to avoid pushing
+ # someone to remove the "required: true" and changing the behaviour by
+ # mistake.
+ Enabled: false
+
+Rails/RedundantPresenceValidationOnBelongsTo:
+ # See comment for Rails/BelongsTo. Our setting for default is different
+ # than defaults in Rails 5+ applications. This should not be enabled.
+ Enabled: false
diff --git a/.rubocop/rails_5.yml b/.rubocop/rails_5.yml
new file mode 100644
index 0000000..a7c0fad
--- /dev/null
+++ b/.rubocop/rails_5.yml
@@ -0,0 +1,5 @@
+# Cross-Repository conguration for Cops of the rubocop-rails extension while running rails version 5
+
+Rails/ResponseParsedBody:
+ # We will disable this cop for rails version 5 or lower
+ Enabled: false
diff --git a/.rubocop/rspec.yml b/.rubocop/rspec.yml
new file mode 100644
index 0000000..1e8a560
--- /dev/null
+++ b/.rubocop/rspec.yml
@@ -0,0 +1,29 @@
+# Cross-Repository conguration for Cops of the rubocop-rspec extension
+
+RSpec:
+ Include:
+ - spec/**/*
+
+RSpec/ExampleLength:
+ # Topic on how to structure the specs is whole separate thing. When
+ # we want to reduce let/before to improve redablity, then block length
+ # cannot stay low. See comments on "MultipleExpectations".
+ Enabled: false
+
+RSpec/MultipleExpectations:
+ # Disable check for multiple Expectations in single specs. Forcing
+ # single assertion requires repeated specs, which might slow down
+ # legacy test suites. Also this forces heavey extraction into
+ # separate lets/before which itself causes readablity issues.
+ # Please refer to https://thoughtbot.com/blog/lets-not
+ Enabled: false
+
+RSpec/MultipleMemoizedHelpers:
+ # Current legacy codebase uses a lot of helpers in RSpec. Please see comment
+ # for RSpec/MultipleExpectations why this is not a good thing. For now
+ # "lets" (hehe) relax this rule.
+ Max: 35
+
+RSpec/NestedGroups:
+ # Legacy codebase. Relax for now to avoid heavy refactoring.
+ Max: 7
diff --git a/.rubocop/strict.yml b/.rubocop/strict.yml
new file mode 100644
index 0000000..a2e3ea4
--- /dev/null
+++ b/.rubocop/strict.yml
@@ -0,0 +1,14 @@
+# Cross-Repository configuration of Cops that are mandatory enabled.
+#
+# There are a handful of cops that must be enabled for all the files
+# independently of any prior excludes.
+
+Lint/Debugger:
+ # don't leave binding.pry or debugger
+ Enabled: true
+ Exclude: []
+
+Rails/UniqBeforePluck:
+ # uniq.pluck and not pluck.uniq
+ Enabled: true
+ Exclude: []
diff --git a/Gemfile b/Gemfile
index 13879d0..7ead32c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -32,40 +32,67 @@ gem "jbuilder"
# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"
-# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
-# gem "kredis"
-
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
gem "bcrypt", "~> 3.1.7"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
-gem "tzinfo-data", platforms: %i[ windows jruby ]
+gem "tzinfo-data", platforms: %i[windows jruby]
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
-# gem "image_processing", "~> 1.2"
gem "active_model_serializers"
+# Security & Performance Monitoring
+gem "airbrake", "~> 13.0"
+gem "brakeman", require: false
+gem "bullet" # For N+1 query alerts
+gem "query_diet"
+
group :development, :test do
- # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
- gem "debug", platforms: %i[ mri windows ]
+ # Debugging tools
+ gem "debug", platforms: %i[mri windows]
+ gem "factory_bot_rails"
+ gem "faker"
+
+ # Linting & Code Quality
+ gem "rubocop", require: false
+ gem "rubocop-factory_bot", require: false
+ gem "rubocop-performance", "~> 1.23"
+ gem "rubocop-rails", "~> 2.29"
+ gem "rubocop-rspec", "~> 3.4"
+
+ # Pre-commit hooks
+ gem "overcommit", require: false
end
group :development do
- # Use console on exceptions pages [https://github.com/rails/web-console]
+ # Developer tools
+ gem "spring"
+ gem "spring-commands-rspec"
gem "web-console"
- # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
- # gem "rack-mini-profiler"
-
- # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
- # gem "spring"
+ # Debugging Rails controllers
+ gem "httparty"
+ gem "rack-cors"
+ gem "rest-client"
end
group :test do
- # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
- gem "capybara"
- gem "selenium-webdriver"
+ # Testing tools
+ gem "parallel_tests"
+ gem "rspec"
+ gem "rspec-rails"
+ gem "rspec-sidekiq"
+ gem 'rubocop-rspec_rails'
+ gem "shoulda-callback-matchers"
+ gem "shoulda-matchers"
+
+ # Test coverage & logging
+ gem "rspec_junit_formatter"
+ gem "simplecov", require: false
+ gem "simplecov-cobertura", require: false
+ gem "vcr"
+ gem "webmock"
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 2eece38..3ea81f1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,35 +1,35 @@
GEM
remote: https://rubygems.org/
specs:
- actioncable (7.1.3.3)
- actionpack (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ actioncable (7.1.5.1)
+ actionpack (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
- actionmailbox (7.1.3.3)
- actionpack (= 7.1.3.3)
- activejob (= 7.1.3.3)
- activerecord (= 7.1.3.3)
- activestorage (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ actionmailbox (7.1.5.1)
+ actionpack (= 7.1.5.1)
+ activejob (= 7.1.5.1)
+ activerecord (= 7.1.5.1)
+ activestorage (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
mail (>= 2.7.1)
net-imap
net-pop
net-smtp
- actionmailer (7.1.3.3)
- actionpack (= 7.1.3.3)
- actionview (= 7.1.3.3)
- activejob (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ actionmailer (7.1.5.1)
+ actionpack (= 7.1.5.1)
+ actionview (= 7.1.5.1)
+ activejob (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.2)
- actionpack (7.1.3.3)
- actionview (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ actionpack (7.1.5.1)
+ actionview (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
nokogiri (>= 1.8.5)
racc
rack (>= 2.2.4)
@@ -37,95 +37,129 @@ GEM
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
- actiontext (7.1.3.3)
- actionpack (= 7.1.3.3)
- activerecord (= 7.1.3.3)
- activestorage (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ actiontext (7.1.5.1)
+ actionpack (= 7.1.5.1)
+ activerecord (= 7.1.5.1)
+ activestorage (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
- actionview (7.1.3.3)
- activesupport (= 7.1.3.3)
+ actionview (7.1.5.1)
+ activesupport (= 7.1.5.1)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
- active_model_serializers (0.10.14)
+ active_model_serializers (0.10.15)
actionpack (>= 4.1)
activemodel (>= 4.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
- activejob (7.1.3.3)
- activesupport (= 7.1.3.3)
+ activejob (7.1.5.1)
+ activesupport (= 7.1.5.1)
globalid (>= 0.3.6)
- activemodel (7.1.3.3)
- activesupport (= 7.1.3.3)
- activerecord (7.1.3.3)
- activemodel (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ activemodel (7.1.5.1)
+ activesupport (= 7.1.5.1)
+ activerecord (7.1.5.1)
+ activemodel (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
timeout (>= 0.4.0)
- activestorage (7.1.3.3)
- actionpack (= 7.1.3.3)
- activejob (= 7.1.3.3)
- activerecord (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ activestorage (7.1.5.1)
+ actionpack (= 7.1.5.1)
+ activejob (= 7.1.5.1)
+ activerecord (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
marcel (~> 1.0)
- activesupport (7.1.3.3)
+ activesupport (7.1.5.1)
base64
+ benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
+ logger (>= 1.4.2)
minitest (>= 5.1)
mutex_m
+ securerandom (>= 0.3)
tzinfo (~> 2.0)
- addressable (2.8.6)
- public_suffix (>= 2.0.2, < 6.0)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
+ airbrake (13.0.5)
+ airbrake-ruby (~> 6.0)
+ airbrake-ruby (6.2.2)
+ rbtree3 (~> 0.6)
+ ast (2.4.2)
base64 (0.2.0)
bcrypt (3.1.20)
- bigdecimal (3.1.8)
+ benchmark (0.4.0)
+ bigdecimal (3.1.9)
bindex (0.8.1)
- bootsnap (1.18.3)
+ bootsnap (1.18.4)
msgpack (~> 1.2)
- builder (3.2.4)
- capybara (3.40.0)
- addressable
- matrix
- mini_mime (>= 0.1.3)
- nokogiri (~> 1.11)
- rack (>= 1.6.0)
- rack-test (>= 0.6.3)
- regexp_parser (>= 1.5, < 3.0)
- xpath (~> 3.2)
+ brakeman (7.0.0)
+ racc
+ builder (3.3.0)
+ bullet (8.0.1)
+ activesupport (>= 3.0.0)
+ uniform_notifier (~> 1.11)
case_transform (0.2)
activesupport
- concurrent-ruby (1.2.3)
- connection_pool (2.4.1)
+ childprocess (5.1.0)
+ logger (~> 1.5)
+ concurrent-ruby (1.3.5)
+ connection_pool (2.5.0)
+ crack (1.0.0)
+ bigdecimal
+ rexml
crass (1.0.6)
- date (3.3.4)
- debug (1.9.2)
+ csv (3.3.2)
+ date (3.4.1)
+ debug (1.10.0)
irb (~> 1.10)
reline (>= 0.3.8)
+ diff-lcs (1.6.0)
+ docile (1.4.1)
+ domain_name (0.6.20240107)
drb (2.2.1)
- erubi (1.12.0)
+ erubi (1.13.1)
+ factory_bot (6.5.1)
+ activesupport (>= 6.1.0)
+ factory_bot_rails (6.4.4)
+ factory_bot (~> 6.5)
+ railties (>= 5.0.0)
+ faker (3.5.1)
+ i18n (>= 1.8.11, < 2)
globalid (1.2.1)
activesupport (>= 6.1)
- i18n (1.14.5)
+ hashdiff (1.1.2)
+ http-accept (1.7.0)
+ http-cookie (1.0.8)
+ domain_name (~> 0.5)
+ httparty (0.22.0)
+ csv
+ mini_mime (>= 1.0.0)
+ multi_xml (>= 0.5.2)
+ i18n (1.14.7)
concurrent-ruby (~> 1.0)
- importmap-rails (2.0.1)
+ importmap-rails (2.1.0)
actionpack (>= 6.0.0)
activesupport (>= 6.0.0)
railties (>= 6.0.0)
- io-console (0.7.2)
- irb (1.13.1)
+ iniparse (1.5.0)
+ io-console (0.8.0)
+ irb (1.15.1)
+ pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
- jbuilder (2.12.0)
+ jbuilder (2.13.0)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
+ json (2.10.1)
jsonapi-renderer (0.2.2)
- loofah (2.22.0)
+ language_server-protocol (3.17.0.4)
+ logger (1.6.6)
+ loofah (2.24.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
@@ -134,151 +168,314 @@ GEM
net-pop
net-smtp
marcel (1.0.4)
- matrix (0.4.2)
+ mime-types (3.6.0)
+ logger
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2025.0204)
mini_mime (1.1.5)
- minitest (5.23.0)
- msgpack (1.7.2)
- mutex_m (0.2.0)
- net-imap (0.4.11)
+ minitest (5.25.4)
+ msgpack (1.8.0)
+ multi_xml (0.7.1)
+ bigdecimal (~> 3.1)
+ mutex_m (0.3.0)
+ net-imap (0.5.6)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.2)
timeout
- net-smtp (0.5.0)
+ net-smtp (0.5.1)
net-protocol
- nio4r (2.7.3)
- nokogiri (1.16.5-arm64-darwin)
+ netrc (0.11.0)
+ nio4r (2.7.4)
+ nokogiri (1.18.2-aarch64-linux-gnu)
racc (~> 1.4)
- nokogiri (1.16.5-x86_64-linux)
+ nokogiri (1.18.2-aarch64-linux-musl)
racc (~> 1.4)
- psych (5.1.2)
+ nokogiri (1.18.2-arm-linux-gnu)
+ racc (~> 1.4)
+ nokogiri (1.18.2-arm-linux-musl)
+ racc (~> 1.4)
+ nokogiri (1.18.2-arm64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.18.2-x86_64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.18.2-x86_64-linux-gnu)
+ racc (~> 1.4)
+ nokogiri (1.18.2-x86_64-linux-musl)
+ racc (~> 1.4)
+ overcommit (0.66.0)
+ childprocess (>= 0.6.3, < 6)
+ iniparse (~> 1.4)
+ rexml (>= 3.3.9)
+ parallel (1.26.3)
+ parallel_tests (4.9.0)
+ parallel
+ parser (3.3.7.1)
+ ast (~> 2.4.1)
+ racc
+ pp (0.6.2)
+ prettyprint
+ prettyprint (0.2.0)
+ psych (5.2.3)
+ date
stringio
- public_suffix (5.0.5)
- puma (6.4.2)
+ public_suffix (6.0.1)
+ puma (6.6.0)
nio4r (~> 2.0)
- racc (1.7.3)
- rack (3.0.11)
- rack-session (2.0.0)
+ query_diet (0.7.2)
+ racc (1.8.1)
+ rack (3.1.10)
+ rack-cors (2.0.2)
+ rack (>= 2.0.0)
+ rack-session (2.1.0)
+ base64 (>= 0.1.0)
rack (>= 3.0.0)
- rack-test (2.1.0)
+ rack-test (2.2.0)
rack (>= 1.3)
- rackup (2.1.0)
+ rackup (2.2.1)
rack (>= 3)
- webrick (~> 1.8)
- rails (7.1.3.3)
- actioncable (= 7.1.3.3)
- actionmailbox (= 7.1.3.3)
- actionmailer (= 7.1.3.3)
- actionpack (= 7.1.3.3)
- actiontext (= 7.1.3.3)
- actionview (= 7.1.3.3)
- activejob (= 7.1.3.3)
- activemodel (= 7.1.3.3)
- activerecord (= 7.1.3.3)
- activestorage (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ rails (7.1.5.1)
+ actioncable (= 7.1.5.1)
+ actionmailbox (= 7.1.5.1)
+ actionmailer (= 7.1.5.1)
+ actionpack (= 7.1.5.1)
+ actiontext (= 7.1.5.1)
+ actionview (= 7.1.5.1)
+ activejob (= 7.1.5.1)
+ activemodel (= 7.1.5.1)
+ activerecord (= 7.1.5.1)
+ activestorage (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
bundler (>= 1.15.0)
- railties (= 7.1.3.3)
+ railties (= 7.1.5.1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
- rails-html-sanitizer (1.6.0)
+ rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
- nokogiri (~> 1.14)
- railties (7.1.3.3)
- actionpack (= 7.1.3.3)
- activesupport (= 7.1.3.3)
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
+ railties (7.1.5.1)
+ actionpack (= 7.1.5.1)
+ activesupport (= 7.1.5.1)
irb
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
+ rainbow (3.1.1)
rake (13.2.1)
- rdoc (6.6.3.1)
+ rbtree3 (0.7.1)
+ rdoc (6.12.0)
psych (>= 4.0.0)
- redis (5.2.0)
+ redis (5.3.0)
redis-client (>= 0.22.0)
- redis-client (0.22.1)
+ redis-client (0.23.2)
connection_pool
- regexp_parser (2.9.2)
- reline (0.5.7)
+ regexp_parser (2.10.0)
+ reline (0.6.0)
io-console (~> 0.5)
- rexml (3.2.8)
- strscan (>= 3.0.9)
- rubyzip (2.3.2)
- selenium-webdriver (4.21.1)
- base64 (~> 0.2)
- rexml (~> 3.2, >= 3.2.5)
- rubyzip (>= 1.2.2, < 3.0)
- websocket (~> 1.0)
+ rest-client (2.1.0)
+ http-accept (>= 1.7.0, < 2.0)
+ http-cookie (>= 1.0.2, < 2.0)
+ mime-types (>= 1.16, < 4.0)
+ netrc (~> 0.8)
+ rexml (3.4.0)
+ rspec (3.13.0)
+ rspec-core (~> 3.13.0)
+ rspec-expectations (~> 3.13.0)
+ rspec-mocks (~> 3.13.0)
+ rspec-core (3.13.3)
+ rspec-support (~> 3.13.0)
+ rspec-expectations (3.13.3)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.13.0)
+ rspec-mocks (3.13.2)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.13.0)
+ rspec-rails (7.1.1)
+ actionpack (>= 7.0)
+ activesupport (>= 7.0)
+ railties (>= 7.0)
+ rspec-core (~> 3.13)
+ rspec-expectations (~> 3.13)
+ rspec-mocks (~> 3.13)
+ rspec-support (~> 3.13)
+ rspec-sidekiq (5.0.0)
+ rspec-core (~> 3.0)
+ rspec-expectations (~> 3.0)
+ rspec-mocks (~> 3.0)
+ sidekiq (>= 5, < 8)
+ rspec-support (3.13.2)
+ rspec_junit_formatter (0.6.0)
+ rspec-core (>= 2, < 4, != 2.12.0)
+ rubocop (1.71.2)
+ json (~> 2.3)
+ language_server-protocol (>= 3.17.0)
+ parallel (~> 1.10)
+ parser (>= 3.3.0.2)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 2.9.3, < 3.0)
+ rubocop-ast (>= 1.38.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 2.4.0, < 4.0)
+ rubocop-ast (1.38.0)
+ parser (>= 3.3.1.0)
+ rubocop-factory_bot (2.26.1)
+ rubocop (~> 1.61)
+ rubocop-performance (1.23.1)
+ rubocop (>= 1.48.1, < 2.0)
+ rubocop-ast (>= 1.31.1, < 2.0)
+ rubocop-rails (2.29.1)
+ activesupport (>= 4.2.0)
+ rack (>= 1.1)
+ rubocop (>= 1.52.0, < 2.0)
+ rubocop-ast (>= 1.31.1, < 2.0)
+ rubocop-rspec (3.4.0)
+ rubocop (~> 1.61)
+ rubocop-rspec_rails (2.30.0)
+ rubocop (~> 1.61)
+ rubocop-rspec (~> 3, >= 3.0.1)
+ ruby-progressbar (1.13.0)
+ securerandom (0.4.1)
+ shoulda-callback-matchers (1.1.4)
+ activesupport (>= 3)
+ shoulda-matchers (6.4.0)
+ activesupport (>= 5.2.0)
+ sidekiq (7.3.8)
+ base64
+ connection_pool (>= 2.3.0)
+ logger
+ rack (>= 2.2.4)
+ redis-client (>= 0.22.2)
+ simplecov (0.22.0)
+ docile (~> 1.1)
+ simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-cobertura (2.1.0)
+ rexml
+ simplecov (~> 0.19)
+ simplecov-html (0.13.1)
+ simplecov_json_formatter (0.1.4)
+ spring (4.2.1)
+ spring-commands-rspec (1.0.4)
+ spring (>= 0.9.1)
sprockets (4.2.1)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
- sprockets-rails (3.4.2)
- actionpack (>= 5.2)
- activesupport (>= 5.2)
+ sprockets-rails (3.5.2)
+ actionpack (>= 6.1)
+ activesupport (>= 6.1)
sprockets (>= 3.0.0)
+ sqlite3 (1.7.3-aarch64-linux)
+ sqlite3 (1.7.3-arm-linux)
sqlite3 (1.7.3-arm64-darwin)
+ sqlite3 (1.7.3-x86_64-darwin)
sqlite3 (1.7.3-x86_64-linux)
- stimulus-rails (1.3.3)
+ stimulus-rails (1.3.4)
railties (>= 6.0.0)
- stringio (3.1.0)
- strscan (3.1.0)
- tailwindcss-rails (2.6.0-arm64-darwin)
+ stringio (3.1.3)
+ tailwindcss-rails (4.0.0)
railties (>= 7.0.0)
- tailwindcss-rails (2.6.0-x86_64-linux)
- railties (>= 7.0.0)
- thor (1.3.1)
- timeout (0.4.1)
- turbo-rails (2.0.5)
+ tailwindcss-ruby (~> 4.0)
+ tailwindcss-ruby (4.0.6)
+ tailwindcss-ruby (4.0.6-aarch64-linux-gnu)
+ tailwindcss-ruby (4.0.6-aarch64-linux-musl)
+ tailwindcss-ruby (4.0.6-arm64-darwin)
+ tailwindcss-ruby (4.0.6-x86_64-darwin)
+ tailwindcss-ruby (4.0.6-x86_64-linux-gnu)
+ tailwindcss-ruby (4.0.6-x86_64-linux-musl)
+ thor (1.3.2)
+ timeout (0.4.3)
+ turbo-rails (2.0.11)
actionpack (>= 6.0.0)
- activejob (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
+ unicode-display_width (3.1.4)
+ unicode-emoji (~> 4.0, >= 4.0.4)
+ unicode-emoji (4.0.4)
+ uniform_notifier (1.16.0)
+ vcr (6.3.1)
+ base64
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
- webrick (1.8.1)
- websocket (1.2.10)
- websocket-driver (0.7.6)
+ webmock (3.25.0)
+ addressable (>= 2.8.0)
+ crack (>= 0.3.2)
+ hashdiff (>= 0.4.0, < 2.0.0)
+ websocket-driver (0.7.7)
+ base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
- xpath (3.2.0)
- nokogiri (~> 1.8)
- zeitwerk (2.6.14)
+ zeitwerk (2.7.1)
PLATFORMS
- arm64-darwin-23
- x86_64-linux
+ aarch64-linux
+ aarch64-linux-gnu
+ aarch64-linux-musl
+ arm-linux
+ arm-linux-gnu
+ arm-linux-musl
+ arm64-darwin
+ x86_64-darwin
+ x86_64-linux-gnu
+ x86_64-linux-musl
DEPENDENCIES
active_model_serializers
+ airbrake (~> 13.0)
bcrypt (~> 3.1.7)
bootsnap
- capybara
+ brakeman
+ bullet
debug
+ factory_bot_rails
+ faker
+ httparty
importmap-rails
jbuilder
+ overcommit
+ parallel_tests
puma (>= 5.0)
+ query_diet
+ rack-cors
rails (~> 7.1.3, >= 7.1.3.3)
redis (>= 4.0.1)
- selenium-webdriver
+ rest-client
+ rspec
+ rspec-rails
+ rspec-sidekiq
+ rspec_junit_formatter
+ rubocop
+ rubocop-factory_bot
+ rubocop-performance (~> 1.23)
+ rubocop-rails (~> 2.29)
+ rubocop-rspec (~> 3.4)
+ rubocop-rspec_rails
+ shoulda-callback-matchers
+ shoulda-matchers
+ simplecov
+ simplecov-cobertura
+ spring
+ spring-commands-rspec
sprockets-rails
sqlite3 (~> 1.4)
stimulus-rails
tailwindcss-rails
turbo-rails
tzinfo-data
+ vcr
web-console
+ webmock
RUBY VERSION
ruby 3.2.4p170
BUNDLED WITH
- 2.4.19
+ 2.6.3
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
index cd04671..cf5333d 100644
--- a/app/assets/config/manifest.js
+++ b/app/assets/config/manifest.js
@@ -1,5 +1,7 @@
//= link_tree ../images
-//= link_directory ../stylesheets .css
+//= link_tree ../builds
+//= link application.css
+//= link tailwind.css
+//= link controllers/application.js
+//= link controllers/index.js
//= link_tree ../../javascript .js
-//= link_tree ../../../vendor/javascript .js
-//= link_tree ../builds
\ No newline at end of file
diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css
index 08d74a7..73ab48c 100644
--- a/app/assets/stylesheets/application.tailwind.css
+++ b/app/assets/stylesheets/application.tailwind.css
@@ -1,7 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
-
+@import "tailwindcss";
/*
@layer components {
diff --git a/app/assets/tailwind/application.css b/app/assets/tailwind/application.css
new file mode 100644
index 0000000..f1d8c73
--- /dev/null
+++ b/app/assets/tailwind/application.css
@@ -0,0 +1 @@
+@import "tailwindcss";
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 8b6a04c..f79f7ea 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,6 +1,6 @@
class ApplicationController < ActionController::Base
-
private
+
def set_company
company_id = session.fetch(:company_id, Company.first&.id)
session[:company_id] = company_id
diff --git a/app/controllers/companies_controller.rb b/app/controllers/companies_controller.rb
index b673533..3edf8b0 100644
--- a/app/controllers/companies_controller.rb
+++ b/app/controllers/companies_controller.rb
@@ -1,5 +1,5 @@
class CompaniesController < ApplicationController
- before_action :set_company, only: %i[ show edit update destroy ]
+ before_action :set_company, only: %i[show edit update destroy]
# GET /companies or /companies.json
def index
@@ -7,8 +7,7 @@ class CompaniesController < ApplicationController
end
# GET /companies/1 or /companies/1.json
- def show
- end
+ def show; end
# GET /companies/new
def new
@@ -16,8 +15,7 @@ class CompaniesController < ApplicationController
end
# GET /companies/1/edit
- def edit
- end
+ def edit; end
# POST /companies or /companies.json
def create
@@ -25,7 +23,7 @@ class CompaniesController < ApplicationController
respond_to do |format|
if @company.save
- format.html { redirect_to company_url(@company), notice: "Company was successfully created." }
+ format.html { redirect_to company_url(@company), notice: t('.company_created') }
format.json { render :show, status: :created, location: @company }
else
format.html { render :new, status: :unprocessable_entity }
@@ -38,7 +36,7 @@ class CompaniesController < ApplicationController
def update
respond_to do |format|
if @company.update(company_params)
- format.html { redirect_to company_url(@company), notice: "Company was successfully updated." }
+ format.html { redirect_to company_url(@company), notice: t('.company_updated') }
format.json { render :show, status: :ok, location: @company }
else
format.html { render :edit, status: :unprocessable_entity }
@@ -52,19 +50,30 @@ class CompaniesController < ApplicationController
@company.destroy!
respond_to do |format|
- format.html { redirect_to companies_url, notice: "Company was successfully destroyed." }
+ format.html { redirect_to companies_url, notice: t('.company_destroyed') }
format.json { head :no_content }
end
end
private
- # Use callbacks to share common setup or constraints between actions.
- def set_company
- @company = Company.find(params[:id])
- end
- # Only allow a list of trusted parameters through.
- def company_params
- params.require(:company).permit(:name, :id_number, :vat_number, :address_line_one, :address_line_two, :postal_code, :city, :entity, :country)
- end
+ # Use callbacks to share common setup or constraints between actions.
+ def set_company
+ @company = Company.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def company_params
+ params.require(:company).permit(
+ :name,
+ :id_number,
+ :vat_number,
+ :address_line_one,
+ :address_line_two,
+ :postal_code,
+ :city,
+ :entity,
+ :country
+ )
+ end
end
diff --git a/app/controllers/customers_controller.rb b/app/controllers/customers_controller.rb
index 4c7eadf..fa7c725 100644
--- a/app/controllers/customers_controller.rb
+++ b/app/controllers/customers_controller.rb
@@ -1,6 +1,6 @@
class CustomersController < ApplicationController
before_action :set_company
- before_action :set_customer, only: %i[ show edit update destroy ]
+ before_action :set_customer, only: %i[show edit update destroy]
# GET /customers or /customers.json
def index
@@ -8,8 +8,7 @@ class CustomersController < ApplicationController
end
# GET /customers/1 or /customers/1.json
- def show
- end
+ def show; end
# GET /customers/new
def new
@@ -17,8 +16,7 @@ class CustomersController < ApplicationController
end
# GET /customers/1/edit
- def edit
- end
+ def edit; end
# POST /customers or /customers.json
def create
@@ -27,7 +25,7 @@ class CustomersController < ApplicationController
respond_to do |format|
if @customer.save
- format.html { redirect_to customer_url(@customer), notice: "Customer was successfully created." }
+ format.html { redirect_to customer_url(@customer), notice: t('.customer_created') }
format.json { render :show, status: :created, location: @customer }
else
format.html { render :new, status: :unprocessable_entity }
@@ -40,7 +38,7 @@ class CustomersController < ApplicationController
def update
respond_to do |format|
if @customer.update(customer_params)
- format.html { redirect_to customer_url(@customer), notice: "Customer was successfully updated." }
+ format.html { redirect_to customer_url(@customer), notice: t('.customer_updated') }
format.json { render :show, status: :ok, location: @customer }
else
format.html { render :edit, status: :unprocessable_entity }
@@ -54,19 +52,20 @@ class CustomersController < ApplicationController
@customer.destroy!
respond_to do |format|
- format.html { redirect_to customers_url, notice: "Customer was successfully destroyed." }
+ format.html { redirect_to customers_url, notice: t('.customer_destroyed') }
format.json { head :no_content }
end
end
private
- # Use callbacks to share common setup or constraints between actions.
- def set_customer
- @customer = Customer.find(params[:id])
- end
- # Only allow a list of trusted parameters through.
- def customer_params
- params.require(:customer).permit(:name, :phone, :notes, :email, :birthyear)
- end
+ # Use callbacks to share common setup or constraints between actions.
+ def set_customer
+ @customer = Customer.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def customer_params
+ params.require(:customer).permit(:name, :phone, :notes, :email, :birthyear)
+ end
end
diff --git a/app/controllers/reservations_controller.rb b/app/controllers/reservations_controller.rb
index 20e02f3..a61ec09 100644
--- a/app/controllers/reservations_controller.rb
+++ b/app/controllers/reservations_controller.rb
@@ -1,17 +1,16 @@
class ReservationsController < ApplicationController
before_action :set_company
- before_action :set_reservation, only: %i[ show edit update destroy ]
+ before_action :set_reservation, only: %i[show edit update destroy]
layout :determine_layout
# GET /reservations or /reservations.json
def index
- @reservations = Reservation.all.includes(:team, :customer).where(company: @company)
+ @reservations = Reservation.includes(:team, :customer).where(company: @company)
@reservations = ActiveModelSerializers::SerializableResource.new(@reservations).as_json
end
# GET /reservations/1 or /reservations/1.json
- def show
- end
+ def show; end
# GET /reservations/new
def new
@@ -20,8 +19,7 @@ class ReservationsController < ApplicationController
end
# GET /reservations/1/edit
- def edit
- end
+ def edit; end
# POST /reservations or /reservations.json
def create
@@ -30,7 +28,7 @@ class ReservationsController < ApplicationController
respond_to do |format|
if @reservation.save
- format.html { redirect_to reservation_url(@reservation), notice: "Reservation was successfully created." }
+ format.html { redirect_to reservation_url(@reservation), notice: t('.reservation_created') }
format.json { render :show, status: :created, location: @reservation }
else
format.html { render :new, status: :unprocessable_entity }
@@ -43,7 +41,7 @@ class ReservationsController < ApplicationController
def update
respond_to do |format|
if @reservation.update(reservation_params)
- format.html { redirect_to reservation_url(@reservation), notice: "Reservation was successfully updated." }
+ format.html { redirect_to reservation_url(@reservation), notice: t('.reservation_updated') }
format.json { render :show, status: :ok, location: @reservation }
else
format.html { render :edit, status: :unprocessable_entity }
@@ -57,24 +55,25 @@ class ReservationsController < ApplicationController
@reservation.destroy!
respond_to do |format|
- format.html { redirect_to reservations_url, notice: "Reservation was successfully destroyed." }
+ format.html { redirect_to reservations_url, notice: t('.reservation_destroyed') }
format.json { head :no_content }
end
end
private
- # Use callbacks to share common setup or constraints between actions.
- def set_reservation
- @reservation = Reservation.find(params[:id])
- end
- # Only allow a list of trusted parameters through.
- def reservation_params
- params.require(:reservation).permit(:company_id, :customer_id, :team_id, :title, :description, :start_time, :end_time)
- end
+ # Use callbacks to share common setup or constraints between actions.
+ def set_reservation
+ @reservation = Reservation.find(params[:id])
+ end
- def determine_layout
- action_name == 'index' ? 'calendar' : 'application'
- end
+ # Only allow a list of trusted parameters through.
+ def reservation_params
+ params.require(:reservation).permit(:company_id, :customer_id, :team_id, :title, :description, :start_time,
+ :end_time)
+ end
+ def determine_layout
+ action_name == 'index' ? 'calendar' : 'application'
+ end
end
diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb
index 979aff7..375d3ce 100644
--- a/app/controllers/teams_controller.rb
+++ b/app/controllers/teams_controller.rb
@@ -1,5 +1,6 @@
class TeamsController < ApplicationController
- before_action :set_team, only: %i[ show edit update destroy ]
+ before_action :set_company
+ before_action :set_team, only: %i[show edit update destroy]
# GET /teams or /teams.json
def index
@@ -7,8 +8,7 @@ class TeamsController < ApplicationController
end
# GET /teams/1 or /teams/1.json
- def show
- end
+ def show; end
# GET /teams/new
def new
@@ -16,17 +16,16 @@ class TeamsController < ApplicationController
end
# GET /teams/1/edit
- def edit
- end
+ def edit; end
# POST /teams or /teams.json
def create
@team = Team.new(team_params)
- @team.company = Company.first
+ @team.company = @company
respond_to do |format|
if @team.save
- format.html { redirect_to team_url(@team), notice: "Team was successfully created." }
+ format.html { redirect_to team_url(@team), notice: t('.team_created') }
format.json { render :show, status: :created, location: @team }
else
format.html { render :new, status: :unprocessable_entity }
@@ -37,10 +36,9 @@ class TeamsController < ApplicationController
# PATCH/PUT /teams/1 or /teams/1.json
def update
- @team.company = Company.first
respond_to do |format|
if @team.update(team_params)
- format.html { redirect_to team_url(@team), notice: "Team was successfully updated." }
+ format.html { redirect_to team_url(@team), notice: t('.team_updated') }
format.json { render :show, status: :ok, location: @team }
else
format.html { render :edit, status: :unprocessable_entity }
@@ -54,19 +52,20 @@ class TeamsController < ApplicationController
@team.destroy!
respond_to do |format|
- format.html { redirect_to teams_url, notice: "Team was successfully destroyed." }
+ format.html { redirect_to teams_url, notice: t('.team_destroyed') }
format.json { head :no_content }
end
end
private
- # Use callbacks to share common setup or constraints between actions.
- def set_team
- @team = Team.find(params[:id])
- end
- # Only allow a list of trusted parameters through.
- def team_params
- params.require(:team).permit(:name)
- end
+ # Use callbacks to share common setup or constraints between actions.
+ def set_team
+ @team = Team.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def team_params
+ params.require(:team).permit(:name, :description)
+ end
end
diff --git a/app/models/reservation.rb b/app/models/reservation.rb
index 51cbd91..532094d 100644
--- a/app/models/reservation.rb
+++ b/app/models/reservation.rb
@@ -10,4 +10,4 @@ end
class ReservationSerializer < ActiveModel::Serializer
attributes :id, :company, :customer, :team, :start_time, :end_time
-end
\ No newline at end of file
+end
diff --git a/app/serializers/reservatiopn_serializer.rb b/app/serializers/reservatiopn_serializer.rb
index fb3ceac..1faa0ca 100644
--- a/app/serializers/reservatiopn_serializer.rb
+++ b/app/serializers/reservatiopn_serializer.rb
@@ -1,6 +1,5 @@
class ReservationSerializer < ActiveModel::Serializer
- attributes :id, :company_id, :customer_id, :team_id, :title, :description, :start_time, :end_time
-
- belongs_to :team
+ attributes :id, :title, :description, :start_time, :end_time
belongs_to :customer
-end
\ No newline at end of file
+ belongs_to :team
+end
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index b84b013..1cde6ff 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -7,7 +7,8 @@
<%= csp_meta_tag %>
- <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
+
+ <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
diff --git a/app/views/layouts/calendar.html.erb b/app/views/layouts/calendar.html.erb
index 7ea68d4..427618e 100644
--- a/app/views/layouts/calendar.html.erb
+++ b/app/views/layouts/calendar.html.erb
@@ -7,7 +7,8 @@
<%= csp_meta_tag %>
- <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
+
+ <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "calendar.tailwind", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
diff --git a/bin/parallel_cucumber b/bin/parallel_cucumber
new file mode 100755
index 0000000..3e7b968
--- /dev/null
+++ b/bin/parallel_cucumber
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'parallel_cucumber' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("parallel_tests", "parallel_cucumber")
diff --git a/bin/parallel_rspec b/bin/parallel_rspec
new file mode 100755
index 0000000..e7a07f6
--- /dev/null
+++ b/bin/parallel_rspec
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'parallel_rspec' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("parallel_tests", "parallel_rspec")
diff --git a/bin/parallel_spinach b/bin/parallel_spinach
new file mode 100755
index 0000000..2872b8d
--- /dev/null
+++ b/bin/parallel_spinach
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'parallel_spinach' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("parallel_tests", "parallel_spinach")
diff --git a/bin/parallel_test b/bin/parallel_test
new file mode 100755
index 0000000..581278e
--- /dev/null
+++ b/bin/parallel_test
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'parallel_test' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("parallel_tests", "parallel_test")
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 2e7fb48..00a094f 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Metrics/BlockLength
require "active_support/core_ext/integer/time"
Rails.application.configure do
@@ -74,3 +75,4 @@ Rails.application.configure do
# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = true
end
+# rubocop:enable Metrics/BlockLength
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 8ea0151..3a578c4 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -52,12 +52,12 @@ Rails.application.configure do
config.force_ssl = true
# Log to STDOUT by default
- config.logger = ActiveSupport::Logger.new(STDOUT)
- .tap { |logger| logger.formatter = ::Logger::Formatter.new }
- .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
+ 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 ]
+ 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
diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb
index c2d89e2..166997c 100644
--- a/config/initializers/filter_parameter_logging.rb
+++ b/config/initializers/filter_parameter_logging.rb
@@ -1,8 +1,8 @@
# Be sure to restart your server when you modify this file.
-# 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
+# Configure parameters to be 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 += %i[
+ passw secret token _key crypt salt certificate otp ssn
]
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 6c349ae..b736c39 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -29,3 +29,24 @@
en:
hello: "Hello world"
+ customers:
+ create:
+ customer_created: "Customer was successfully created."
+ update:
+ customer_updated: "Customer was successfully updated."
+ destroy:
+ customer_destroyed: "Customer was successfully destroyed."
+ reservations:
+ create:
+ reservation_created: "Reservation was successfully created."
+ update:
+ reservation_updated: "Reservation was successfully updated."
+ destroy:
+ reservation_destroyed: "Reservation was successfully destroyed."
+ teams:
+ create:
+ team_created: "Team was successfully created."
+ update:
+ team_updated: "Team was successfully updated."
+ destroy:
+ team_destroyed: "Team was successfully destroyed."
diff --git a/config/puma.rb b/config/puma.rb
index afa809b..5149b01 100644
--- a/config/puma.rb
+++ b/config/puma.rb
@@ -7,8 +7,8 @@
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
-max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
-min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
+max_threads_count = ENV.fetch("RAILS_MAX_THREADS", 5)
+min_threads_count = ENV.fetch("RAILS_MIN_THREADS", max_threads_count)
threads min_threads_count, max_threads_count
# Specifies that the worker count should equal the number of processors in production.
@@ -23,7 +23,7 @@ end
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
-port ENV.fetch("PORT") { 3000 }
+port ENV.fetch("PORT", 3000)
# Specifies the `environment` that Puma will run in.
environment ENV.fetch("RAILS_ENV") { "development" }
diff --git a/config/routes.rb b/config/routes.rb
index 8033ad0..24638f2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,7 +1,8 @@
Rails.application.routes.draw do
- resources :teams
+ root "reservations#index"
resources :reservations
resources :customers
+ resources :teams
resources :companies
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
diff --git a/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb b/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb
index 8056503..d25fa37 100644
--- a/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb
+++ b/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb
@@ -1,6 +1,6 @@
class RemoveTitleAndDescriptionFromReservations < ActiveRecord::Migration[7.1]
def change
- remove_column :reservations, :title, :string
- remove_column :reservations, :description, :text
+ # remove_column :reservations, :title, :string
+ # remove_column :reservations, :description, :text
end
end
diff --git a/db/migrate/20250217185300_add_index_to_customers.rb b/db/migrate/20250217185300_add_index_to_customers.rb
new file mode 100644
index 0000000..ef82416
--- /dev/null
+++ b/db/migrate/20250217185300_add_index_to_customers.rb
@@ -0,0 +1,5 @@
+class AddIndexToCustomers < ActiveRecord::Migration[7.1]
+ def change
+ add_index :customers, [:name, :company_id], unique: true
+ end
+end
\ No newline at end of file
diff --git a/db/schema.rb b/db/schema.rb
index 0828cb4..03a76ba 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.1].define(version: 2024_08_18_063444) do
+ActiveRecord::Schema[7.1].define(version: 2025_02_17_185300) do
create_table "companies", force: :cascade do |t|
t.string "name"
t.string "id_number"
@@ -34,19 +34,14 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_18_063444) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "company_id"
- end
-
- create_table "places", force: :cascade do |t|
- t.string "name"
- t.integer "company_id", null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["company_id"], name: "index_places_on_company_id"
+ t.index ["name", "company_id"], name: "index_customers_on_name_and_company_id", unique: true
end
create_table "reservations", force: :cascade do |t|
t.integer "company_id", null: false
t.integer "customer_id", null: false
+ t.string "title"
+ t.text "description"
t.datetime "start_time"
t.datetime "end_time"
t.datetime "created_at", null: false
@@ -65,7 +60,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_18_063444) do
t.index ["company_id"], name: "index_teams_on_company_id"
end
- add_foreign_key "places", "companies"
add_foreign_key "reservations", "companies"
add_foreign_key "reservations", "customers"
add_foreign_key "reservations", "teams"
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..091f753
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,99 @@
+# This file was generated by the `rspec --init` command. Conventionally, all
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
+# The generated `.rspec` file contains `--require spec_helper` which will cause
+# this file to always be loaded, without a need to explicitly require it in any
+# files.
+#
+# Given that it is always loaded, you are encouraged to keep this file as
+# light-weight as possible. Requiring heavyweight dependencies from this file
+# will add to the boot time of your test suite on EVERY test run, even for an
+# individual file that may not need all of that loaded. Instead, consider making
+# a separate helper file that requires the additional dependencies and performs
+# the additional setup, and require it from the spec files that actually need
+# it.
+#
+# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+ # rspec-expectations config goes here. You can use an alternate
+ # assertion/expectation library such as wrong or the stdlib/minitest
+ # assertions if you prefer.
+ config.expect_with :rspec do |expectations|
+ # This option will default to `true` in RSpec 4. It makes the `description`
+ # and `failure_message` of custom matchers include text for helper methods
+ # defined using `chain`, e.g.:
+ # be_bigger_than(2).and_smaller_than(4).description
+ # # => "be bigger than 2 and smaller than 4"
+ # ...rather than:
+ # # => "be bigger than 2"
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ # rspec-mocks config goes here. You can use an alternate test double
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
+ config.mock_with :rspec do |mocks|
+ # Prevents you from mocking or stubbing a method that does not exist on
+ # a real object. This is generally recommended, and will default to
+ # `true` in RSpec 4.
+ mocks.verify_partial_doubles = true
+ end
+
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
+ # have no way to turn it off -- the option exists only for backwards
+ # compatibility in RSpec 3). It causes shared context metadata to be
+ # inherited by the metadata hash of host groups and examples, rather than
+ # triggering implicit auto-inclusion in groups with matching metadata.
+ config.shared_context_metadata_behavior = :apply_to_host_groups
+
+ # The settings below are suggested to provide a good initial experience
+ # with RSpec, but feel free to customize to your heart's content.
+ # This file was generated by rspec-rails...
+ # ... rest of the comments ...
+
+ # This allows you to limit a spec run to individual examples or groups
+ # you care about by tagging them with `:focus` metadata. When nothing
+ # is tagged with `:focus`, all examples get run. RSpec also provides
+ # aliases for `it`, `describe`, and `context` that include `:focus`
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
+ # config.filter_run_when_matching :focus
+
+ # Allows RSpec to persist some state between runs in order to support
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
+ # you configure your source control system to ignore this file.
+ # config.example_status_persistence_file_path = "spec/examples.txt"
+
+ # Limits the available syntax to the non-monkey patched syntax that is
+ # recommended. For more details, see:
+ # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/
+ # config.disable_monkey_patching!
+
+ # This setting enables warnings. It's recommended, but in some cases may
+ # be too noisy due to issues in dependencies.
+ # config.warnings = true
+
+ # Many RSpec users commonly either run the entire suite or an individual
+ # file, and it's useful to allow more verbose output when running an
+ # individual spec file.
+ # if config.files_to_run.one?
+ # Use the documentation formatter for detailed output,
+ # unless a formatter has already been configured
+ # (e.g. via a command-line flag).
+ # config.default_formatter = "doc"
+ # end
+
+ # Print the 10 slowest examples and example groups at the
+ # end of the spec run, to help surface which specs are running
+ # particularly slow.
+ # config.profile_examples = 10
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ # config.order = :random
+
+ # Seed global randomization in this process using the `--seed` CLI option.
+ # Setting this allows you to use `--seed` to deterministically reproduce
+ # test failures related to randomization by passing the same `--seed` value
+ # as the one that triggered the failure.
+ # Kernel.srand config.seed
+end
diff --git a/test/controllers/companies_controller_test.rb b/test/controllers/companies_controller_test.rb
index 22012a5..7733fc2 100644
--- a/test/controllers/companies_controller_test.rb
+++ b/test/controllers/companies_controller_test.rb
@@ -17,7 +17,19 @@ class CompaniesControllerTest < ActionDispatch::IntegrationTest
test "should create company" do
assert_difference("Company.count") do
- post companies_url, params: { company: { address_line_one: @company.address_line_one, address_line_two: @company.address_line_two, city: @company.city, country: @company.country, entity: @company.entity, id_number: @company.id_number, name: @company.name, postal_code: @company.postal_code, vat_number: @company.vat_number } }
+ post companies_url, params: {
+ company: {
+ address_line_one: @company.address_line_one,
+ address_line_two: @company.address_line_two,
+ city: @company.city,
+ country: @company.country,
+ entity: @company.entity,
+ id_number: @company.id_number,
+ name: @company.name,
+ postal_code: @company.postal_code,
+ vat_number: @company.vat_number
+ }
+ }
end
assert_redirected_to company_url(Company.last)
@@ -34,7 +46,19 @@ class CompaniesControllerTest < ActionDispatch::IntegrationTest
end
test "should update company" do
- patch company_url(@company), params: { company: { address_line_one: @company.address_line_one, address_line_two: @company.address_line_two, city: @company.city, country: @company.country, entity: @company.entity, id_number: @company.id_number, name: @company.name, postal_code: @company.postal_code, vat_number: @company.vat_number } }
+ patch company_url(@company), params: {
+ company: {
+ address_line_one: @company.address_line_one,
+ address_line_two: @company.address_line_two,
+ city: @company.city,
+ country: @company.country,
+ entity: @company.entity,
+ id_number: @company.id_number,
+ name: @company.name,
+ postal_code: @company.postal_code,
+ vat_number: @company.vat_number
+ }
+ }
assert_redirected_to company_url(@company)
end
diff --git a/test/controllers/customers_controller_test.rb b/test/controllers/customers_controller_test.rb
index b932686..3db8d24 100644
--- a/test/controllers/customers_controller_test.rb
+++ b/test/controllers/customers_controller_test.rb
@@ -17,7 +17,15 @@ class CustomersControllerTest < ActionDispatch::IntegrationTest
test "should create customer" do
assert_difference("Customer.count") do
- post customers_url, params: { customer: { birthyear: @customer.birthyear, email: @customer.email, name: @customer.name, notes: @customer.notes, phone: @customer.phone } }
+ post customers_url, params: {
+ customer: {
+ birthyear: @customer.birthyear,
+ email: @customer.email,
+ name: @customer.name,
+ notes: @customer.notes,
+ phone: @customer.phone
+ }
+ }
end
assert_redirected_to customer_url(Customer.last)
@@ -34,7 +42,15 @@ class CustomersControllerTest < ActionDispatch::IntegrationTest
end
test "should update customer" do
- patch customer_url(@customer), params: { customer: { birthyear: @customer.birthyear, email: @customer.email, name: @customer.name, notes: @customer.notes, phone: @customer.phone } }
+ patch customer_url(@customer), params: {
+ customer: {
+ birthyear: @customer.birthyear,
+ email: @customer.email,
+ name: @customer.name,
+ notes: @customer.notes,
+ phone: @customer.phone
+ }
+ }
assert_redirected_to customer_url(@customer)
end
diff --git a/test/controllers/reservations_controller_test.rb b/test/controllers/reservations_controller_test.rb
index 5060b13..19245fb 100644
--- a/test/controllers/reservations_controller_test.rb
+++ b/test/controllers/reservations_controller_test.rb
@@ -17,7 +17,17 @@ class ReservationsControllerTest < ActionDispatch::IntegrationTest
test "should create reservation" do
assert_difference("Reservation.count") do
- post reservations_url, params: { reservation: { company_id: @reservation.company_id, customer_id: @reservation.customer_id, description: @reservation.description, end_time: @reservation.end_time, place_id: @reservation.place_id, start_time: @reservation.start_time, title: @reservation.title } }
+ post reservations_url, params: {
+ reservation: {
+ company_id: @reservation.company_id,
+ customer_id: @reservation.customer_id,
+ description: @reservation.description,
+ end_time: @reservation.end_time,
+ place_id: @reservation.place_id,
+ start_time: @reservation.start_time,
+ title: @reservation.title
+ }
+ }
end
assert_redirected_to reservation_url(Reservation.last)
@@ -34,7 +44,17 @@ class ReservationsControllerTest < ActionDispatch::IntegrationTest
end
test "should update reservation" do
- patch reservation_url(@reservation), params: { reservation: { company_id: @reservation.company_id, customer_id: @reservation.customer_id, description: @reservation.description, end_time: @reservation.end_time, place_id: @reservation.place_id, start_time: @reservation.start_time, title: @reservation.title } }
+ patch reservation_url(@reservation), params: {
+ reservation: {
+ company_id: @reservation.company_id,
+ customer_id: @reservation.customer_id,
+ description: @reservation.description,
+ end_time: @reservation.end_time,
+ place_id: @reservation.place_id,
+ start_time: @reservation.start_time,
+ title: @reservation.title
+ }
+ }
assert_redirected_to reservation_url(@reservation)
end
diff --git a/test/controllers/teams_controller_test.rb b/test/controllers/teams_controller_test.rb
index 4aea2bd..1535ad9 100644
--- a/test/controllers/teams_controller_test.rb
+++ b/test/controllers/teams_controller_test.rb
@@ -17,7 +17,7 @@ class TeamsControllerTest < ActionDispatch::IntegrationTest
test "should create team" do
assert_difference("Team.count") do
- post teams_url, params: { team: { } }
+ post teams_url, params: { team: {} }
end
assert_redirected_to team_url(Team.last)
@@ -34,7 +34,7 @@ class TeamsControllerTest < ActionDispatch::IntegrationTest
end
test "should update team" do
- patch team_url(@team), params: { team: { } }
+ patch team_url(@team), params: { team: {} }
assert_redirected_to team_url(@team)
end