From 94f1b64cbd84aca8f684c4718c4a3ffce21f780c Mon Sep 17 00:00:00 2001 From: Did Date: Sat, 9 Aug 2025 01:00:59 +0200 Subject: [PATCH 01/29] fix: make sure the default value of translatable attributes work in MySQL --- app/models/concerns/maglev/translatable.rb | 3 ++- spec/models/maglev/page_spec.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index a3e12511..1a21bfeb 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -8,7 +8,8 @@ class UnavailableLocaleError < RuntimeError; end extend ActiveSupport::Concern def translations_for(attr) - public_send("#{attr}_translations") + # With MySQL, the Jsonb field becomes nil when the field is not set, causing the default value to be discarded + public_send("#{attr}_translations").presence || {} end def translate_attr_in(attr, locale, source_locale) 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? } From 576b82377a5c0d0fe0ad08cc76c08ba519c66383 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 16:44:43 +0200 Subject: [PATCH 02/29] feat: support for MySQL/MariaDB --- .gitignore | 3 + Gemfile | 5 +- Gemfile.lock | 4 + app/models/concerns/maglev/translatable.rb | 22 +++- app/models/maglev/application_record.rb | 10 ++ app/models/maglev/page/search_concern.rb | 10 +- app/models/maglev/site.rb | 4 + app/models/maglev/site/locales_concern.rb | 74 +++++++++--- app/services/maglev/fetch_style.rb | 2 +- app/types/maglev/locales_type.rb | 19 +++ ...831101942_create_maglev_section_content.rb | 4 + ...9092740_switch_to_localized_page_fields.rb | 10 +- .../20211008064437_add_locales_to_sites.rb | 2 + ...0211013210954_translate_section_content.rb | 8 +- ...1203224112_add_open_graph_tags_to_pages.rb | 4 + .../20220612092235_add_style_to_sites.rb | 2 + lib/maglev/engine.rb | 4 + maglevcms.gemspec | 2 +- spec/dummy/config/boot.rb | 3 + spec/dummy/config/database.yml | 9 ++ spec/dummy/db/schema.mariadb.rb | 114 ++++++++++++++++++ spec/dummy/db/schema.mysql.rb | 104 ++++++++++++++++ 22 files changed, 391 insertions(+), 28 deletions(-) create mode 100644 app/types/maglev/locales_type.rb create mode 100644 spec/dummy/db/schema.mariadb.rb create mode 100644 spec/dummy/db/schema.mysql.rb 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..62199b2c 100644 --- a/Gemfile +++ b/Gemfile @@ -30,9 +30,10 @@ 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 'pg', '~> 1.5.9' gem 'sqlite3' +gem 'mysql2' # Gems no longer be part of the default gems from Ruby 3.5.0 gem 'observer' @@ -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/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index 1a21bfeb..6237fede 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -8,7 +8,7 @@ class UnavailableLocaleError < RuntimeError; end extend ActiveSupport::Concern def translations_for(attr) - # With MySQL, the Jsonb field becomes nil when the field is not set, causing the default value to be discarded + # With MySQL, there is no default value for JSON columns, so we need to check for nil public_send("#{attr}_translations").presence || {} end @@ -18,7 +18,20 @@ def translate_attr_in(attr, locale, source_locale) 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::Nodes::InfixOperation.new('->>', + arel_table[:"#{attr}_translations"], + Arel::Nodes.build_quoted(locale)) unless mysql? + + # Mysql and MariaDB JSON support 🤬🤬🤬 + 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) @@ -37,6 +50,9 @@ def add_presence_validator(attributes) end def setup_accessors(attr) + # MariaDB doesn't support native JSON columns (longtext instead), we need to force it. + attribute("#{attr}_translations", :json) if respond_to?(:attribute) + define_method("#{attr}=") do |value| public_send("#{attr}_translations=", translations_for(attr).merge(Maglev::I18n.current_locale.to_s => value)) @@ -44,7 +60,7 @@ def setup_accessors(attr) define_method(attr) { translations_for(attr)[Maglev::I18n.current_locale.to_s] } define_method("default_#{attr}") { translations_for(attr)[Maglev::I18n.default_locale.to_s] } - end + end end end end diff --git a/app/models/maglev/application_record.rb b/app/models/maglev/application_record.rb index f6c87688..a88d22c4 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 + + private + + def mysql? + self.class.mysql? + end + + def self.mysql? + connection.adapter_name.downcase == 'mysql2' + end end end diff --git a/app/models/maglev/page/search_concern.rb b/app/models/maglev/page/search_concern.rb index 865201a4..d61e3bf1 100644 --- a/app/models/maglev/page/search_concern.rb +++ b/app/models/maglev/page/search_concern.rb @@ -32,9 +32,13 @@ 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 + + private + + def mysql? + connection.adapter_name.downcase == 'mysql2' 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..5a25d286 100644 --- a/app/models/maglev/site/locales_concern.rb +++ b/app/models/maglev/site/locales_concern.rb @@ -2,15 +2,18 @@ # rubocop:disable Style/ClassAndModuleChildren module Maglev::Site::LocalesConcern - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do + 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 + # 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, adapter_name: ActiveRecord::Base.connection.adapter_name ## validation ## validates :locales, 'maglev/collection': true, length: { minimum: 1 } @@ -42,15 +45,56 @@ def each_locale end end end + + # class LocalesType < ActiveRecord::Type::Json + # attr_reader :adapter_name - class LocalesSerializer - def self.dump(array) - (array || []).map(&:as_json) - end + # def initialize(adapter_name:) + # @adapter_name = adapter_name + # end - def self.load(array) - (array || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } - end - end + # def deserialize(value) + # pp "deserialize #{value} 🍿 #{@adapter_name}" + + # # in MariaDB, the array is a string, so we need to parse it first + # value = JSON.parse(value) if value.is_a?(String) + + # (value || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } + # end + + # def serialize(value) + # pp "serialize #{value} 🍿" + + # value = (value || []).map(&:as_json) + + # # MariaDB doesn't support default values for json columns, so we need to convert it to a JSON string + # # MySQL is ok to also use a JSON string + # mysql? ? value.to_json : value + # end + + # private + + # def mysql? + # @adapter_name.downcase == 'mysql2' + # end + # end + + # class LocalesSerializer + # def self.dump(array) + # pp "self.load #{array} 🍿" + # (array || []).map(&:as_json) + + # # in MariaDB, the array is a string, so we need to convert it to a JSON string + # # (array || []).to_json + # end + + # def self.load(array) + # pp "self.load #{array} 🥸" + # # in MariaDB, the array is a string, so we need to parse it + # array = JSON.parse(array) if array.is_a?(String) + + # (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..1fc2508e --- /dev/null +++ b/app/types/maglev/locales_type.rb @@ -0,0 +1,19 @@ +module Maglev + class LocalesType < ActiveRecord::Type::Json + attr_reader :adapter_name + + def initialize(adapter_name:) + @adapter_name = adapter_name + end + + def deserialize(value) + (super || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } + end + + private + + def mysql? + adapter_name.downcase == 'mysql2' + end + end +end \ No newline at end of file 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/lib/maglev/engine.rb b/lib/maglev/engine.rb index f4acd5ac..7fe73730 100644 --- a/lib/maglev/engine.rb +++ b/lib/maglev/engine.rb @@ -13,6 +13,10 @@ class Engine < ::Rails::Engine g.factory_bot dir: 'spec/factories' end + config.after_initialize do + ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) + end + initializer 'maglev.theme_reloader' do |app| require_relative './theme_filesystem_loader' theme_path = Rails.root.join('app/theme') 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..059d78cc --- /dev/null +++ b/spec/dummy/db/schema.mariadb.rb @@ -0,0 +1,114 @@ +# 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: 2022_06_12_092235) 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 ["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 ["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 ["canonical", "locale", "value"], name: "canonical_speed" + t.index ["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..9245516d --- /dev/null +++ b/spec/dummy/db/schema.mysql.rb @@ -0,0 +1,104 @@ +# 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: 2022_06_12_092235) 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 ["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 ["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 ["canonical", "locale", "value"], name: "canonical_speed" + t.index ["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 From fcec49e226f8c250c7668b7dbc5b5d741a827b84 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 16:53:40 +0200 Subject: [PATCH 03/29] chore: attempt to fix the CI --- app/models/maglev/page/search_concern.rb | 6 ------ app/models/maglev/site/locales_concern.rb | 2 +- app/types/maglev/locales_type.rb | 12 ------------ lib/maglev/engine.rb | 1 + 4 files changed, 2 insertions(+), 19 deletions(-) diff --git a/app/models/maglev/page/search_concern.rb b/app/models/maglev/page/search_concern.rb index d61e3bf1..ac46b6d5 100644 --- a/app/models/maglev/page/search_concern.rb +++ b/app/models/maglev/page/search_concern.rb @@ -34,12 +34,6 @@ def search_path_clause(query, locale) def search_title_node(locale) translated_arel_attribute(:title, locale) end - - private - - def mysql? - connection.adapter_name.downcase == 'mysql2' - end end end # rubocop:enable Style/ClassAndModuleChildren diff --git a/app/models/maglev/site/locales_concern.rb b/app/models/maglev/site/locales_concern.rb index 5a25d286..fdef416c 100644 --- a/app/models/maglev/site/locales_concern.rb +++ b/app/models/maglev/site/locales_concern.rb @@ -13,7 +13,7 @@ module Maglev::Site::LocalesConcern # end ## custom column type ## - attribute :locales, :maglev_locales, adapter_name: ActiveRecord::Base.connection.adapter_name + attribute :locales, :maglev_locales ## validation ## validates :locales, 'maglev/collection': true, length: { minimum: 1 } diff --git a/app/types/maglev/locales_type.rb b/app/types/maglev/locales_type.rb index 1fc2508e..2da0d41e 100644 --- a/app/types/maglev/locales_type.rb +++ b/app/types/maglev/locales_type.rb @@ -1,19 +1,7 @@ module Maglev class LocalesType < ActiveRecord::Type::Json - attr_reader :adapter_name - - def initialize(adapter_name:) - @adapter_name = adapter_name - end - def deserialize(value) (super || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } end - - private - - def mysql? - adapter_name.downcase == 'mysql2' - end end end \ No newline at end of file diff --git a/lib/maglev/engine.rb b/lib/maglev/engine.rb index 7fe73730..0101c8a3 100644 --- a/lib/maglev/engine.rb +++ b/lib/maglev/engine.rb @@ -14,6 +14,7 @@ class Engine < ::Rails::Engine end config.after_initialize do + pp "registering maglev_locales type" ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) end From bc2cc901454cdc248413b7a0e46529feaef8cc65 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 17:11:32 +0200 Subject: [PATCH 04/29] chore: Rubocop --- Gemfile | 2 +- app/models/concerns/maglev/translatable.rb | 20 ++- app/models/maglev/application_record.rb | 8 +- app/models/maglev/page/search_concern.rb | 2 +- app/models/maglev/site/locales_concern.rb | 6 +- app/types/maglev/locales_type.rb | 4 +- lib/maglev/engine.rb | 2 +- spec/dummy/db/schema.mariadb.rb | 170 +++++++++++---------- spec/dummy/db/schema.mysql.rb | 150 +++++++++--------- 9 files changed, 189 insertions(+), 175 deletions(-) diff --git a/Gemfile b/Gemfile index 62199b2c..1493e788 100644 --- a/Gemfile +++ b/Gemfile @@ -31,9 +31,9 @@ gem 'puma' # gem 'byebug', group: [:development, :test] # Use SQLite/PostgreSQL/MariaDB for development and test +gem 'mysql2' gem 'pg', '~> 1.5.9' gem 'sqlite3' -gem 'mysql2' # Gems no longer be part of the default gems from Ruby 3.5.0 gem 'observer' diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index 6237fede..d0417466 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -16,16 +16,19 @@ 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(translated_arel_attribute(attr, Maglev::I18n.current_locale) => direction) end def translated_arel_attribute(attr, locale) - return Arel::Nodes::InfixOperation.new('->>', - arel_table[:"#{attr}_translations"], - Arel::Nodes.build_quoted(locale)) unless mysql? - + unless mysql? + return Arel::Nodes::InfixOperation.new('->>', + arel_table[:"#{attr}_translations"], + Arel::Nodes.build_quoted(locale)) + end + # Mysql and MariaDB JSON support 🤬🤬🤬 json_extract = Arel::Nodes::NamedFunction.new( 'json_extract', @@ -35,6 +38,9 @@ def translated_arel_attribute(attr, locale) end def translates(*attributes, presence: false) + # MariaDB doesn't support native JSON columns (longtext instead), we need to force it. + attribute("#{attr}_translations", :json) if respond_to?(:attribute) + attributes.each { |attr| setup_accessors(attr) } add_presence_validator(attributes) if presence end @@ -50,9 +56,6 @@ def add_presence_validator(attributes) end def setup_accessors(attr) - # MariaDB doesn't support native JSON columns (longtext instead), we need to force it. - attribute("#{attr}_translations", :json) if respond_to?(:attribute) - define_method("#{attr}=") do |value| public_send("#{attr}_translations=", translations_for(attr).merge(Maglev::I18n.current_locale.to_s => value)) @@ -60,7 +63,8 @@ def setup_accessors(attr) define_method(attr) { translations_for(attr)[Maglev::I18n.current_locale.to_s] } define_method("default_#{attr}") { translations_for(attr)[Maglev::I18n.default_locale.to_s] } - end + 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 a88d22c4..5422b446 100644 --- a/app/models/maglev/application_record.rb +++ b/app/models/maglev/application_record.rb @@ -4,14 +4,14 @@ 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 - - def self.mysql? - connection.adapter_name.downcase == 'mysql2' - end end end diff --git a/app/models/maglev/page/search_concern.rb b/app/models/maglev/page/search_concern.rb index ac46b6d5..16fd0158 100644 --- a/app/models/maglev/page/search_concern.rb +++ b/app/models/maglev/page/search_concern.rb @@ -32,7 +32,7 @@ def search_path_clause(query, locale) end def search_title_node(locale) - translated_arel_attribute(:title, locale) + translated_arel_attribute(:title, locale) end end end diff --git a/app/models/maglev/site/locales_concern.rb b/app/models/maglev/site/locales_concern.rb index fdef416c..4a724d94 100644 --- a/app/models/maglev/site/locales_concern.rb +++ b/app/models/maglev/site/locales_concern.rb @@ -2,9 +2,9 @@ # rubocop:disable Style/ClassAndModuleChildren module Maglev::Site::LocalesConcern - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do + included do ## serializers ## # if Rails::VERSION::MAJOR >= 8 || (Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR.positive?) # serialize :locales, coder: LocalesSerializer @@ -45,7 +45,7 @@ def each_locale end end end - + # class LocalesType < ActiveRecord::Type::Json # attr_reader :adapter_name diff --git a/app/types/maglev/locales_type.rb b/app/types/maglev/locales_type.rb index 2da0d41e..1720f89b 100644 --- a/app/types/maglev/locales_type.rb +++ b/app/types/maglev/locales_type.rb @@ -1,7 +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 \ No newline at end of file +end diff --git a/lib/maglev/engine.rb b/lib/maglev/engine.rb index 0101c8a3..e3cc75ea 100644 --- a/lib/maglev/engine.rb +++ b/lib/maglev/engine.rb @@ -14,7 +14,7 @@ class Engine < ::Rails::Engine end config.after_initialize do - pp "registering maglev_locales type" + $stderr.puts 'registering maglev_locales type' ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) end diff --git a/spec/dummy/db/schema.mariadb.rb b/spec/dummy/db/schema.mariadb.rb index 059d78cc..52322c20 100644 --- a/spec/dummy/db/schema.mariadb.rb +++ b/spec/dummy/db/schema.mariadb.rb @@ -1,3 +1,5 @@ +# 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. @@ -10,105 +12,107 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2022_06_12_092235) 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 +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 ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + 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 + 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 ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + 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 + 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 ["canonical", "locale", "value"], name: "canonical_speed" - t.index ["canonical", "maglev_page_id", "locale"], name: "scoped_canonical_speed" - t.index ["maglev_page_id"], name: "index_maglev_page_paths_on_maglev_page_id" + 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" + 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" + 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 + 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" + 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 index 9245516d..e4025c2f 100644 --- a/spec/dummy/db/schema.mysql.rb +++ b/spec/dummy/db/schema.mysql.rb @@ -1,3 +1,5 @@ +# 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. @@ -10,95 +12,97 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2022_06_12_092235) 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 +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 ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + 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 + 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 ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + 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 + 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 ["canonical", "locale", "value"], name: "canonical_speed" - t.index ["canonical", "maglev_page_id", "locale"], name: "scoped_canonical_speed" - t.index ["maglev_page_id"], name: "index_maglev_page_paths_on_maglev_page_id" + 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" + 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" + 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 + 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" + 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 From 4fb71f3d0f5e9f691a44b2d6a5b725f29b1292b4 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 17:22:33 +0200 Subject: [PATCH 05/29] chore: another way of registering the LocalesType --- config/initializers/active_record_types.rb | 3 +++ lib/maglev/engine.rb | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 config/initializers/active_record_types.rb diff --git a/config/initializers/active_record_types.rb b/config/initializers/active_record_types.rb new file mode 100644 index 00000000..52dad330 --- /dev/null +++ b/config/initializers/active_record_types.rb @@ -0,0 +1,3 @@ +require_relative '../../app/types/maglev/locales_type' + +ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) \ No newline at end of file diff --git a/lib/maglev/engine.rb b/lib/maglev/engine.rb index e3cc75ea..f4acd5ac 100644 --- a/lib/maglev/engine.rb +++ b/lib/maglev/engine.rb @@ -13,11 +13,6 @@ class Engine < ::Rails::Engine g.factory_bot dir: 'spec/factories' end - config.after_initialize do - $stderr.puts 'registering maglev_locales type' - ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) - end - initializer 'maglev.theme_reloader' do |app| require_relative './theme_filesystem_loader' theme_path = Rails.root.join('app/theme') From a146b9aaed2161799c2de4e68f8611d85b48d118 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 17:33:44 +0200 Subject: [PATCH 06/29] fix: use Arel.sql instead (in order to support Rails 7.0) --- app/models/concerns/maglev/translatable.rb | 6 +-- app/models/maglev/site/locales_concern.rb | 58 ---------------------- config/initializers/active_record_types.rb | 4 +- 3 files changed, 4 insertions(+), 64 deletions(-) diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index d0417466..30b0fa3b 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -23,11 +23,7 @@ def order_by_translated(attr, direction) end def translated_arel_attribute(attr, locale) - unless mysql? - return Arel::Nodes::InfixOperation.new('->>', - arel_table[:"#{attr}_translations"], - Arel::Nodes.build_quoted(locale)) - end + return Arel.sql("#{attr}_translations->>'#{locale}'") unless mysql? # Mysql and MariaDB JSON support 🤬🤬🤬 json_extract = Arel::Nodes::NamedFunction.new( diff --git a/app/models/maglev/site/locales_concern.rb b/app/models/maglev/site/locales_concern.rb index 4a724d94..9b88722d 100644 --- a/app/models/maglev/site/locales_concern.rb +++ b/app/models/maglev/site/locales_concern.rb @@ -5,13 +5,6 @@ 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 @@ -45,56 +38,5 @@ def each_locale end end end - - # class LocalesType < ActiveRecord::Type::Json - # attr_reader :adapter_name - - # def initialize(adapter_name:) - # @adapter_name = adapter_name - # end - - # def deserialize(value) - # pp "deserialize #{value} 🍿 #{@adapter_name}" - - # # in MariaDB, the array is a string, so we need to parse it first - # value = JSON.parse(value) if value.is_a?(String) - - # (value || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } - # end - - # def serialize(value) - # pp "serialize #{value} 🍿" - - # value = (value || []).map(&:as_json) - - # # MariaDB doesn't support default values for json columns, so we need to convert it to a JSON string - # # MySQL is ok to also use a JSON string - # mysql? ? value.to_json : value - # end - - # private - - # def mysql? - # @adapter_name.downcase == 'mysql2' - # end - # end - - # class LocalesSerializer - # def self.dump(array) - # pp "self.load #{array} 🍿" - # (array || []).map(&:as_json) - - # # in MariaDB, the array is a string, so we need to convert it to a JSON string - # # (array || []).to_json - # end - - # def self.load(array) - # pp "self.load #{array} 🥸" - # # in MariaDB, the array is a string, so we need to parse it - # array = JSON.parse(array) if array.is_a?(String) - - # (array || []).map { |attributes| Maglev::Site::Locale.new(**attributes.symbolize_keys) } - # end - # end end # rubocop:enable Style/ClassAndModuleChildren diff --git a/config/initializers/active_record_types.rb b/config/initializers/active_record_types.rb index 52dad330..a4f466ae 100644 --- a/config/initializers/active_record_types.rb +++ b/config/initializers/active_record_types.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../../app/types/maglev/locales_type' -ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) \ No newline at end of file +ActiveRecord::Type.register(:maglev_locales, Maglev::LocalesType) From 79543096296a36bfa0ddbe84309d3e27c1aecd6f Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:13:12 +0200 Subject: [PATCH 07/29] chore: MariaDB / MySQL support only for Rails 8 --- .github/workflows/verify.yml | 85 +++++++++++++++++++++--- Gemfile.rails_7_0 | 2 + Gemfile.rails_7_0.lock | 2 + Gemfile.rails_7_2 | 2 + Gemfile.rails_7_2.lock | 2 + config/initializers/migration_patches.rb | 5 ++ spec/legacy_dummy/config/boot.rb | 3 + 7 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 config/initializers/migration_patches.rb diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 4711ba5f..9fb6e534 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -17,9 +17,22 @@ 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_USER: "maglev" + MYSQL_PASSWORD: "password" + ports: + - 3306:3306 + options: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --bind-address=0.0.0.0 --skip-name-resolve + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "maglev", "-ppassword"] + timeout: 20s + retries: 10 + strategy: matrix: - node: [20, 23] + node: [23] gemfile: ["Gemfile.rails_7_0", "Gemfile.rails_7_2", "Gemfile"] steps: @@ -67,7 +80,11 @@ jobs: MAGLEV_APP_DATABASE_PASSWORD: "password" run: bundle exec rspec - - name: Setup test database (SQLite) + - name: Run Javascript tests + run: yarn test + + # === SQLite 🪽 === + - name: Setup test database (SQLite) 🪽 env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -79,21 +96,67 @@ 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) 🪽 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.gemfile == 'Gemfile' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + RAILS_ENV: test + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_PORT: 3306 + MAGLEV_APP_DATABASE_USERNAME: "maglev" + 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 + bin/rails db:setup - - name: Run Javascript tests - run: yarn test + - name: Run Rails tests (MySQL) 🐬 + if: ${{ matrix.gemfile == 'Gemfile' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_PORT: 3306 + MAGLEV_APP_DATABASE_USERNAME: "maglev" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: bundle exec rspec + + # === MariaDB 🦭=== + - name: Setup test database (MariaDB) 🦭 + if: ${{ matrix.gemfile == 'Gemfile' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + RAILS_ENV: test + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_PORT: 3307 + MAGLEV_APP_DATABASE_USERNAME: "maglev" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: | + cp spec/dummy/db/schema.mariadb.rb spec/dummy/db/schema.rb + bin/rails db:setup + + - name: Run Rails tests (MySQL) 🦭 + if: ${{ matrix.gemfile == 'Gemfile' }} + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + USE_MYSQL: 1 + MAGLEV_APP_DATABASE_PORT: 3307 + MAGLEV_APP_DATABASE_USERNAME: "maglev" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: bundle exec rspec + + # === CLEAN UP === + # - name: Cleanup DB schema files + # 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 # NOTE: disabled because an error of eslint in the GH env # - name: Run Javascript linter diff --git a/Gemfile.rails_7_0 b/Gemfile.rails_7_0 index dbb5d106..681bf0cd 100644 --- a/Gemfile.rails_7_0 +++ b/Gemfile.rails_7_0 @@ -60,6 +60,8 @@ group :development, :test do gem 'generator_spec' gem 'nokogiri', '>= 1.13.10' + + gem 'dotenv' end group :test do diff --git a/Gemfile.rails_7_0.lock b/Gemfile.rails_7_0.lock index 10f4bf07..ab12a75c 100644 --- a/Gemfile.rails_7_0.lock +++ b/Gemfile.rails_7_0.lock @@ -87,6 +87,7 @@ GEM 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) @@ -303,6 +304,7 @@ DEPENDENCIES base64 bcrypt bigdecimal + dotenv drb factory_bot_rails (~> 6.2.0) fiddle diff --git a/Gemfile.rails_7_2 b/Gemfile.rails_7_2 index 62210536..44fb77b5 100644 --- a/Gemfile.rails_7_2 +++ b/Gemfile.rails_7_2 @@ -60,6 +60,8 @@ group :development, :test do gem 'nokogiri', '>= 1.15.6' gem 'rdoc', '>= 6.6.3.1' + + gem 'dotenv' end group :test do diff --git a/Gemfile.rails_7_2.lock b/Gemfile.rails_7_2.lock index e094a6ea..227e49df 100644 --- a/Gemfile.rails_7_2.lock +++ b/Gemfile.rails_7_2.lock @@ -95,6 +95,7 @@ GEM 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) @@ -343,6 +344,7 @@ PLATFORMS DEPENDENCIES bcrypt + dotenv factory_bot_rails (~> 6.2.0) generator_spec image_processing (~> 1.12.2) diff --git a/config/initializers/migration_patches.rb b/config/initializers/migration_patches.rb new file mode 100644 index 00000000..4b58a0e8 --- /dev/null +++ b/config/initializers/migration_patches.rb @@ -0,0 +1,5 @@ +class ActiveRecord::Migration + def mysql? + connection.adapter_name.downcase == 'mysql2' + end +end \ No newline at end of file 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__) From d6bdbc1b31da998fe4ed83d6c76e2e2811845329 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:14:25 +0200 Subject: [PATCH 08/29] fix: healthcheck doesn't exist --- .github/workflows/verify.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 9fb6e534..2d8d7b97 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -24,11 +24,7 @@ jobs: MYSQL_PASSWORD: "password" ports: - 3306:3306 - options: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --bind-address=0.0.0.0 --skip-name-resolve - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "maglev", "-ppassword"] - timeout: 20s - retries: 10 + options: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --bind-address=0.0.0.0 --skip-name-resolve strategy: matrix: From d11d9c7dab1e5829785e63c37d26d7c48297c756 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:18:24 +0200 Subject: [PATCH 09/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 51 ++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 2d8d7b97..df9f8ecf 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -24,7 +24,12 @@ jobs: MYSQL_PASSWORD: "password" ports: - 3306:3306 - options: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --bind-address=0.0.0.0 --skip-name-resolve + options: >- + --health-cmd "mysqladmin ping -u maglev -ppassword" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + --bind-address=0.0.0.0 strategy: matrix: @@ -123,28 +128,28 @@ jobs: run: bundle exec rspec # === MariaDB 🦭=== - - name: Setup test database (MariaDB) 🦭 - if: ${{ matrix.gemfile == 'Gemfile' }} - env: - BUNDLE_GEMFILE: ${{ matrix.gemfile }} - RAILS_ENV: test - USE_MYSQL: 1 - MAGLEV_APP_DATABASE_PORT: 3307 - MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "password" - run: | - cp spec/dummy/db/schema.mariadb.rb spec/dummy/db/schema.rb - bin/rails db:setup - - - name: Run Rails tests (MySQL) 🦭 - if: ${{ matrix.gemfile == 'Gemfile' }} - env: - BUNDLE_GEMFILE: ${{ matrix.gemfile }} - USE_MYSQL: 1 - MAGLEV_APP_DATABASE_PORT: 3307 - MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "password" - run: bundle exec rspec + # - name: Setup test database (MariaDB) 🦭 + # if: ${{ matrix.gemfile == 'Gemfile' }} + # env: + # BUNDLE_GEMFILE: ${{ matrix.gemfile }} + # RAILS_ENV: test + # USE_MYSQL: 1 + # MAGLEV_APP_DATABASE_PORT: 3307 + # MAGLEV_APP_DATABASE_USERNAME: "maglev" + # MAGLEV_APP_DATABASE_PASSWORD: "password" + # run: | + # cp spec/dummy/db/schema.mariadb.rb spec/dummy/db/schema.rb + # bin/rails db:setup + + # - name: Run Rails tests (MySQL) 🦭 + # if: ${{ matrix.gemfile == 'Gemfile' }} + # env: + # BUNDLE_GEMFILE: ${{ matrix.gemfile }} + # USE_MYSQL: 1 + # MAGLEV_APP_DATABASE_PORT: 3307 + # MAGLEV_APP_DATABASE_USERNAME: "maglev" + # MAGLEV_APP_DATABASE_PASSWORD: "password" + # run: bundle exec rspec # === CLEAN UP === # - name: Cleanup DB schema files From 210a1eef4e427789c4b2f0e122943c9370301923 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:19:19 +0200 Subject: [PATCH 10/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index df9f8ecf..b8c96866 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -29,7 +29,6 @@ jobs: --health-interval 10s --health-timeout 5s --health-retries 5 - --bind-address=0.0.0.0 strategy: matrix: From 81ffade6a6d07976b54e771718f977d85c22b020 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:23:05 +0200 Subject: [PATCH 11/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index b8c96866..527c471e 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -21,7 +21,8 @@ jobs: image: mysql:8.0 env: MYSQL_USER: "maglev" - MYSQL_PASSWORD: "password" + MYSQL_PASSWORD: "" + MYSQL_ALLOW_EMPTY_PASSWORD: true ports: - 3306:3306 options: >- @@ -111,7 +112,7 @@ jobs: USE_MYSQL: 1 MAGLEV_APP_DATABASE_PORT: 3306 MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "password" + MAGLEV_APP_DATABASE_PASSWORD: "" run: | cp spec/dummy/db/schema.mysql.rb spec/dummy/db/schema.rb bin/rails db:setup @@ -123,7 +124,7 @@ jobs: USE_MYSQL: 1 MAGLEV_APP_DATABASE_PORT: 3306 MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "password" + MAGLEV_APP_DATABASE_PASSWORD: "" run: bundle exec rspec # === MariaDB 🦭=== From 80833c0c005f1c202b3c95e426b66902c7ecb253 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:28:23 +0200 Subject: [PATCH 12/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 527c471e..8f331435 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -110,6 +110,7 @@ jobs: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test USE_MYSQL: 1 + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" MAGLEV_APP_DATABASE_PORT: 3306 MAGLEV_APP_DATABASE_USERNAME: "maglev" MAGLEV_APP_DATABASE_PASSWORD: "" @@ -122,6 +123,7 @@ jobs: env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" MAGLEV_APP_DATABASE_PORT: 3306 MAGLEV_APP_DATABASE_USERNAME: "maglev" MAGLEV_APP_DATABASE_PASSWORD: "" From 48407f6c5079d147a2369d486635bc2176a9b6f6 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:32:32 +0200 Subject: [PATCH 13/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 8f331435..e75f8326 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -20,13 +20,11 @@ jobs: mysql: image: mysql:8.0 env: - MYSQL_USER: "maglev" - MYSQL_PASSWORD: "" MYSQL_ALLOW_EMPTY_PASSWORD: true ports: - 3306:3306 options: >- - --health-cmd "mysqladmin ping -u maglev -ppassword" + --health-cmd "mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 5 @@ -110,10 +108,7 @@ jobs: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test USE_MYSQL: 1 - MAGLEV_APP_DATABASE_HOST: "127.0.0.1" - MAGLEV_APP_DATABASE_PORT: 3306 - MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "" + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" run: | cp spec/dummy/db/schema.mysql.rb spec/dummy/db/schema.rb bin/rails db:setup @@ -123,10 +118,7 @@ jobs: env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 - MAGLEV_APP_DATABASE_HOST: "127.0.0.1" - MAGLEV_APP_DATABASE_PORT: 3306 - MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "" + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" run: bundle exec rspec # === MariaDB 🦭=== From f9ab744f9bbb7a97a0aacbb7aeb1a723480fdee1 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:37:25 +0200 Subject: [PATCH 14/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index e75f8326..a11b48de 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -108,7 +108,8 @@ jobs: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test USE_MYSQL: 1 - MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_USERNAME: "root" run: | cp spec/dummy/db/schema.mysql.rb spec/dummy/db/schema.rb bin/rails db:setup @@ -118,7 +119,8 @@ jobs: env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 - MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_USERNAME: "root" run: bundle exec rspec # === MariaDB 🦭=== From 8a170020fb580100e77039858c403df86c078e4b Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:43:31 +0200 Subject: [PATCH 15/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 76 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index a11b48de..d68aad3f 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -20,6 +20,9 @@ jobs: mysql: image: mysql:8.0 env: + MYSQL_DATABASE: "maglev_engine_test" + MYSQL_USER: "root" + MYSQL_PASSWORD: "" MYSQL_ALLOW_EMPTY_PASSWORD: true ports: - 3306:3306 @@ -32,7 +35,8 @@ jobs: strategy: matrix: node: [23] - gemfile: ["Gemfile.rails_7_0", "Gemfile.rails_7_2", "Gemfile"] + gemfile: ["Gemfile"] + # gemfile: ["Gemfile.rails_7_0", "Gemfile.rails_7_2", "Gemfile"] steps: - name: Checkout code @@ -59,47 +63,47 @@ jobs: node-version: ${{ matrix.node }} cache: yarn - - name: Install packages - run: | - yarn install + # - name: Install packages + # run: | + # yarn install - - name: Setup test database - env: - BUNDLE_GEMFILE: ${{ matrix.gemfile }} - RAILS_ENV: test - MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "password" - run: | - bin/rails db:setup + # - name: Setup test database + # env: + # BUNDLE_GEMFILE: ${{ matrix.gemfile }} + # RAILS_ENV: test + # MAGLEV_APP_DATABASE_USERNAME: "maglev" + # MAGLEV_APP_DATABASE_PASSWORD: "password" + # run: | + # bin/rails db:setup - - name: Run Rails tests - env: - BUNDLE_GEMFILE: ${{ matrix.gemfile }} - MAGLEV_APP_DATABASE_USERNAME: "maglev" - MAGLEV_APP_DATABASE_PASSWORD: "password" - run: bundle exec rspec + # - name: Run Rails tests + # env: + # BUNDLE_GEMFILE: ${{ matrix.gemfile }} + # MAGLEV_APP_DATABASE_USERNAME: "maglev" + # MAGLEV_APP_DATABASE_PASSWORD: "password" + # run: bundle exec rspec - - name: Run Javascript tests - run: yarn test + # - name: Run Javascript tests + # run: yarn test # === SQLite 🪽 === - - name: Setup test database (SQLite) 🪽 - env: - BUNDLE_GEMFILE: ${{ matrix.gemfile }} - RAILS_ENV: test - USE_SQLITE: 1 - run: | - cp spec/dummy/db/schema.rb spec/dummy/db/schema.pg.rb - cp spec/dummy/db/schema.sqlite.rb spec/dummy/db/schema.rb - cp spec/legacy_dummy/db/schema.rb spec/legacy_dummy/db/schema.pg.rb - cp spec/legacy_dummy/db/schema.sqlite.rb spec/legacy_dummy/db/schema.rb - bin/rails db:setup + # - name: Setup test database (SQLite) 🪽 + # env: + # BUNDLE_GEMFILE: ${{ matrix.gemfile }} + # RAILS_ENV: test + # USE_SQLITE: 1 + # run: | + # cp spec/dummy/db/schema.rb spec/dummy/db/schema.pg.rb + # cp spec/dummy/db/schema.sqlite.rb spec/dummy/db/schema.rb + # cp spec/legacy_dummy/db/schema.rb spec/legacy_dummy/db/schema.pg.rb + # cp spec/legacy_dummy/db/schema.sqlite.rb spec/legacy_dummy/db/schema.rb + # bin/rails db:setup - - name: Run Rails tests (SQLite) 🪽 - env: - BUNDLE_GEMFILE: ${{ matrix.gemfile }} - USE_SQLITE: 1 - run: bundle exec rspec + # - name: Run Rails tests (SQLite) 🪽 + # env: + # BUNDLE_GEMFILE: ${{ matrix.gemfile }} + # USE_SQLITE: 1 + # run: bundle exec rspec # === MYSQL 🐬 === - name: Setup test database (MySQL) 🐬 From 510fa9def80c2f493954e05e79bba83b916e794a Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:44:55 +0200 Subject: [PATCH 16/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index d68aad3f..4f9d5e2a 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -22,7 +22,6 @@ jobs: env: MYSQL_DATABASE: "maglev_engine_test" MYSQL_USER: "root" - MYSQL_PASSWORD: "" MYSQL_ALLOW_EMPTY_PASSWORD: true ports: - 3306:3306 From 363fe8e59bf4ca323d4f91d0109de0253b2a6527 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:46:07 +0200 Subject: [PATCH 17/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 4f9d5e2a..2b6a5ede 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -21,7 +21,6 @@ jobs: image: mysql:8.0 env: MYSQL_DATABASE: "maglev_engine_test" - MYSQL_USER: "root" MYSQL_ALLOW_EMPTY_PASSWORD: true ports: - 3306:3306 From c3d3d9600e2ac083f9a0367a06746341bcb20a9c Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:51:52 +0200 Subject: [PATCH 18/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 2b6a5ede..d3beb681 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -21,7 +21,7 @@ jobs: image: mysql:8.0 env: MYSQL_DATABASE: "maglev_engine_test" - MYSQL_ALLOW_EMPTY_PASSWORD: true + MYSQL_ROOT_PASSWORD: "password" ports: - 3306:3306 options: >- @@ -112,6 +112,7 @@ jobs: 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.mysql.rb spec/dummy/db/schema.rb bin/rails db:setup @@ -123,6 +124,7 @@ jobs: 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 🦭=== From 5769b932adea2a87ceac1ac359129e58861338dc Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:55:22 +0200 Subject: [PATCH 19/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 70 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index d3beb681..30d7ce0b 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -61,47 +61,47 @@ jobs: node-version: ${{ matrix.node }} cache: yarn - # - name: Install packages - # run: | - # yarn install + - name: Install packages + run: | + yarn install - # - name: Setup test database - # env: - # BUNDLE_GEMFILE: ${{ matrix.gemfile }} - # RAILS_ENV: test - # MAGLEV_APP_DATABASE_USERNAME: "maglev" - # MAGLEV_APP_DATABASE_PASSWORD: "password" - # run: | - # bin/rails db:setup + - name: Setup test database + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + RAILS_ENV: test + MAGLEV_APP_DATABASE_USERNAME: "maglev" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: | + bin/rails db:setup - # - name: Run Rails tests - # env: - # BUNDLE_GEMFILE: ${{ matrix.gemfile }} - # MAGLEV_APP_DATABASE_USERNAME: "maglev" - # MAGLEV_APP_DATABASE_PASSWORD: "password" - # run: bundle exec rspec + - name: Run Rails tests + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + MAGLEV_APP_DATABASE_USERNAME: "maglev" + MAGLEV_APP_DATABASE_PASSWORD: "password" + run: bundle exec rspec - # - name: Run Javascript tests - # run: yarn test + - name: Run Javascript tests + run: yarn test # === SQLite 🪽 === - # - name: Setup test database (SQLite) 🪽 - # env: - # BUNDLE_GEMFILE: ${{ matrix.gemfile }} - # RAILS_ENV: test - # USE_SQLITE: 1 - # run: | - # cp spec/dummy/db/schema.rb spec/dummy/db/schema.pg.rb - # cp spec/dummy/db/schema.sqlite.rb spec/dummy/db/schema.rb - # cp spec/legacy_dummy/db/schema.rb spec/legacy_dummy/db/schema.pg.rb - # cp spec/legacy_dummy/db/schema.sqlite.rb spec/legacy_dummy/db/schema.rb - # bin/rails db:setup + - name: Setup test database (SQLite) 🪽 + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + RAILS_ENV: test + USE_SQLITE: 1 + run: | + cp spec/dummy/db/schema.rb spec/dummy/db/schema.pg.rb + cp spec/dummy/db/schema.sqlite.rb spec/dummy/db/schema.rb + cp spec/legacy_dummy/db/schema.rb spec/legacy_dummy/db/schema.pg.rb + cp spec/legacy_dummy/db/schema.sqlite.rb spec/legacy_dummy/db/schema.rb + bin/rails db:setup - # - name: Run Rails tests (SQLite) 🪽 - # env: - # BUNDLE_GEMFILE: ${{ matrix.gemfile }} - # USE_SQLITE: 1 - # run: bundle exec rspec + - name: Run Rails tests (SQLite) 🪽 + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + USE_SQLITE: 1 + run: bundle exec rspec # === MYSQL 🐬 === - name: Setup test database (MySQL) 🐬 From fcd2d35dd035f02f023e3f45b1e61a905cc8d7a2 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 18:58:36 +0200 Subject: [PATCH 20/29] chore: fixing the MySQL setup --- .github/workflows/verify.yml | 72 ++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 30d7ce0b..3af415c7 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -30,6 +30,19 @@ jobs: --health-timeout 5s --health-retries 5 + mariadb: + image: mariadb:11.8 + env: + MYSQL_DATABASE: "maglev_engine_test" + MYSQL_ROOT_PASSWORD: "password" + ports: + - 3307:3306 + options: >- + --health-cmd "mysqladmin ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + strategy: matrix: node: [23] @@ -65,7 +78,11 @@ jobs: run: | yarn install - - name: Setup test database + - name: Run Javascript tests + run: yarn test + + # === Postgresql 🐘 === + - name: Setup test database (Postgresql) 🐘 env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -74,15 +91,12 @@ jobs: run: | bin/rails db:setup - - name: Run Rails tests + - name: Run Rails tests (Postgresql) 🐘 env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} MAGLEV_APP_DATABASE_USERNAME: "maglev" MAGLEV_APP_DATABASE_PASSWORD: "password" - run: bundle exec rspec - - - name: Run Javascript tests - run: yarn test + run: bundle exec rspec # === SQLite 🪽 === - name: Setup test database (SQLite) 🪽 @@ -128,28 +142,30 @@ jobs: run: bundle exec rspec # === MariaDB 🦭=== - # - name: Setup test database (MariaDB) 🦭 - # if: ${{ matrix.gemfile == 'Gemfile' }} - # env: - # BUNDLE_GEMFILE: ${{ matrix.gemfile }} - # RAILS_ENV: test - # USE_MYSQL: 1 - # MAGLEV_APP_DATABASE_PORT: 3307 - # MAGLEV_APP_DATABASE_USERNAME: "maglev" - # MAGLEV_APP_DATABASE_PASSWORD: "password" - # run: | - # cp spec/dummy/db/schema.mariadb.rb spec/dummy/db/schema.rb - # bin/rails db:setup - - # - name: Run Rails tests (MySQL) 🦭 - # if: ${{ matrix.gemfile == 'Gemfile' }} - # env: - # BUNDLE_GEMFILE: ${{ matrix.gemfile }} - # USE_MYSQL: 1 - # MAGLEV_APP_DATABASE_PORT: 3307 - # MAGLEV_APP_DATABASE_USERNAME: "maglev" - # MAGLEV_APP_DATABASE_PASSWORD: "password" - # run: bundle exec rspec + - name: Setup test database (MariaDB) 🦭 + if: ${{ matrix.gemfile == 'Gemfile' }} + 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 + bin/rails db:setup + + - name: Run Rails tests (MySQL) 🦭 + if: ${{ matrix.gemfile == 'Gemfile' }} + 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 # === CLEAN UP === # - name: Cleanup DB schema files From 14b6a507689b2f7f590993c46059a52da60a9c5a Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 19:03:41 +0200 Subject: [PATCH 21/29] chore: fixing the MariaDB setup --- .github/workflows/verify.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 3af415c7..f397c1b2 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -33,15 +33,11 @@ jobs: mariadb: image: mariadb:11.8 env: - MYSQL_DATABASE: "maglev_engine_test" - MYSQL_ROOT_PASSWORD: "password" + MARIADB_DATABASE: "maglev_engine_test" + MARIADB_ROOT_PASSWORD: "password" ports: - 3307:3306 - options: >- - --health-cmd "mysqladmin ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 + options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3 strategy: matrix: From f95aaae317c7147b967655bb70365950e5288a4b Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 20:30:27 +0200 Subject: [PATCH 22/29] fix: fix a bad refactoring --- .github/workflows/verify.yml | 2 +- app/models/concerns/maglev/translatable.rb | 9 +++++---- config/initializers/migration_patches.rb | 12 ++++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index f397c1b2..9500d217 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -152,7 +152,7 @@ jobs: cp spec/dummy/db/schema.mariadb.rb spec/dummy/db/schema.rb bin/rails db:setup - - name: Run Rails tests (MySQL) 🦭 + - name: Run Rails tests (MariaDB) 🦭 if: ${{ matrix.gemfile == 'Gemfile' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index 30b0fa3b..eb33aa4b 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -34,10 +34,11 @@ def translated_arel_attribute(attr, locale) end def translates(*attributes, presence: false) - # MariaDB doesn't support native JSON columns (longtext instead), we need to force it. - attribute("#{attr}_translations", :json) if respond_to?(:attribute) - - 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 diff --git a/config/initializers/migration_patches.rb b/config/initializers/migration_patches.rb index 4b58a0e8..bd1c2856 100644 --- a/config/initializers/migration_patches.rb +++ b/config/initializers/migration_patches.rb @@ -1,5 +1,9 @@ -class ActiveRecord::Migration - def mysql? - connection.adapter_name.downcase == 'mysql2' +# frozen_string_literal: true + +module ActiveRecord + class Migration + def mysql? + connection.adapter_name.downcase == 'mysql2' + end end -end \ No newline at end of file +end From c4a82d7a68fd403ce544051be284d90be0b01026 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 21:29:21 +0200 Subject: [PATCH 23/29] chore: one last attempt to support MySQL/MariaDB with Rails 7.x --- Gemfile.rails_7_0 | 2 + Gemfile.rails_7_0.lock | 4 + Gemfile.rails_7_2 | 1 + Gemfile.rails_7_2.lock | 2 + spec/legacy_dummy/config/database.yml | 9 ++ spec/legacy_dummy/db/schema.mariadb.rb | 114 +++++++++++++++++++++++++ spec/legacy_dummy/db/schema.mysql.rb | 104 ++++++++++++++++++++++ 7 files changed, 236 insertions(+) create mode 100644 spec/legacy_dummy/db/schema.mariadb.rb create mode 100644 spec/legacy_dummy/db/schema.mysql.rb diff --git a/Gemfile.rails_7_0 b/Gemfile.rails_7_0 index 681bf0cd..9687f93e 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 diff --git a/Gemfile.rails_7_0.lock b/Gemfile.rails_7_0.lock index ab12a75c..f26957bf 100644 --- a/Gemfile.rails_7_0.lock +++ b/Gemfile.rails_7_0.lock @@ -80,6 +80,7 @@ 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) @@ -142,6 +143,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 @@ -303,6 +305,7 @@ PLATFORMS DEPENDENCIES base64 bcrypt + benchmark bigdecimal dotenv drb @@ -313,6 +316,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 44fb77b5..f111c0e4 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' diff --git a/Gemfile.rails_7_2.lock b/Gemfile.rails_7_2.lock index 227e49df..289aff83 100644 --- a/Gemfile.rails_7_2.lock +++ b/Gemfile.rails_7_2.lock @@ -152,6 +152,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 @@ -349,6 +350,7 @@ DEPENDENCIES generator_spec image_processing (~> 1.12.2) maglevcms! + mysql2 (~> 0.5.6) nokogiri (>= 1.15.6) observer ostruct 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/db/schema.mariadb.rb b/spec/legacy_dummy/db/schema.mariadb.rb new file mode 100644 index 00000000..2cafa0e6 --- /dev/null +++ b/spec/legacy_dummy/db/schema.mariadb.rb @@ -0,0 +1,114 @@ +# 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: 2022_06_12_092235) 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 ["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 ["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 ["canonical", "locale", "value"], name: "canonical_speed" + t.index ["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..de7ec57b --- /dev/null +++ b/spec/legacy_dummy/db/schema.mysql.rb @@ -0,0 +1,104 @@ +# 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: 2022_06_12_092235) 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 ["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 ["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 ["canonical", "locale", "value"], name: "canonical_speed" + t.index ["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 From 39788ad3d4320e8d800a0a8c8d9c211f0fb115fc Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 21:31:41 +0200 Subject: [PATCH 24/29] chore(ci): update the test matrix (databases / rails versions) --- .github/workflows/verify.yml | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 9500d217..030eb834 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -42,8 +42,8 @@ jobs: strategy: matrix: node: [23] - gemfile: ["Gemfile"] - # gemfile: ["Gemfile.rails_7_0", "Gemfile.rails_7_2", "Gemfile"] + database: [postgres, sqlite, mysql, mariadb] + gemfile: ["Gemfile", "Gemfile.rails_7_0", "Gemfile.rails_7_2"] steps: - name: Checkout code @@ -79,6 +79,7 @@ jobs: # === Postgresql 🐘 === - name: Setup test database (Postgresql) 🐘 + if: ${{ matrix.database == 'postgres' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -88,6 +89,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (Postgresql) 🐘 + if: ${{ matrix.database == 'postgres' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} MAGLEV_APP_DATABASE_USERNAME: "maglev" @@ -96,6 +98,7 @@ jobs: # === SQLite 🪽 === - name: Setup test database (SQLite) 🪽 + if: ${{ matrix.database == 'sqlite' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -108,6 +111,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (SQLite) 🪽 + if: ${{ matrix.database == 'sqlite' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_SQLITE: 1 @@ -115,7 +119,7 @@ jobs: # === MYSQL 🐬 === - name: Setup test database (MySQL) 🐬 - if: ${{ matrix.gemfile == 'Gemfile' }} + if: ${{ matrix.database == 'mysql' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -128,7 +132,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (MySQL) 🐬 - if: ${{ matrix.gemfile == 'Gemfile' }} + if: ${{ matrix.database == 'mysql' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 @@ -139,7 +143,7 @@ jobs: # === MariaDB 🦭=== - name: Setup test database (MariaDB) 🦭 - if: ${{ matrix.gemfile == 'Gemfile' }} + if: ${{ matrix.database == 'mariadb' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -153,7 +157,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (MariaDB) 🦭 - if: ${{ matrix.gemfile == 'Gemfile' }} + if: ${{ matrix.database == 'mariadb' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 @@ -163,14 +167,6 @@ jobs: MAGLEV_APP_DATABASE_PASSWORD: "password" run: bundle exec rspec - # === CLEAN UP === - # - name: Cleanup DB schema files - # 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 - # NOTE: disabled because an error of eslint in the GH env # - name: Run Javascript linter # run: yarn lint From 4d349ceff0bcaf2d8eee4b87ab467a3fc21b7f6d Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 21:39:27 +0200 Subject: [PATCH 25/29] chore(ci): wrong schema.rb file for the legacy app --- .github/workflows/verify.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 030eb834..98ec0a2e 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -129,6 +129,7 @@ jobs: MAGLEV_APP_DATABASE_PASSWORD: "password" run: | 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 Rails tests (MySQL) 🐬 @@ -154,6 +155,7 @@ jobs: 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) 🦭 From 2df377486751aae06e3b60abd6b6498442dfe60d Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 21:53:31 +0200 Subject: [PATCH 26/29] fix(ci): automatic MySQL reconnection --- spec/legacy_dummy/config/environments/test.rb | 7 ++++ spec/support/database_connection_helper.rb | 33 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 spec/support/database_connection_helper.rb diff --git a/spec/legacy_dummy/config/environments/test.rb b/spec/legacy_dummy/config/environments/test.rb index 151eab39..98f96ccb 100644 --- a/spec/legacy_dummy/config/environments/test.rb +++ b/spec/legacy_dummy/config/environments/test.rb @@ -54,4 +54,11 @@ # Raises error for missing translations. # config.action_view.raise_on_missing_translations = true + + # Database connection settings for tests + if ENV['USE_MYSQL'] + config.active_record.database_pool_size = 5 + config.active_record.database_pool_timeout = 5 + config.active_record.database_pool_reaping_frequency = 10 + end end diff --git a/spec/support/database_connection_helper.rb b/spec/support/database_connection_helper.rb new file mode 100644 index 00000000..c90bea0d --- /dev/null +++ b/spec/support/database_connection_helper.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module DatabaseConnectionHelper + extend ActiveSupport::Concern + + included do + before(:each) do + ensure_database_connection + end + end + + private + + def ensure_database_connection + return unless mysql_database? + + # Check if connection is still alive + unless ActiveRecord::Base.connection.active? + ActiveRecord::Base.connection.reconnect! + end + rescue ActiveRecord::StatementInvalid, ActiveRecord::ConnectionNotEstablished + # If reconnection fails, try to establish a new connection + ActiveRecord::Base.establish_connection + end + + def mysql_database? + ActiveRecord::Base.connection.adapter_name.downcase == 'mysql2' + end +end + +RSpec.configure do |config| + config.include DatabaseConnectionHelper +end From 36481875bc5665a5ef93cd44912698a69b9907a0 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 22:47:18 +0200 Subject: [PATCH 27/29] chore(ci): MySQL/MariaDB doesnt work well with Rails 7.0 --- .github/workflows/verify.yml | 8 ++--- Gemfile.rails_7_0 | 2 ++ Gemfile.rails_7_0.lock | 5 +++ Gemfile.rails_7_2 | 2 ++ Gemfile.rails_7_2.lock | 5 +++ app/models/concerns/maglev/translatable.rb | 3 +- spec/legacy_dummy/config/environments/test.rb | 10 ------ spec/support/database_cleaner.rb | 19 +++++++++++ spec/support/database_connection_helper.rb | 33 ------------------- 9 files changed, 39 insertions(+), 48 deletions(-) create mode 100644 spec/support/database_cleaner.rb delete mode 100644 spec/support/database_connection_helper.rb diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 98ec0a2e..f6a2599b 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -119,7 +119,7 @@ jobs: # === MYSQL 🐬 === - name: Setup test database (MySQL) 🐬 - if: ${{ matrix.database == 'mysql' }} + if: ${{ matrix.database == 'mysql' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -133,7 +133,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (MySQL) 🐬 - if: ${{ matrix.database == 'mysql' }} + if: ${{ matrix.database == 'mysql' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 @@ -144,7 +144,7 @@ jobs: # === MariaDB 🦭=== - name: Setup test database (MariaDB) 🦭 - if: ${{ matrix.database == 'mariadb' }} + if: ${{ matrix.database == 'mariadb' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -159,7 +159,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (MariaDB) 🦭 - if: ${{ matrix.database == 'mariadb' }} + if: ${{ matrix.database == 'mariadb' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 diff --git a/Gemfile.rails_7_0 b/Gemfile.rails_7_0 index 9687f93e..181c31c1 100644 --- a/Gemfile.rails_7_0 +++ b/Gemfile.rails_7_0 @@ -64,6 +64,8 @@ group :development, :test do 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 f26957bf..6d838d75 100644 --- a/Gemfile.rails_7_0.lock +++ b/Gemfile.rails_7_0.lock @@ -85,6 +85,10 @@ GEM 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) @@ -307,6 +311,7 @@ DEPENDENCIES bcrypt benchmark bigdecimal + database_cleaner-active_record dotenv drb factory_bot_rails (~> 6.2.0) diff --git a/Gemfile.rails_7_2 b/Gemfile.rails_7_2 index f111c0e4..01087ad6 100644 --- a/Gemfile.rails_7_2 +++ b/Gemfile.rails_7_2 @@ -63,6 +63,8 @@ group :development, :test do 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 289aff83..9ffc4d76 100644 --- a/Gemfile.rails_7_2.lock +++ b/Gemfile.rails_7_2.lock @@ -92,6 +92,10 @@ 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) @@ -345,6 +349,7 @@ PLATFORMS DEPENDENCIES bcrypt + database_cleaner-active_record dotenv factory_bot_rails (~> 6.2.0) generator_spec diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index eb33aa4b..dd3e1223 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -25,7 +25,8 @@ def order_by_translated(attr, direction) def translated_arel_attribute(attr, locale) return Arel.sql("#{attr}_translations->>'#{locale}'") unless mysql? - # Mysql and MariaDB JSON support 🤬🤬🤬 + # 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}")] diff --git a/spec/legacy_dummy/config/environments/test.rb b/spec/legacy_dummy/config/environments/test.rb index 98f96ccb..e361f3da 100644 --- a/spec/legacy_dummy/config/environments/test.rb +++ b/spec/legacy_dummy/config/environments/test.rb @@ -51,14 +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 - - # Database connection settings for tests - if ENV['USE_MYSQL'] - config.active_record.database_pool_size = 5 - config.active_record.database_pool_timeout = 5 - config.active_record.database_pool_reaping_frequency = 10 - end end diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb new file mode 100644 index 00000000..dd29cb9c --- /dev/null +++ b/spec/support/database_cleaner.rb @@ -0,0 +1,19 @@ +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 \ No newline at end of file diff --git a/spec/support/database_connection_helper.rb b/spec/support/database_connection_helper.rb deleted file mode 100644 index c90bea0d..00000000 --- a/spec/support/database_connection_helper.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -module DatabaseConnectionHelper - extend ActiveSupport::Concern - - included do - before(:each) do - ensure_database_connection - end - end - - private - - def ensure_database_connection - return unless mysql_database? - - # Check if connection is still alive - unless ActiveRecord::Base.connection.active? - ActiveRecord::Base.connection.reconnect! - end - rescue ActiveRecord::StatementInvalid, ActiveRecord::ConnectionNotEstablished - # If reconnection fails, try to establish a new connection - ActiveRecord::Base.establish_connection - end - - def mysql_database? - ActiveRecord::Base.connection.adapter_name.downcase == 'mysql2' - end -end - -RSpec.configure do |config| - config.include DatabaseConnectionHelper -end From e4199f439822177ea1fd1da150e6d6061886cc4a Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 22:59:24 +0200 Subject: [PATCH 28/29] chore(ci): MySQL/MariaDB doesnt work well with Rails 7.0 (attempt #2) --- .github/workflows/verify.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index f6a2599b..27c15839 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -41,9 +41,13 @@ jobs: strategy: matrix: - node: [23] - database: [postgres, sqlite, mysql, mariadb] 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 @@ -64,10 +68,10 @@ 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 @@ -119,7 +123,7 @@ jobs: # === MYSQL 🐬 === - name: Setup test database (MySQL) 🐬 - if: ${{ matrix.database == 'mysql' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} + if: ${{ matrix.database == 'mysql' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -133,7 +137,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (MySQL) 🐬 - if: ${{ matrix.database == 'mysql' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} + if: ${{ matrix.database == 'mysql' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 @@ -144,7 +148,7 @@ jobs: # === MariaDB 🦭=== - name: Setup test database (MariaDB) 🦭 - if: ${{ matrix.database == 'mariadb' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} + if: ${{ matrix.database == 'mariadb' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test @@ -159,7 +163,7 @@ jobs: bin/rails db:setup - name: Run Rails tests (MariaDB) 🦭 - if: ${{ matrix.database == 'mariadb' }} && ${{matrix.gemfile != 'Gemfile.rails_7_0' }} + if: ${{ matrix.database == 'mariadb' }} env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} USE_MYSQL: 1 From b59a537828b270b7b3dd0d24686ea29e223f2474 Mon Sep 17 00:00:00 2001 From: Did Date: Mon, 18 Aug 2025 23:03:01 +0200 Subject: [PATCH 29/29] chore: Rubocop --- .github/workflows/verify.yml | 2 +- app/models/concerns/maglev/translatable.rb | 2 +- spec/legacy_dummy/db/schema.mariadb.rb | 170 +++++++++++---------- spec/legacy_dummy/db/schema.mysql.rb | 150 +++++++++--------- spec/support/database_cleaner.rb | 6 +- 5 files changed, 169 insertions(+), 161 deletions(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 27c15839..6db8e5f0 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -128,7 +128,7 @@ jobs: BUNDLE_GEMFILE: ${{ matrix.gemfile }} RAILS_ENV: test USE_MYSQL: 1 - MAGLEV_APP_DATABASE_HOST: "127.0.0.1" + MAGLEV_APP_DATABASE_HOST: "127.0.0.1" MAGLEV_APP_DATABASE_USERNAME: "root" MAGLEV_APP_DATABASE_PASSWORD: "password" run: | diff --git a/app/models/concerns/maglev/translatable.rb b/app/models/concerns/maglev/translatable.rb index dd3e1223..dd0557c3 100644 --- a/app/models/concerns/maglev/translatable.rb +++ b/app/models/concerns/maglev/translatable.rb @@ -25,7 +25,7 @@ def order_by_translated(attr, direction) def translated_arel_attribute(attr, locale) return Arel.sql("#{attr}_translations->>'#{locale}'") unless mysql? - # MySQL and MariaDB JSON support 🤬🤬🤬 + # MySQL and MariaDB JSON support 🤬🤬🤬 # Note: doesn't work with Rails 7.0.x json_extract = Arel::Nodes::NamedFunction.new( 'json_extract', diff --git a/spec/legacy_dummy/db/schema.mariadb.rb b/spec/legacy_dummy/db/schema.mariadb.rb index 2cafa0e6..be31467a 100644 --- a/spec/legacy_dummy/db/schema.mariadb.rb +++ b/spec/legacy_dummy/db/schema.mariadb.rb @@ -1,3 +1,5 @@ +# 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. @@ -10,105 +12,107 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_06_12_092235) 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 +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 ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + 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 + 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 ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + 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 + 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 ["canonical", "locale", "value"], name: "canonical_speed" - t.index ["canonical", "maglev_page_id", "locale"], name: "scoped_canonical_speed" - t.index ["maglev_page_id"], name: "index_maglev_page_paths_on_maglev_page_id" + 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" + 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" + 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 + 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" + 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 index de7ec57b..c1fdd95d 100644 --- a/spec/legacy_dummy/db/schema.mysql.rb +++ b/spec/legacy_dummy/db/schema.mysql.rb @@ -1,3 +1,5 @@ +# 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. @@ -10,95 +12,97 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_06_12_092235) 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 +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 ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + 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 + 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 ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + 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 + 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 ["canonical", "locale", "value"], name: "canonical_speed" - t.index ["canonical", "maglev_page_id", "locale"], name: "scoped_canonical_speed" - t.index ["maglev_page_id"], name: "index_maglev_page_paths_on_maglev_page_id" + 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" + 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" + 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 + 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" + 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/support/database_cleaner.rb b/spec/support/database_cleaner.rb index dd29cb9c..2081f72e 100644 --- a/spec/support/database_cleaner.rb +++ b/spec/support/database_cleaner.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + begin require 'database_cleaner/active_record' RSpec.configure do |config| - config.before(:suite) do DatabaseCleaner.strategy = :transaction end @@ -12,8 +13,7 @@ example.run end end - end rescue LoadError # DatabaseCleaner is not available -end \ No newline at end of file +end