Bug: has_many with `id_method_name` returns only one object (instead of an array) and with the wrong ID
This is very similar to #237, I think they might be related, so I'm going to use the same example.
Picture simple relationship like this:
class ASerializer
include FastJsonapi::ObjectSerializer
has_many :bs, id_method_name: :custom_id
end
class BSerializer
include FastJsonapi::ObjectSerializer
set_id :custom_id
end
As you can see, we have explicitly told it to use :custom_id as the foreign key for the has_many association. But the problem is when we run ASerializer.new(instance_of_a, {include: [:bs]}).serializable_hash, the generated hash is like this:
{
data: [
{ id: AID,
type: :a,
attributes: {},
relationships: {
bs: {
data: {id: "AID", :type=>:B}
}
],
included: [
{ id: B1CUSTOMID, ... },
{ id: B2CUSTOMID, ... },
]
}
As you can see, there's clearly a bug, because on relationships.bs, its returning an object (instead of an expected array, because it's a has_many) with just one element (even tough the example object has 2 associated Bs!), and the ID returned inside that object is actually A's own ID, which does NOT match any of the included IDs (because there you will find, as expected, B's ids).
If I simply remove the id_method_name from that has_many association, leaving it like this:
class ASerializer
include FastJsonapi::ObjectSerializer
has_many :bs
end
And run the exact same command, the generated output is like this:
{
data: [
{ id: AID,
type: :a,
attributes: {},
relationships: {
bs: {
data: [
{id: "B1ID", :type=>:B}
{id: "B2ID", :type=>:B}
]
}
],
included: [
{ id: B1CUSTOMID, ... },
{ id: B2CUSTOMID, ... },
]
}
As you see, then the generated Hash contains an array in relationships.bs, but it's also unusable because the IDs there won't match the IDs in the included key because there we use :custom_id.
Unfortunately I have zero experience in coding tests, so I can't help with writing one.
I just confirmed it also happens with belongs_to: as well.
If it helps debugging (just a hint), my id_method_name is :id_hash, which is coincidentially the same name as some methods used by the gem.
@shishirmk Did you manage to reproduce the bug?
@feliperaul @shishirmk I ran into the same type of issue for belongs_to. This is what i have done:
class ASerializer
include FastJsonapi::ObjectSerializer
set_id :uuid
belongs_to :b, id_method_name: :uuid
end
class BSerializer
include FastJsonapi::ObjectSerializer
set_id :uuid
end
I ran ASerializer.new(instance_of_a).serializable_hash and got following output:
{
data: {
id: uuid_for_instance_of_a,
type: :a,
attributes: {},
relationships: {
b: {
data: {
id: uuid_for_instance_of_a,
type: :b
}
}
}
}
Expected Output:
{
data: {
id: uuid_for_instance_of_a,
type: :a,
attributes: {},
relationships: {
b: {
data: {
id: uuid_of_b_to_which_a_belongs,
type: :b
}
}
}
}
@henvo I understood your point. But:
First, I think there should not be a need of using id_method_name to set id for the b for the relationships. It should use id from b's serializer. (Just Like AMS)
Second, if id_method_name has to be used then it should be called upon relationship object. It does not make sense to set id of b's object by calling a method for a's object.
@shishirmk Please consider this. As current behavior does not make sense.
@rishabhsairawat I completely agree.
Just stumbled upon this issue myself and found a solution in a referenced link. https://github.com/Netflix/fast_jsonapi/issues/338#issuecomment-451205662
For the case of ASerializer having many BSerializer, a working example should be:
class ASerializer
...
has_many :bs, id_method_name: :uuid do |object|
object.bs
end
end
But this being said I agree with @rishabhsairawat. The current behavior is a surprise and its workaround is redundant.