Skip to content

Commit 61432ef

Browse files
authored
fix: avoid creating invalid objects when foreign key is null in serializer (#740)
1 parent a273052 commit 61432ef

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

app/serializers/forest_liana/serializer_factory.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,10 @@ def has_one_relationships
146146
@options[:fields][relation_class_name]&.size == 1 &&
147147
@options[:fields][relation_class_name]&.include?(relation.klass.primary_key.to_sym)
148148

149-
attr_data[:attr_or_block] = proc { relation.klass.new(relation.klass.primary_key => object.send(relation.foreign_key.to_sym)) }
149+
attr_data[:attr_or_block] = proc {
150+
foreign_key_value = object.send(relation.foreign_key.to_sym)
151+
foreign_key_value.nil? ? nil : relation.klass.new(relation.klass.primary_key => foreign_key_value)
152+
}
150153
end
151154
end
152155

spec/dummy/app/models/tree.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Tree < ActiveRecord::Base
22
belongs_to :owner, class_name: 'User', inverse_of: :trees_owned
33
belongs_to :cutter, class_name: 'User', inverse_of: :trees_cut
4-
belongs_to :island
4+
belongs_to :island, optional: true
55
belongs_to :eponymous_island,
66
->(record) { where(name: record.name) },
77
class_name: 'Island',
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module ForestLiana
2+
describe SerializerFactory do
3+
describe '#serializer_for has_one_relationships patch' do
4+
let(:user) { User.create!(name: 'PatchTest') }
5+
let(:island) { Island.create!(name: 'TestIsland') }
6+
let(:tree) { Tree.create!(name: 'TestTree', island: island, owner: user) }
7+
8+
it 'simulates has_one relation with only primary key' do
9+
factory = described_class.new
10+
serializer_class = factory.serializer_for(Tree)
11+
12+
serializer_class.send(:has_one, :island) { }
13+
14+
instance = serializer_class.new(tree, fields: {
15+
'Island' => [:id],
16+
'Tree' => [:island]
17+
})
18+
19+
relationships = instance.send(:has_one_relationships)
20+
expect(relationships).to have_key(:island)
21+
relation_data = relationships[:island]
22+
expect(relation_data[:attr_or_block]).to be_a(Proc)
23+
model = relation_data[:attr_or_block].call
24+
25+
expect(model).to be_a(Island)
26+
expect(model.id).to eq(island.id)
27+
end
28+
29+
it 'returns nil if foreign key is nil' do
30+
tree_without_island = Tree.create!(name: 'NoIslandTree', island_id: nil, owner: user)
31+
32+
factory = described_class.new
33+
serializer_class = factory.serializer_for(Tree)
34+
35+
serializer_class.send(:has_one, :island) { }
36+
37+
instance = serializer_class.new(tree_without_island, fields: {
38+
'Island' => [:id],
39+
'Tree' => [:island]
40+
})
41+
42+
relationships = instance.send(:has_one_relationships)
43+
expect(relationships).to have_key(:island)
44+
relation_data = relationships[:island]
45+
expect(relation_data[:attr_or_block]).to be_a(Proc)
46+
model = relation_data[:attr_or_block].call
47+
48+
expect(model).to be_nil
49+
end
50+
51+
end
52+
end
53+
end

0 commit comments

Comments
 (0)