Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend container reader mixes up dirty tracking and creates empty locale hash #540

Closed
doits opened this issue Oct 22, 2021 · 5 comments · Fixed by #543
Closed

Backend container reader mixes up dirty tracking and creates empty locale hash #540

doits opened this issue Oct 22, 2021 · 5 comments · Fixed by #543

Comments

@doits
Copy link
Contributor

doits commented Oct 22, 2021

This is in a similar vein to #535: The container backend does some weird things to the dirty tracking after a reload or after accessing a reader.

One is about .changes where it states that the column changed like this: {"translations"=>[{}, {}]} simply after reload.

property.translations
# => {}

property.changes
# => {}

property.reload

property.changes
# => {"translations"=>[{}, {}]}
# Expected: {}

Second one is that when a reader is accessed it adds the locale key to the translations, but with empty hash:

property.translations
# => {}

property.changes
# => {}

property.name
# => nil

property.translations
# => {"en"=>{}}
# Expected: {}

property.changes
# => {"translations"=>[{}, {"en"=>{}}]}
# Expected: {}

Bug template

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"
  gem "rails", "6.1.4.1"
  gem "pg", "1.2.3"
  gem "mobility", github: 'shioyama/mobility'
end

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

Mobility.configure do
  plugins do
    backend :container

    reader

    active_record
  end
end

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

ActiveRecord::Schema.define do
  create_table :properties, force: true do |t|
    t.jsonb :translations, default: {}, null: false
  end
end

class PropertyWithMobility < ActiveRecord::Base
  self.table_name = "properties"
  extend Mobility
  translates :name
end

class BugTest < Minitest::Test
  def test_translations_and_changes_are_blank_after_create_reload
    property = PropertyWithMobility.create!
    property.reload

    assert_equal({}, property.translations, "translations should be blank")
    assert_equal({}, property.changes, "changes should be blank")
    assert_equal(false, property.changed?, "changed should be false")
  end

  def test_translations_and_changes_are_blank_after_accessor
    property = PropertyWithMobility.create!

    property.name

    assert_equal({}, property.translations, "translations should be blank")
    assert_equal({}, property.changes, "changes should be blank")
    assert_equal(false, property.changed?, "changed should be false")
  end
end
@doits
Copy link
Contributor Author

doits commented Oct 22, 2021

I think one culprit is this:

def model_translations(locale)
model[column_name][locale] ||= {}
end

Another one might be here:

def set_attribute_translation(locale, value)
translations = model[column_name] || {}
translations[locale.to_s] ||= {}
translations[locale.to_s][attribute] = value
model[column_name] = translations
end

Maybe something like this could fix it?

--- a/lib/mobility/backends/active_record/container.rb
+++ b/lib/mobility/backends/active_record/container.rb
@@ -107,14 +107,15 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
       private

       def model_translations(locale)
-        model[column_name][locale] ||= {}
+        model[column_name][locale] || {}
       end

       def set_attribute_translation(locale, value)
         translations = model[column_name] || {}
         translations[locale.to_s] ||= {}
         translations[locale.to_s][attribute] = value
-        model[column_name] = translations
+        translations[locale.to_s].compact!
+        model[column_name] = translations.compact
       end

       class Coder

@shioyama
Copy link
Owner

Thanks! You're right we should do the same thing on all AR backends that use store with a coder. I think the fix would be to entirely remove the store line here:

store options[:column_name], coder: Coder

maybe the changes you made above would help make that possible, I haven't looked at the code for quite a while.

@doits
Copy link
Contributor Author

doits commented Oct 25, 2021

I played a little bit with it and could fix the errors I reported but some existing specs were failing whenever I touched something. Looks like a deeper investigation is needed here, I'll see if I can find some time the next days.

@shioyama
Copy link
Owner

shioyama commented Nov 3, 2021

Thanks! 🙇‍♂️

doits added a commit to doits/mobility that referenced this issue Nov 5, 2021
fixes dirty tracking and creating empty translation hashes on read

fixes shioyama#540
@doits
Copy link
Contributor Author

doits commented Nov 5, 2021

I gave it a try in #543! specs should pass and issues are fixed. Lets discuss the code there.

doits added a commit to doits/mobility that referenced this issue Dec 2, 2021
fixes dirty tracking and creating empty translation hashes on read

fixes shioyama#540
doits added a commit to doits/mobility that referenced this issue Feb 27, 2022
fixes dirty tracking and creating empty translation hashes on read

fixes shioyama#540
shioyama pushed a commit that referenced this issue Feb 28, 2022
fixes dirty tracking and creating empty translation hashes on read

fixes #540
mrbrdo pushed a commit to mrbrdo/mobility that referenced this issue May 24, 2023
fixes dirty tracking and creating empty translation hashes on read

fixes shioyama#540
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants