Adam Sharp @adamsharp Sep 07 13:32
@cheerfulstoic — No delay at all! <24 hours for a free product is lightning service! Feel better too knowing the answer isn't "here's the stupid mistake you made." Thank you.
Yeah, I had hoped the inheritance on ActiveRel
would be like that on ActiveNode
where subclassed items are part of .all at each level. I have some instances in my project where I can do the direct approach, but one or two spots where I need other properties and logic in the relationship.
I also considered two other approaches:
1) Having just HasAccount but with a role property. But I had trouble figuring out the simplest way to write an owns method for the parent node that would be something like:
def owns
self.accounts.(SOME LOGIC FOR role == 'owner' IN THE REL)
end
Also was unsure how to change the role after set, and wondered if performance-wise separate rels would be better.
2) Refactoring all the logic into an intermediate ActiveNode type, i.e. AccountRole in this example , which I could subclass such that an OwnerRole < AccountRole node would be included in either scope. Then key bits of my models would be:
class AccountRole
include Neo4j::ActiveRel
from_class :User
to_class :Account
def account
self.to_node
end
end
class OwnerRole < AccountRole
end
class User
include Neo4j::ActiveNode
include Neo4j::Timestamps
has_many :out, :has_account_roles, rel_class: :AccountRole
has_many :out, :has_owner_roles, rel_class: :OwnerRole
def accounts
self.has_account_roles.map{ |role| role.account }
end
def owns
self. has_owner_role.map{ |role| role.account }
end
end
Leaning toward #2 right now, but very keen for your take.
Thanks again!
Brian Underwood @cheerfulstoic Sep 07 20:29
@adamsharp Actually, it should be pretty easy to do #1 with something like self.accounts.rel_where(role: ‘owner)
The owns method would then still return a QueryProxy representing Account nodes which you could filter further or chain associations off of. You could also have a class method with the same name on User implemented with all (like self.accounts.rel_where(role: ‘owner)) which would allow you to chain like User.all.owns or Something.users.owns, etc...
Adam Sharp @adamsharp Sep 07 21:44
Awesome. Thanks @cheerfulstoic! Will give that a try. What's the easiest way to change a rel property? (Ie from owner to manager)?
Brian Underwood @cheerfulstoic Sep 07 21:57
If you have an ActiveRel object you could just say rel.role = ‘owner’; rel.save / rel.update(role: ‘owner’). Otherwise you’d use Cypher or Ruby APIs like user.owns(:node, :rel).where(id: account.id).query.set(rel: {role: ‘owner’}).exec (obviously that’s more verbose, but that syntax can be useful if you’re updating more than one)
Adam Sharp @adamsharp 13:48
Thank you @cheerfulstoic. Yeah, it was trying to construct the latter and generally figuring out clean ways of accessing the relevant object that tied me in knots on that front. Will go this route. Thanks for the help! Been a SQL guy my whole career. This is fun.