diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 4711ba5f..6db8e5f0 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -17,10 +17,37 @@ jobs: # needed because the postgres container does not provide a healthcheck options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + mysql: + image: mysql:8.0 + env: + MYSQL_DATABASE: "maglev_engine_test" + MYSQL_ROOT_PASSWORD: "password" + ports: + - 3306:3306 + options: >- + --health-cmd "mysqladmin ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + mariadb: + image: mariadb:11.8 + env: + MARIADB_DATABASE: "maglev_engine_test" + MARIADB_ROOT_PASSWORD: "password" + ports: + - 3307:3306 + options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3 + strategy: matrix: - node: [20, 23] - gemfile: ["Gemfile.rails_7_0", "Gemfile.rails_7_2", "Gemfile"] + gemfile: ["Gemfile", "Gemfile.rails_7_0", "Gemfile.rails_7_2"] + database: [postgres, sqlite, mysql, mariadb] + exclude: + - gemfile: Gemfile.rails_7_0 + database: mysql + - gemfile: Gemfile.rails_7_0 + database: mariadb steps: - name: Checkout code @@ -41,17 +68,22 @@ jobs: run: | corepack enable - - name: Use Node.js ${{ matrix.node }} + - name: Use Node.js v23 uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node }} + node-version: 23 cache: yarn - name: Install packages run: | yarn install - - name: Setup test database + - name: Run Javascript tests + run: yarn test + + # === Postgresql 🐘 === + - name: Setup test database (Postgresql) 🐘 + if: ${{ matrix.database == 'postgres' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -60,14 +92,17 @@ jobs: run: | bin/rails db:setup - - name: Run Rails tests + - name: Run Rails tests (Postgresql) 🐘 + if: ${{ matrix.database == 'postgres' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} MAGLEV_APP_DATABASE_USERNAME: "maglev" MAGLEV_APP_DATABASE_PASSWORD: "password" - run: bundle exec rspec + run: bundle exec rspec - - name: Setup test database (SQLite) + # === SQLite 🪽 === + - name: Setup test database (SQLite) 🪽 + if: ${{ matrix.database == 'sqlite' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -79,21 +114,64 @@ jobs: cp spec/legacy_dummy/db/schema.sqlite.rb spec/legacy_dummy/db/schema.rb bin/rails db:setup - - name: Run Rails tests (SQLite) + - name: Run Rails tests (SQLite) 🪽 + if: ${{ matrix.database == 'sqlite' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} - USE_SQLITE: true + USE_SQLITE: 1 run: bundle exec rspec - - name: Cleanup DB schema files + # === MYSQL 🐬 === + - name: Setup test database (MySQL) 🐬 + if: ${{ matrix.database == 'mysql' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + RAILS_ENV: test + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_USERNAME: "root" + MAGLEV_APP_DATABASE_PASSWORD: "password" run: | - cp spec/dummy/db/schema.pg.rb spec/dummy/db/schema.rb - cp spec/legacy_dummy/db/schema.pg.rb spec/legacy_dummy/db/schema.rb - rm -f spec/dummy/db/maglev_engine_test.sqlite3 - rm -f spec/legacy_dummy/db/maglev_engine_test.sqlite3 + cp spec/dummy/db/schema.mysql.rb spec/dummy/db/schema.rb + cp spec/legacy_dummy/db/schema.mysql.rb spec/legacy_dummy/db/schema.rb + bin/rails db:setup - - name: Run Javascript tests - run: yarn test + - name: Run Rails tests (MySQL) 🐬 + if: ${{ matrix.database == 'mysql' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_USERNAME: "root" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: bundle exec rspec + + # === MariaDB 🦭=== + - name: Setup test database (MariaDB) 🦭 + if: ${{ matrix.database == 'mariadb' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + RAILS_ENV: test + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_PORT: 3307 + MAGLEV_APP_DATABASE_USERNAME: "root" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: | + cp spec/dummy/db/schema.mariadb.rb spec/dummy/db/schema.rb + cp spec/legacy_dummy/db/schema.mariadb.rb spec/legacy_dummy/db/schema.rb + bin/rails db:setup + + - name: Run Rails tests (MariaDB) 🦭 + if: ${{ matrix.database == 'mariadb' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_PORT: 3307 + MAGLEV_APP_DATABASE_USERNAME: "root" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: bundle exec rspec # NOTE: disabled because an error of eslint in the GH env # - name: Run Javascript linter diff --git a/.gitignore b/.gitignore index 11e7ed5e..f2ed2328 100644 --- a/.gitignore +++ b/.gitignore @@ -40,5 +40,8 @@ bin/test spec/dummy/db/*.sqlite3 spec/legacy_dummy/db/*.sqlite3 +docker-compose.yml +db/mysql/init/01-init-databases.sql + docs/ TODO.md \ No newline at end of file diff --git a/Gemfile b/Gemfile index 69b5a9e5..1493e788 100644 --- a/Gemfile +++ b/Gemfile @@ -30,7 +30,8 @@ gem 'puma' # To use a debugger # gem 'byebug', group: [:development, :test] -# Use SQLite/PostgreSQL for development and test +# Use SQLite/PostgreSQL/MariaDB for development and test +gem 'mysql2' gem 'pg', '~> 1.5.9' gem 'sqlite3' @@ -55,6 +56,8 @@ group :development, :test do gem 'annotaterb' gem 'rdoc', '>= 6.6.3.1' + + gem 'dotenv' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index f7642d91..2eff1495 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,6 +96,7 @@ GEM date (3.4.1) diff-lcs (1.5.1) docile (1.4.1) + dotenv (3.1.8) drb (2.2.3) dry-cli (1.2.0) erubi (1.13.0) @@ -161,6 +162,7 @@ GEM mini_portile2 (2.8.9) minitest (5.25.5) mutex_m (0.3.0) + mysql2 (0.5.6) net-imap (0.5.8) date net-protocol @@ -369,10 +371,12 @@ PLATFORMS DEPENDENCIES annotaterb bcrypt + dotenv factory_bot_rails (~> 6.2.0) generator_spec image_processing (~> 1.12.2) maglevcms! + mysql2 nokogiri (>= 1.15.6) observer ostruct diff --git a/Gemfile.rails_7_0 b/Gemfile.rails_7_0 index dbb5d106..181c31c1 100644 --- a/Gemfile.rails_7_0 +++ b/Gemfile.rails_7_0 @@ -36,6 +36,7 @@ gem 'puma' # Use SQLite/PostgreSQL for development and test gem 'pg', '~> 1.5.9' gem 'sqlite3', '~> 1.4' +gem 'mysql2', '~> 0.5.6' # Gems no longer be part of the default gems from Ruby 3.5.0 gem 'observer' @@ -45,6 +46,7 @@ gem 'bigdecimal' gem 'mutex_m' gem 'drb' gem 'fiddle' +gem 'benchmark' group :development, :test do # Use SCSS for stylesheets @@ -60,6 +62,10 @@ group :development, :test do gem 'generator_spec' gem 'nokogiri', '>= 1.13.10' + + gem 'dotenv' + + gem 'database_cleaner-active_record' end group :test do diff --git a/Gemfile.rails_7_0.lock b/Gemfile.rails_7_0.lock index 10f4bf07..6d838d75 100644 --- a/Gemfile.rails_7_0.lock +++ b/Gemfile.rails_7_0.lock @@ -80,13 +80,19 @@ GEM ast (2.4.2) base64 (0.2.0) bcrypt (3.1.20) + benchmark (0.4.1) bigdecimal (3.1.9) builder (3.3.0) concurrent-ruby (1.3.4) crass (1.0.6) + database_cleaner-active_record (2.2.2) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0) + database_cleaner-core (2.0.1) date (3.4.0) diff-lcs (1.5.1) docile (1.4.1) + dotenv (3.1.8) drb (2.2.1) dry-cli (1.2.0) erubi (1.13.0) @@ -141,6 +147,7 @@ GEM mini_portile2 (2.8.9) minitest (5.25.1) mutex_m (0.3.0) + mysql2 (0.5.6) net-imap (0.5.1) date net-protocol @@ -302,7 +309,10 @@ PLATFORMS DEPENDENCIES base64 bcrypt + benchmark bigdecimal + database_cleaner-active_record + dotenv drb factory_bot_rails (~> 6.2.0) fiddle @@ -311,6 +321,7 @@ DEPENDENCIES maglevcms! mini_magick (~> 4.11) mutex_m + mysql2 (~> 0.5.6) nokogiri (>= 1.13.10) observer ostruct diff --git a/Gemfile.rails_7_2 b/Gemfile.rails_7_2 index 62210536..01087ad6 100644 --- a/Gemfile.rails_7_2 +++ b/Gemfile.rails_7_2 @@ -39,6 +39,7 @@ gem 'puma' # Use SQLite/PostgreSQL for development and test gem 'pg', '~> 1.5.9' gem 'sqlite3' +gem 'mysql2', '~> 0.5.6' # Gems no longer be part of the default gems from Ruby 3.5.0 gem 'observer' @@ -60,6 +61,10 @@ group :development, :test do gem 'nokogiri', '>= 1.15.6' gem 'rdoc', '>= 6.6.3.1' + + gem 'dotenv' + + gem 'database_cleaner-active_record' end group :test do diff --git a/Gemfile.rails_7_2.lock b/Gemfile.rails_7_2.lock index e094a6ea..9ffc4d76 100644 --- a/Gemfile.rails_7_2.lock +++ b/Gemfile.rails_7_2.lock @@ -92,9 +92,14 @@ GEM concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) + database_cleaner-active_record (2.2.2) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0) + database_cleaner-core (2.0.1) date (3.4.0) diff-lcs (1.5.1) docile (1.4.1) + dotenv (3.1.8) drb (2.2.1) dry-cli (1.2.0) erubi (1.13.0) @@ -151,6 +156,7 @@ GEM mini_portile2 (2.8.9) minitest (5.25.2) mutex_m (0.3.0) + mysql2 (0.5.6) net-imap (0.5.1) date net-protocol @@ -343,10 +349,13 @@ PLATFORMS DEPENDENCIES bcrypt + database_cleaner-active_record + dotenv factory_bot_rails (~> 6.2.0) generator_spec image_processing (~> 1.12.2) maglevcms! + mysql2 (~> 0.5.6) nokogiri (>= 1.15.6) observer ostruct diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index a3e12511..dd0557c3 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -8,20 +8,38 @@ class UnavailableLocaleError < RuntimeError; end extend ActiveSupport::Concern def translations_for(attr) - public_send("#{attr}_translations") + # With MySQL, there is no default value for JSON columns, so we need to check for nil + public_send("#{attr}_translations").presence || {} end def translate_attr_in(attr, locale, source_locale) translations_for(attr)[locale.to_s] ||= translations_for(attr)[source_locale.to_s] end + # rubocop:disable Metrics/BlockLength class_methods do def order_by_translated(attr, direction) - order(Arel.sql("#{attr}_translations->>'#{Maglev::I18n.current_locale}'") => direction) + order(translated_arel_attribute(attr, Maglev::I18n.current_locale) => direction) + end + + def translated_arel_attribute(attr, locale) + return Arel.sql("#{attr}_translations->>'#{locale}'") unless mysql? + + # MySQL and MariaDB JSON support 🤬🤬🤬 + # Note: doesn't work with Rails 7.0.x + json_extract = Arel::Nodes::NamedFunction.new( + 'json_extract', + [Arel::Nodes::SqlLiteral.new("#{attr}_translations"), Arel::Nodes.build_quoted("$.#{locale}")] + ) + Arel::Nodes::NamedFunction.new('json_unquote', [json_extract]) end def translates(*attributes, presence: false) - attributes.each { |attr| setup_accessors(attr) } + attributes.each do |attr| + # MariaDB doesn't support native JSON columns (longtext instead), we need to force it. + attribute("#{attr}_translations", :json) if respond_to?(:attribute) + setup_accessors(attr) + end add_presence_validator(attributes) if presence end @@ -45,5 +63,6 @@ def setup_accessors(attr) define_method("default_#{attr}") { translations_for(attr)[Maglev::I18n.default_locale.to_s] } end end + # rubocop:enable Metrics/BlockLength end end diff --git a/app/models/maglev/application_record.rb b/app/models/maglev/application_record.rb index f6c87688..5422b446 100644 --- a/app/models/maglev/application_record.rb +++ b/app/models/maglev/application_record.rb @@ -3,5 +3,15 @@ module Maglev class ApplicationRecord < ActiveRecord::Base self.abstract_class = true + + def self.mysql? + connection.adapter_name.downcase == 'mysql2' + end + + private + + def mysql? + self.class.mysql? + end end end diff --git a/app/models/maglev/page/search_concern.rb b/app/models/maglev/page/search_concern.rb index 865201a4..16fd0158 100644 --- a/app/models/maglev/page/search_concern.rb +++ b/app/models/maglev/page/search_concern.rb @@ -32,9 +32,7 @@ def search_path_clause(query, locale) end def search_title_node(locale) - Arel::Nodes::InfixOperation.new('->>', - arel_table[:title_translations], - Arel::Nodes.build_quoted(locale)) + translated_arel_attribute(:title, locale) end end end diff --git a/app/models/maglev/site.rb b/app/models/maglev/site.rb index 778e7735..18539b1f 100644 --- a/app/models/maglev/site.rb +++ b/app/models/maglev/site.rb @@ -20,6 +20,10 @@ class Site < ApplicationRecord include Maglev::SectionsConcern include Maglev::Translatable + ## force JSON columns for MariaDB ## + attribute :style, :json + attribute :sections_translations, :json + ## translations ## translates :sections diff --git a/app/models/maglev/site/locales_concern.rb b/app/models/maglev/site/locales_concern.rb index 13b1d484..9b88722d 100644 --- a/app/models/maglev/site/locales_concern.rb +++ b/app/models/maglev/site/locales_concern.rb @@ -5,12 +5,8 @@ module Maglev::Site::LocalesConcern extend ActiveSupport::Concern included do - ## serializers ## - if Rails::VERSION::MAJOR >= 8 || (Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR.positive?) - serialize :locales, coder: LocalesSerializer - else - serialize :locales, LocalesSerializer - end + ## custom column type ## + attribute :locales, :maglev_locales ## validation ## validates :locales, 'maglev/collection': true, length: { minimum: 1 } @@ -42,15 +38,5 @@ def each_locale end end end - - class LocalesSerializer - def self.dump(array) - (array || []).map(&:as_json) - end - - def self.load(array) - (array || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } - end - end end # rubocop:enable Style/ClassAndModuleChildren diff --git a/app/services/maglev/fetch_style.rb b/app/services/maglev/fetch_style.rb index 25047c7a..093a2a66 100644 --- a/app/services/maglev/fetch_style.rb +++ b/app/services/maglev/fetch_style.rb @@ -31,7 +31,7 @@ def build_style_value(setting) end def custom_value(setting) - value = site.style.find { |local_value| local_value['id'] == setting.id } + value = (site.style || []).find { |local_value| local_value['id'] == setting.id } value && value['type'] == setting.type ? value['value'] : setting.default end end diff --git a/app/types/maglev/locales_type.rb b/app/types/maglev/locales_type.rb new file mode 100644 index 00000000..1720f89b --- /dev/null +++ b/app/types/maglev/locales_type.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Maglev + class LocalesType < ActiveRecord::Type::Json + def deserialize(value) + (super || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } + end + end +end diff --git a/config/initializers/active_record_types.rb b/config/initializers/active_record_types.rb new file mode 100644 index 00000000..a4f466ae --- /dev/null +++ b/config/initializers/active_record_types.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +require_relative '../../app/types/maglev/locales_type' + +ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) diff --git a/config/initializers/migration_patches.rb b/config/initializers/migration_patches.rb new file mode 100644 index 00000000..bd1c2856 --- /dev/null +++ b/config/initializers/migration_patches.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module ActiveRecord + class Migration + def mysql? + connection.adapter_name.downcase == 'mysql2' + end + end +end diff --git a/db/migrate/20200831101942_create_maglev_section_content.rb b/db/migrate/20200831101942_create_maglev_section_content.rb index d41c20c0..581bcfda 100644 --- a/db/migrate/20200831101942_create_maglev_section_content.rb +++ b/db/migrate/20200831101942_create_maglev_section_content.rb @@ -3,6 +3,8 @@ def change change_table :maglev_sites do |t| if t.respond_to? :jsonb t.jsonb :sections, default: [] + elsif mysql? + t.json :sections # MySQL doesn't support default values for json columns else t.json :sections, default: [] end @@ -11,6 +13,8 @@ def change change_table :maglev_pages do |t| if t.respond_to? :jsonb t.jsonb :sections, default: [] + elsif mysql? + t.json :sections # MySQL doesn't support default values for json columns else t.json :sections, default: [] end diff --git a/db/migrate/20210819092740_switch_to_localized_page_fields.rb b/db/migrate/20210819092740_switch_to_localized_page_fields.rb index dac5ba4a..c08d21ee 100644 --- a/db/migrate/20210819092740_switch_to_localized_page_fields.rb +++ b/db/migrate/20210819092740_switch_to_localized_page_fields.rb @@ -1,12 +1,18 @@ class SwitchToLocalizedPageFields < ActiveRecord::Migration[6.1] def up - remove_columns :maglev_pages, :title, :seo_title, :meta_description - + remove_column :maglev_pages, :title if column_exists?(:maglev_pages, :title) + remove_column :maglev_pages, :seo_title if column_exists?(:maglev_pages, :seo_title) + remove_column :maglev_pages, :meta_description if column_exists?(:maglev_pages, :meta_description) + change_table :maglev_pages do |t| if t.respond_to? :jsonb t.jsonb :title_translations, default: {} t.jsonb :seo_title_translations, default: {} t.jsonb :meta_description_translations, default: {} + elsif mysql? + t.json :title_translations + t.json :seo_title_translations + t.json :meta_description_translations else t.json :title_translations, default: {} t.json :seo_title_translations, default: {} diff --git a/db/migrate/20211008064437_add_locales_to_sites.rb b/db/migrate/20211008064437_add_locales_to_sites.rb index 083642df..c2338169 100644 --- a/db/migrate/20211008064437_add_locales_to_sites.rb +++ b/db/migrate/20211008064437_add_locales_to_sites.rb @@ -3,6 +3,8 @@ def change change_table :maglev_sites do |t| if t.respond_to? :jsonb t.jsonb :locales, default: [] + elsif mysql? + t.json :locales # MySQL doesn't support default values for json columns else t.json :locales, default: [] end diff --git a/db/migrate/20211013210954_translate_section_content.rb b/db/migrate/20211013210954_translate_section_content.rb index ecdc2567..0d23333d 100644 --- a/db/migrate/20211013210954_translate_section_content.rb +++ b/db/migrate/20211013210954_translate_section_content.rb @@ -1,11 +1,13 @@ class TranslateSectionContent < ActiveRecord::Migration[6.0] def change - remove_column :maglev_sites, :sections, :jsonb, default: [] - remove_column :maglev_pages, :sections, :jsonb, default: [] + remove_column :maglev_sites, :sections, :jsonb, default: [] if column_exists?(:maglev_sites, :sections) + remove_column :maglev_pages, :sections, :jsonb, default: [] if column_exists?(:maglev_pages, :sections) change_table :maglev_sites do |t| if t.respond_to? :jsonb t.jsonb :sections_translations, default: {} + elsif mysql? + t.json :sections_translations # MySQL doesn't support default values for json columns else t.json :sections_translations, default: {} end @@ -14,6 +16,8 @@ def change change_table :maglev_pages do |t| if t.respond_to? :jsonb t.jsonb :sections_translations, default: {} + elsif mysql? + t.json :sections_translations # MySQL doesn't support default values for json columns else t.json :sections_translations, default: {} end diff --git a/db/migrate/20211203224112_add_open_graph_tags_to_pages.rb b/db/migrate/20211203224112_add_open_graph_tags_to_pages.rb index 2af44234..615f46b8 100644 --- a/db/migrate/20211203224112_add_open_graph_tags_to_pages.rb +++ b/db/migrate/20211203224112_add_open_graph_tags_to_pages.rb @@ -5,6 +5,10 @@ def change t.jsonb :og_title_translations, default: {} t.jsonb :og_description_translations, default: {} t.jsonb :og_image_url_translations, default: {} + elsif mysql? + t.json :og_title_translations + t.json :og_description_translations + t.json :og_image_url_translations else t.json :og_title_translations, default: {} t.json :og_description_translations, default: {} diff --git a/db/migrate/20220612092235_add_style_to_sites.rb b/db/migrate/20220612092235_add_style_to_sites.rb index 6a81df81..1d035c4c 100644 --- a/db/migrate/20220612092235_add_style_to_sites.rb +++ b/db/migrate/20220612092235_add_style_to_sites.rb @@ -3,6 +3,8 @@ def change change_table :maglev_sites do |t| if t.respond_to? :jsonb t.jsonb :style, default: [] + elsif mysql? + t.json :style # MySQL doesn't support default values for json columns else t.json :style, default: [] end diff --git a/maglevcms.gemspec b/maglevcms.gemspec index aeade60d..9743b240 100644 --- a/maglevcms.gemspec +++ b/maglevcms.gemspec @@ -43,7 +43,7 @@ Gem::Specification.new do |spec| 'MIT-LICENSE', 'Rakefile', 'README.md' - ] + ].reject { |f| f.start_with?('db/mysql') } spec.add_dependency 'jbuilder', '< 3', '>= 2' spec.add_dependency 'kaminari', '~> 1.2.1' diff --git a/spec/dummy/config/boot.rb b/spec/dummy/config/boot.rb index 6d2cba07..1e9b9192 100644 --- a/spec/dummy/config/boot.rb +++ b/spec/dummy/config/boot.rb @@ -4,4 +4,7 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) + +require 'dotenv/load' + $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml index 761b4835..f54a2daa 100644 --- a/spec/dummy/config/database.yml +++ b/spec/dummy/config/database.yml @@ -19,6 +19,15 @@ default: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 + <% elsif ENV['USE_MYSQL'] %> + adapter: mysql2 + encoding: utf8mb4 + collation: utf8mb4_unicode_ci + host: <%= ENV.fetch('MAGLEV_APP_DATABASE_HOST') { 'localhost' } %> + username: <%= ENV.fetch('MAGLEV_APP_DATABASE_USERNAME') { 'start' } %> + password: <%= ENV.fetch('MAGLEV_APP_DATABASE_PASSWORD') { 'start' } %> + port: <%= ENV.fetch('MAGLEV_APP_DATABASE_PORT') { '3306' } %> + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> <% else %> adapter: postgresql encoding: unicode diff --git a/spec/dummy/db/schema.mariadb.rb b/spec/dummy/db/schema.mariadb.rb new file mode 100644 index 00000000..52322c20 --- /dev/null +++ b/spec/dummy/db/schema.mariadb.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[8.0].define(version: 20_220_612_092_235) do + create_table 'accounts', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'email' + t.string 'password_digest' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'active_storage_attachments', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name', null: false + t.string 'record_type', null: false + t.bigint 'record_id', null: false + t.bigint 'blob_id', null: false + t.datetime 'created_at', precision: nil, null: false + t.index ['blob_id'], name: 'index_active_storage_attachments_on_blob_id' + t.index %w[record_type record_id name blob_id], name: 'index_active_storage_attachments_uniqueness', + unique: true + end + + create_table 'active_storage_blobs', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'key', null: false + t.string 'filename', null: false + t.string 'content_type' + t.text 'metadata' + t.bigint 'byte_size', null: false + t.string 'checksum', null: false + t.datetime 'created_at', precision: nil, null: false + t.string 'service_name', null: false + t.index ['key'], name: 'index_active_storage_blobs_on_key', unique: true + end + + create_table 'active_storage_variant_records', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', + force: :cascade do |t| + t.bigint 'blob_id', null: false + t.string 'variation_digest', null: false + t.index %w[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true + end + + create_table 'maglev_assets', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'filename' + t.string 'content_type' + t.integer 'width' + t.integer 'height' + t.integer 'byte_size' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'maglev_page_paths', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.bigint 'maglev_page_id' + t.string 'locale', null: false + t.string 'value', null: false + t.boolean 'canonical', default: true + t.index %w[canonical locale value], name: 'canonical_speed' + t.index %w[canonical maglev_page_id locale], name: 'scoped_canonical_speed' + t.index ['maglev_page_id'], name: 'index_maglev_page_paths_on_maglev_page_id' + end + + create_table 'maglev_pages', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.boolean 'visible', default: true + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.text 'title_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.text 'seo_title_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.text 'meta_description_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.text 'sections_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.integer 'lock_version' + t.text 'og_title_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.text 'og_description_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.text 'og_image_url_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.check_constraint 'json_valid(`meta_description_translations`)', name: 'meta_description_translations' + t.check_constraint 'json_valid(`og_description_translations`)', name: 'og_description_translations' + t.check_constraint 'json_valid(`og_image_url_translations`)', name: 'og_image_url_translations' + t.check_constraint 'json_valid(`og_title_translations`)', name: 'og_title_translations' + t.check_constraint 'json_valid(`sections_translations`)', name: 'sections_translations' + t.check_constraint 'json_valid(`seo_title_translations`)', name: 'seo_title_translations' + t.check_constraint 'json_valid(`title_translations`)', name: 'title_translations' + end + + create_table 'maglev_sites', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.text 'locales', size: :long, default: '[]', collation: 'utf8mb4_bin' + t.text 'sections_translations', size: :long, default: '{}', collation: 'utf8mb4_bin' + t.integer 'lock_version' + t.text 'style', size: :long, default: '[]', collation: 'utf8mb4_bin' + t.check_constraint 'json_valid(`locales`)', name: 'locales' + t.check_constraint 'json_valid(`sections_translations`)', name: 'sections_translations' + t.check_constraint 'json_valid(`style`)', name: 'style' + end + + create_table 'products', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.string 'sku' + t.float 'price' + t.boolean 'sold_out', default: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + add_foreign_key 'active_storage_attachments', 'active_storage_blobs', column: 'blob_id' + add_foreign_key 'active_storage_variant_records', 'active_storage_blobs', column: 'blob_id' +end diff --git a/spec/dummy/db/schema.mysql.rb b/spec/dummy/db/schema.mysql.rb new file mode 100644 index 00000000..e4025c2f --- /dev/null +++ b/spec/dummy/db/schema.mysql.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[8.0].define(version: 20_220_612_092_235) do + create_table 'accounts', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'email' + t.string 'password_digest' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'active_storage_attachments', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name', null: false + t.string 'record_type', null: false + t.bigint 'record_id', null: false + t.bigint 'blob_id', null: false + t.datetime 'created_at', precision: nil, null: false + t.index ['blob_id'], name: 'index_active_storage_attachments_on_blob_id' + t.index %w[record_type record_id name blob_id], name: 'index_active_storage_attachments_uniqueness', + unique: true + end + + create_table 'active_storage_blobs', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'key', null: false + t.string 'filename', null: false + t.string 'content_type' + t.text 'metadata' + t.bigint 'byte_size', null: false + t.string 'checksum', null: false + t.datetime 'created_at', precision: nil, null: false + t.string 'service_name', null: false + t.index ['key'], name: 'index_active_storage_blobs_on_key', unique: true + end + + create_table 'active_storage_variant_records', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', + force: :cascade do |t| + t.bigint 'blob_id', null: false + t.string 'variation_digest', null: false + t.index %w[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true + end + + create_table 'maglev_assets', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'filename' + t.string 'content_type' + t.integer 'width' + t.integer 'height' + t.integer 'byte_size' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'maglev_page_paths', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.bigint 'maglev_page_id' + t.string 'locale', null: false + t.string 'value', null: false + t.boolean 'canonical', default: true + t.index %w[canonical locale value], name: 'canonical_speed' + t.index %w[canonical maglev_page_id locale], name: 'scoped_canonical_speed' + t.index ['maglev_page_id'], name: 'index_maglev_page_paths_on_maglev_page_id' + end + + create_table 'maglev_pages', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.boolean 'visible', default: true + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.json 'title_translations' + t.json 'seo_title_translations' + t.json 'meta_description_translations' + t.json 'sections_translations' + t.integer 'lock_version' + t.json 'og_title_translations' + t.json 'og_description_translations' + t.json 'og_image_url_translations' + end + + create_table 'maglev_sites', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.json 'locales' + t.json 'sections_translations' + t.integer 'lock_version' + t.json 'style' + end + + create_table 'products', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.string 'sku' + t.float 'price' + t.boolean 'sold_out', default: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + add_foreign_key 'active_storage_attachments', 'active_storage_blobs', column: 'blob_id' + add_foreign_key 'active_storage_variant_records', 'active_storage_blobs', column: 'blob_id' +end diff --git a/spec/legacy_dummy/config/boot.rb b/spec/legacy_dummy/config/boot.rb index 6d2cba07..1e9b9192 100644 --- a/spec/legacy_dummy/config/boot.rb +++ b/spec/legacy_dummy/config/boot.rb @@ -4,4 +4,7 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) + +require 'dotenv/load' + $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/spec/legacy_dummy/config/database.yml b/spec/legacy_dummy/config/database.yml index 3dbd2eb2..ecb4bf34 100644 --- a/spec/legacy_dummy/config/database.yml +++ b/spec/legacy_dummy/config/database.yml @@ -19,6 +19,15 @@ default: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 + <% elsif ENV['USE_MYSQL'] %> + adapter: mysql2 + encoding: utf8mb4 + collation: utf8mb4_unicode_ci + host: <%= ENV.fetch('MAGLEV_APP_DATABASE_HOST') { 'localhost' } %> + username: <%= ENV.fetch('MAGLEV_APP_DATABASE_USERNAME') { 'start' } %> + password: <%= ENV.fetch('MAGLEV_APP_DATABASE_PASSWORD') { 'start' } %> + port: <%= ENV.fetch('MAGLEV_APP_DATABASE_PORT') { '3306' } %> + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> <% else %> adapter: postgresql encoding: unicode diff --git a/spec/legacy_dummy/config/environments/test.rb b/spec/legacy_dummy/config/environments/test.rb index 151eab39..e361f3da 100644 --- a/spec/legacy_dummy/config/environments/test.rb +++ b/spec/legacy_dummy/config/environments/test.rb @@ -51,7 +51,4 @@ # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - - # Raises error for missing translations. - # config.action_view.raise_on_missing_translations = true end diff --git a/spec/legacy_dummy/db/schema.mariadb.rb b/spec/legacy_dummy/db/schema.mariadb.rb new file mode 100644 index 00000000..be31467a --- /dev/null +++ b/spec/legacy_dummy/db/schema.mariadb.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 20_220_612_092_235) do + create_table 'accounts', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'email' + t.string 'password_digest' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'active_storage_attachments', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name', null: false + t.string 'record_type', null: false + t.bigint 'record_id', null: false + t.bigint 'blob_id', null: false + t.datetime 'created_at', precision: nil, null: false + t.index ['blob_id'], name: 'index_active_storage_attachments_on_blob_id' + t.index %w[record_type record_id name blob_id], name: 'index_active_storage_attachments_uniqueness', + unique: true + end + + create_table 'active_storage_blobs', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'key', null: false + t.string 'filename', null: false + t.string 'content_type' + t.text 'metadata' + t.bigint 'byte_size', null: false + t.string 'checksum', null: false + t.datetime 'created_at', precision: nil, null: false + t.string 'service_name', null: false + t.index ['key'], name: 'index_active_storage_blobs_on_key', unique: true + end + + create_table 'active_storage_variant_records', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', + force: :cascade do |t| + t.bigint 'blob_id', null: false + t.string 'variation_digest', null: false + t.index %w[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true + end + + create_table 'maglev_assets', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'filename' + t.string 'content_type' + t.integer 'width' + t.integer 'height' + t.integer 'byte_size' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'maglev_page_paths', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.bigint 'maglev_page_id' + t.string 'locale', null: false + t.string 'value', null: false + t.boolean 'canonical', default: true + t.index %w[canonical locale value], name: 'canonical_speed' + t.index %w[canonical maglev_page_id locale], name: 'scoped_canonical_speed' + t.index ['maglev_page_id'], name: 'index_maglev_page_paths_on_maglev_page_id' + end + + create_table 'maglev_pages', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.boolean 'visible', default: true + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.text 'title_translations', size: :long, collation: 'utf8mb4_bin' + t.text 'seo_title_translations', size: :long, collation: 'utf8mb4_bin' + t.text 'meta_description_translations', size: :long, collation: 'utf8mb4_bin' + t.text 'sections_translations', size: :long, collation: 'utf8mb4_bin' + t.integer 'lock_version' + t.text 'og_title_translations', size: :long, collation: 'utf8mb4_bin' + t.text 'og_description_translations', size: :long, collation: 'utf8mb4_bin' + t.text 'og_image_url_translations', size: :long, collation: 'utf8mb4_bin' + t.check_constraint 'json_valid(`meta_description_translations`)', name: 'meta_description_translations' + t.check_constraint 'json_valid(`og_description_translations`)', name: 'og_description_translations' + t.check_constraint 'json_valid(`og_image_url_translations`)', name: 'og_image_url_translations' + t.check_constraint 'json_valid(`og_title_translations`)', name: 'og_title_translations' + t.check_constraint 'json_valid(`sections_translations`)', name: 'sections_translations' + t.check_constraint 'json_valid(`seo_title_translations`)', name: 'seo_title_translations' + t.check_constraint 'json_valid(`title_translations`)', name: 'title_translations' + end + + create_table 'maglev_sites', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.text 'locales', size: :long, collation: 'utf8mb4_bin' + t.text 'sections_translations', size: :long, collation: 'utf8mb4_bin' + t.integer 'lock_version' + t.text 'style', size: :long, collation: 'utf8mb4_bin' + t.check_constraint 'json_valid(`locales`)', name: 'locales' + t.check_constraint 'json_valid(`sections_translations`)', name: 'sections_translations' + t.check_constraint 'json_valid(`style`)', name: 'style' + end + + create_table 'products', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.string 'sku' + t.float 'price' + t.boolean 'sold_out', default: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + add_foreign_key 'active_storage_attachments', 'active_storage_blobs', column: 'blob_id' + add_foreign_key 'active_storage_variant_records', 'active_storage_blobs', column: 'blob_id' +end diff --git a/spec/legacy_dummy/db/schema.mysql.rb b/spec/legacy_dummy/db/schema.mysql.rb new file mode 100644 index 00000000..c1fdd95d --- /dev/null +++ b/spec/legacy_dummy/db/schema.mysql.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 20_220_612_092_235) do + create_table 'accounts', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'email' + t.string 'password_digest' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'active_storage_attachments', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name', null: false + t.string 'record_type', null: false + t.bigint 'record_id', null: false + t.bigint 'blob_id', null: false + t.datetime 'created_at', precision: nil, null: false + t.index ['blob_id'], name: 'index_active_storage_attachments_on_blob_id' + t.index %w[record_type record_id name blob_id], name: 'index_active_storage_attachments_uniqueness', + unique: true + end + + create_table 'active_storage_blobs', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'key', null: false + t.string 'filename', null: false + t.string 'content_type' + t.text 'metadata' + t.bigint 'byte_size', null: false + t.string 'checksum', null: false + t.datetime 'created_at', precision: nil, null: false + t.string 'service_name', null: false + t.index ['key'], name: 'index_active_storage_blobs_on_key', unique: true + end + + create_table 'active_storage_variant_records', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', + force: :cascade do |t| + t.bigint 'blob_id', null: false + t.string 'variation_digest', null: false + t.index %w[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true + end + + create_table 'maglev_assets', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'filename' + t.string 'content_type' + t.integer 'width' + t.integer 'height' + t.integer 'byte_size' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'maglev_page_paths', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.bigint 'maglev_page_id' + t.string 'locale', null: false + t.string 'value', null: false + t.boolean 'canonical', default: true + t.index %w[canonical locale value], name: 'canonical_speed' + t.index %w[canonical maglev_page_id locale], name: 'scoped_canonical_speed' + t.index ['maglev_page_id'], name: 'index_maglev_page_paths_on_maglev_page_id' + end + + create_table 'maglev_pages', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.boolean 'visible', default: true + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.json 'title_translations' + t.json 'seo_title_translations' + t.json 'meta_description_translations' + t.json 'sections_translations' + t.integer 'lock_version' + t.json 'og_title_translations' + t.json 'og_description_translations' + t.json 'og_image_url_translations' + end + + create_table 'maglev_sites', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.json 'locales' + t.json 'sections_translations' + t.integer 'lock_version' + t.json 'style' + end + + create_table 'products', charset: 'utf8mb4', collation: 'utf8mb4_unicode_ci', force: :cascade do |t| + t.string 'name' + t.string 'sku' + t.float 'price' + t.boolean 'sold_out', default: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + add_foreign_key 'active_storage_attachments', 'active_storage_blobs', column: 'blob_id' + add_foreign_key 'active_storage_variant_records', 'active_storage_blobs', column: 'blob_id' +end diff --git a/spec/models/maglev/page_spec.rb b/spec/models/maglev/page_spec.rb index 96fe9bf7..6883a70e 100644 --- a/spec/models/maglev/page_spec.rb +++ b/spec/models/maglev/page_spec.rb @@ -7,6 +7,21 @@ expect(build(:page)).to be_valid end + describe 'JSON translation fields initialization' do + it 'initializes translation fields with empty hashes when nil' do + # Create a page without setting translation fields (simulating MySQL behavior) + page = described_class.new(title_translations: nil) + expect(page.title).to eq nil + end + + it 'preserves existing translation values when not nil' do + existing_translations = { en: 'Test Title' } + page = described_class.new(title_translations: existing_translations) + + expect(page.title_translations).to eq(existing_translations.stringify_keys) + end + end + describe '#index?' do subject { page.index? } diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb new file mode 100644 index 00000000..2081f72e --- /dev/null +++ b/spec/support/database_cleaner.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +begin + require 'database_cleaner/active_record' + + RSpec.configure do |config| + config.before(:suite) do + DatabaseCleaner.strategy = :transaction + end + + config.around(:each) do |example| + DatabaseCleaner.cleaning do + example.run + end + end + end +rescue LoadError + # DatabaseCleaner is not available +end