Skip to content

Commit

Permalink
Skip serialization for all JSON/JSONB attributes in activerecord plugin.
Browse files Browse the repository at this point in the history
Use `type_for_attribute` instead of `columns_hash` to check whether an attribute type is JSON or JSONB. Serialization is now skipped not only for database attributes but also for attributes defined using Attributes API.
  • Loading branch information
vojtad committed Sep 13, 2023
1 parent b586fb2 commit 15923e2
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 16 deletions.
6 changes: 3 additions & 3 deletions lib/shrine/plugins/activerecord.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ def activerecord_reload
record.transaction { yield record.clone.reload(lock: true) }
end

# Returns true if the data attribute represents a JSON or JSONB column.
# Returns true if the data attribute type is JSON or JSONB.
# Used by the _persistence plugin to determine whether serialization
# should be skipped.
def activerecord_hash_attribute?
column = record.class.columns_hash[attribute.to_s]
column && [:json, :jsonb].include?(column.type)
attribute_type = record.class.type_for_attribute(attribute.to_s)
attribute_type && [:json, :jsonb].include?(attribute_type.type)
end

# Returns whether the record is an ActiveRecord model. Used by the
Expand Down
26 changes: 13 additions & 13 deletions test/plugin/activerecord_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
def self.model_name
ActiveModel::Name.new(self, nil, "User")
end

attribute :json_avatar_data, :json
end

@user = user_class.new
@attacher = @shrine::Attacher.from_model(@user, :avatar)
@user = user_class.new
@attacher = @shrine::Attacher.from_model(@user, :avatar)
@json_attacher = @shrine::Attacher.from_model(@user, :json_avatar)
end

after do
Expand Down Expand Up @@ -271,22 +274,19 @@ def self.model_name
describe "JSON columns" do
[:json, :jsonb].each do |type|
it "handles #{type} type" do
# work around Active Record casting assigned values into a string
@user.class.send(:attr_accessor, :avatar_data)
# redefine attribute type to make :jsonb test
@user.class.type_for_attribute("json_avatar_data").class.send(:define_method, :type) { type }

columns_hash = @user.class.columns_hash.dup # unfreeze
columns_hash["avatar_data"] = columns_hash["avatar_data"].dup # unfreeze
columns_hash["avatar_data"].singleton_class.send(:define_method, :type) { type }
@user.class.instance_variable_set(:@columns_hash, columns_hash)
assert_equal @user.class.type_for_attribute("json_avatar_data").type, type

@attacher.load_model(@user, :avatar)
@attacher.attach(fakeio)
@json_attacher.load_model(@user, :json_avatar)
@json_attacher.attach(fakeio)

assert_equal @attacher.file.data, @user.avatar_data
assert_equal @json_attacher.file.data, @user.json_avatar_data

@attacher.reload
@json_attacher.reload

assert_equal @attacher.file.data, @user.avatar_data
assert_equal @json_attacher.file.data, @user.json_avatar_data
end
end
end
Expand Down

0 comments on commit 15923e2

Please sign in to comment.