1
  1. How to return an index of only Items where the User has permission?
  2. How to return an index of only Items where the Group a User is in has permission?
  3. How to return a single item only if a User has permission?
  4. How to return a single item only if the Group a User is in has permission?

Note: I know it's possible to query for Item.all, then iterate through the array and pull out only items where .has_permissions == User, but this completely ignores the benefits of having everything in a graph, so is not an answer.


To keep this simple, let's say there are 3 objects:

  • An Item
  • A User
  • A Group

Typical graph situations:

(User)<-[:HAS_PERMISSIONS]-(Item)
(Group)<-[:HAS_PERMISSIONS]-(Item)
(Group)-[:HAS_MEMBERS]->(User)

With the models:

class Item 
  include Neo4j::ActiveNode
  property :name, type: String
  property :description, type: String

  has_many :out, :user_permission_to, type: :PERMISSION_TO, model_class: :User
  has_many :out, :group_permission_to, type: :PERMISSION_TO, model_class: :Group
end

class Identity 
  include Neo4j::ActiveNode
  property :username, type: String

  has_many :in, :permission_to, type: :PERMISSION_TO, model_class: :Item
  has_many :in, :groups, type: :GROUP_MEMBER, model_class: :Group
end

class Group 
  include Neo4j::ActiveNode
  property :group_name, type: String

  has_many :in, :permission_to, type: :PERMISSION_TO, model_class: :Item
  has_many :out, :members, type: :GROUP_MEMBER, model_class: :User
end

And with the simple controller:

# GET /items
def index
  @items = Item.all
  render json: @items
end

# GET /item/1
def show
  render json: @item
end
joshfindit
  • 611
  • 6
  • 27

1 Answers1

2

For starters, I'd suggest checking out this article (the second half covers access control which is very similar)

"How to return an index of only Items where the User has permission?"

You could do this a couple of ways. More explicitly:

identity.as(:id).query.match("(id)<-[PERMISSION_TO*1..2]-(item:Item)").pluck(:item)

Alternatively, I think that this would work:

identity.permission_to(rel_length: 1..2)

"How to return an index of only Items where the Group a User is in has permission?"

Simple:

identity.groups.permission_to

"How to return a single item only if a User has permission?"

For the two solutions above:

identity.as(:id).query.match("(id)<-[PERMISSION_TO*1..2]-(item:Item)").limit(1).pluck(:item)

# or

identity.permission_to(rel_length: 1..2).first

"How to return a single item only if the Group a User is in has permission?"

identity.groups.permission_to

Separately, some feedback:

Using the term "index" the way you're using it is a bit confusing because Neo4j has indexes which allow for performant querying of properties on labels.

I would probably make my models like this:

class Item 
  include Neo4j::ActiveNode
  property :name, type: String
  property :description, type: String

  has_many :in, :users_with_permission, type: :CAN_ACCESS, model_class: :Identity
  has_many :in, :groups_with_permission, type: :CAN_ACCESS, model_class: :Group
end

class Identity 
  include Neo4j::ActiveNode
  property :username, type: String

  has_many :out, :accessible_items, type: :CAN_ACCESS, model_class: :Item
  has_many :out, :groups, type: :IN_GROUP # Don't need `model_class: :Group` here
end

class Group 
  include Neo4j::ActiveNode
  property :group_name, type: String

  has_many :out, :accessible_items, type: :CAN_ACCESS, model_class: :Item
  has_many :in, :members, type: :IN_GROUP, model_class: :Identity
  # You could also do:
  # has_many :in, :members, model_class: :Identity, origin: :groups
end
Brian Underwood
  • 10,746
  • 1
  • 22
  • 34