I want to find out how to handle symmetric relationships with JSON API (and an Ember.js front-end). I have the following models:
class Person < ActiveRecord::Base
has_many :friended, through: :friender_friendships, class_name: Person
has_many :friended_by, through: :friended_friendships, source: :friended, class_name: Person
has_many :friender_friendships, class_name: Friendship, foreign_key: "friender_id"
has_many :friended_friendships, class_name: Friendship, foreign_key: "friended_id"
def friendships
Friendship.where("friender_id = ? OR friended_id = ?", id, id);
end
end
class Friendship < ActiveRecord::Base
belongs_to :friender, class_name: Person
belongs_to :friended, class_name: Person
end
And the current resources:
class PersonResource < JSONAPI::Resource
attributes :name
relationship :friender, to: :many, class_name: "Person"
relationship :friended_by, to: :many, class_name: "Person"
relationship :friender_friendships, to: :many, class_name: "Friendship"
relationship :friended_friendships, to: :many, class_name: "Friendship"
relationship :friendships, to: :many, class_name: "Friendship"
end
class FriendshipResource < JSONAPI::Resource
has_one :friender
has_one :friended
attributes :strength
end
When looking at a person's profile, I would like to show all friendships of that person, whether they are on the "friender" or the "friended" end of the relationship. When I'm fetching the person resource, I pass include=friendships so that all friendships are also returned and I don't need further requests to fetch friendship data.
However, that fails with the following error:
Association named 'friendships' was not found on Person; perhaps you misspelled it?
The reason for this is that jsonapi_resources eventually calls records.includes(relationship) (see here), and since friendships is not a real relationship, ActiveRecord throws an error.
I'm not really sure how to solve this with jsonapi_resources. It might be possible to turn friendships into a "real" hasMany relationship with AR, but I haven't found a way to do that (although it's possible my AR-fu is just lacking).
If not with AR, is there a way to solve this problem with jsonapi_resources? (without making an extra roundtrip to the server). Thank you.
I have a similar issue. I have an extension defined on a has_many association:
class User < ActiveRecord::Base
has_many :client_account_assignments
has_many :clients, -> { uniq }, through: :client_account_assignments do
def visible
proxy_association.owner.visible_clients
end
end
...
def visible_clients
if has_role?(:admin) || self.all_client_access
Client.all
elsif has_role?(:client) || has_role?(:clientmanager)
Client.where(id: self.client.id)
else
self.clients
end
end
...
end
In my API output, I always want @user.clients.visible. However, I cannot find a way to coerce the has_many :clients relationship in the user resource to output @model.clients.visible.
It seems like both my issue and the issue described @balinterdi could be solved if we had the ability to reference a method on the model whose output is known to be an AR relationship.
Yes, @sirvine's suggestion would solve my problem, too, and is a great one, I think.
@balinterdi How did you solve that problem?
@fsmanuel I could not, I went around it.
I fetch the friendships separately, and then I force linkage data to be included for the linked resources:
class FriendshipResource < JSONAPI::Resource
has_one :friender, always_include_linkage_data: true
has_one :friended, always_include_linkage_data: true
attributes :strength
end
This way, there is an extra request to fetch the friendships (e.g /people/24/friendships), but then the related friended and friender resources (of type person) for each one are not refetched from the server if they had been fetched before.
It's hard to explain this and I'm not sure if this makes sense. But you wrote this with perfect timing as I'm going to publish a two blog posts about this on my blog, the first of which goes out tomorrow :)
So, to clarify, my "solution" is not really a solution for the problem, and I'd still like to find one in jsonapi-resources. Being able to include a relationship that is not 1:1 mapped to an AR relationship would still be valuable.
I'm having the same problem described. I have Users and Games that are has_many :through associated through my Roles join table that also has what the User status is for a particular Game. @balinterdi also thanks for writing that blog post it helped me fix my issues on the Ember side of things. I may end up just creating another resource like you did.
Most helpful comment
I have a similar issue. I have an extension defined on a has_many association:
In my API output, I always want
@user.clients.visible. However, I cannot find a way to coerce thehas_many :clientsrelationship in the user resource to output@model.clients.visible.It seems like both my issue and the issue described @balinterdi could be solved if we had the ability to reference a method on the model whose output is known to be an AR relationship.