Rails mysql structure.sql dump contains AUTO_INCREMENT

When rails generates a structure.sql dump for MySQL it contains the AUTO_INCREMENT value. Which is anoying because this is not something you want to happen.

CREATE TABLE `active_storage_variant_records` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `blob_id` bigint NOT NULL,
  `variation_digest` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_active_storage_variant_records_uniqueness` (`blob_id`,`variation_digest`),
  CONSTRAINT `fk_rails_993965df05` FOREIGN KEY (`blob_id`) REFERENCES `active_storage_blobs` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=471 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Look at the part: AUTO_INCREMENT=471

After digging through the activerecord code, I saw I could sneak in a mysqldump option for the dump call. Yeah! 👍🏻

But there isn't such option 😕. It's an ancient BUG/Feature of mysql, which of course still isn't resolved in MySQL 8. https://bugs.mysql.com/bug.php?id=20786

Why would you like to dump the table structure (without data) with the AUTO_INCREMENT value!?

As a workaround it's possible to enhance the db:schema:dump task in a custom rake file (lib/tasks/remove_autoincrement_from_dump.rake).
So the AUTO_INCREMENT part is removed from it.

Rake::Task['db:schema:dump'].enhance do
  structure_sql_path = Rails.root.join("db/structure.sql")
  if File.exist?(structure_sql_path)
    sql = File.read(structure_sql_path)
    File.write(structure_sql_path, sql.gsub(/AUTO_INCREMENT=[0-9]+/, ""))
  end
end

References:

Rails generate both structure.sql and schema.rb

Default behaviour for rails is to generate a db/schema.rb when running migrations or dumping the database.

Schema.rb is great because it can be used for populating other database types and is used to populate the test database.
And I personally think it's great becaus of the vscode plugin Rails Schema which shows the database structure of your application in a sidebar (TIP, move this bar to the right panel).

The rake task db:migrate default behaviour is to invoke a db:schema:dump when migrating is done. By default this generates the schema.rb file.
This output of the generated file is used to popuplate the test-database..

But somethimes the db/schema.rb isn't good enough for popuplating the test database or using the file to generate the basic structure. Contraints are quirky.
(For example see previous article mysql json constraints).
To generate a native sql dump of the database structure, you can change the default structure to sql. Place the following line in your config/application.rb.

    config.active_record.schema_format = :sql

When enabling this dumps are generated to db/structure.sql.
But you loose the schema.rb dumps.

Here's a tip to work with structure.sql and just generate the schema.rb (for your lovely sidebar).

Create a file in lib/tasks/schema_dump.rb and enhance the dump task, so it also creates the schema.rb file.

Rake::Task['db:schema:dump'].enhance do
  File.open(Rails.root.join('db/schema.rb'), 'w') do |stream|
    ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
  end
end

NOTE: structure.sql contains yet another MySQL bug. (See next article for workaround)
Tip: use postgresql !

Rails incorrect constraints in schema.rb mysql dumps (for json)

The default dumping strategy for rails is to generate a ruby schema.rb file.
Having a table created by the following migration. (simplified version)

class CreateOrganisation < ActiveRecord::Migration[7.0]
  def change
    create_table :organisations do |t|
      t.string :name
      t.json :settings
    end
  end
end

It generates the following dump

ActiveRecord::Schema[7.0].define(version: 2022_12_29_082458) do
  create_table "organisations", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "name"
    t.text "settings", size: :long, collation: "utf8mb4_bin"
    t.check_constraint "son_valid(`settings`", name: "organisations_chk_1"
  end

Trying to use this dump results in an error. Which isn't strange when you look at the generated constraint code. The MySQL adapter doesn't extract the constraints correctly

    t.check_constraint "son_valid(`settings`", name: "organisations_chk_1"

TIP: Don't use the 'json' datatype when MySQL. Event better use Postgres when possible, with it's jsonb column.

(See the next post for a good workaround to use structure.sql and schema.rb)

Incompatibility rails 5.2 and mail gem: ArgumentError (:arguments expected to be an Array of individual string args)

After an innocent gem security update, suddenly my application didn't mail anymore. :S
The following crash happend when the rails application tried to send an e-mail.

Error performing ActionMailer::DeliveryJob (Job ID: xxx) from Async(mailers) in 17.17ms: ArgumentError (:arguments expected to be an Array of individual string args):
gems/mail-2.8.0/lib/mail/network/delivery_methods/sendmail.rb:53:in `initialize'
gems/mail-2.8.0/lib/mail/message.rb:278:in `new'
gems/mail-2.8.0/lib/mail/message.rb:278:in `delivery_method'
gems/actionmailer-5.2.8.1/lib/action_mailer/delivery_methods.rb:65:in `wrap_delivery_behavior'
gems/actionmailer-5.2.8.1/lib/action_mailer/delivery_methods.rb:79:in `wrap_delivery_behavior!'
gems/actionmailer-5.2.8.1/lib/action_mailer/base.rb:823:in `mail'

After digging deeper in the exception trace and git diff, I figured out the mail gem was upgraded from 2.7.1 to 2.8.0.

The sendmail default sendmail arguments configuration value given by actionmailer is "-i". Which was fine for the older mail gem.

The new gem requires this to be an list of strings.
You can downgrade this OR use the following workaround in your environment file (config/environments/production.rb)

 config.action_mailer.sendmail_settings = {
   location:  "/usr/sbin/sendmail", arguments: ["-i"] 
}

Btw: It's a known issue and probably resolved in the next 2.8.1 release (https://github.com/mikel/mail/issues/1541)