ruby-i18n/i18n

Incompatibility with Rails 6.1+ and validations containing procs/lambdas

sundling opened this issue · 0 comments

I am not sure if this is the correct place for this issue but I found an older issue that looks similar to my problem.

Rails have passed the ActiveRecord instance to I18n.translate for some time (added for v5.0+, added for v6.1+) to be able to support procs/lambdas and it worked fine when the errors were just plain objects.

Rails v6.1 added ActiveModel::Error and that made things a little bit more complex.

An instance of I18n::MissingTranslation is created each time that a translation key is missing. It is initialized with locale, key and the options originally passed to I18n.translate, including the ActiveRecord instance.
So far everything is working as expected.

The problem arises when adding caching to the application using I18n.cache_store=. We now need to be able to serialize what we have "translated" and that is not always possible.

Is there a special reason for storing the options in the I18n::MissingTranslation object? (Haven't lookups & interpolations been performed by that time?)
If they could be excluded it would save some bytes in the cache, especially if there are ActiveRecord objects there.

What I expected to happen

The I18n::MissingTranslation object should be serialized successfully.

What actually happened

Exception TypeError: no _dump_data is defined for class Proc is thrown during serialization (by Marshal.dump)

Versions of i18n, rails, and anything else you think is necessary

i18n: 1.8.10
rails: 6.1.4.1


# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "activerecord", "6.1.4.1"
  gem "i18n", "1.8.10"
  gem "sqlite3"
end

require "active_record"
require "minitest/autorun"
require "logger"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

I18n::Backend::Simple.send(:include, I18n::Backend::Cache)
I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)

ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
    t.string :title
  end
end

class Post < ActiveRecord::Base
  validates :title, length: { minimum: 10 }, if: -> { true }

  def my_method
    true
  end
end

class BugTest < Minitest::Test
  def test_run
    post = Post.new(title: "My post")
    post.save

    assert_equal "Title is too short (minimum is 10 characters)", post.errors.first.full_message
  end
end