Closed TrevorPage closed 7 years ago
Hey @TrevorPage, there would only be one distinct team instance (one record in the database) that has three difference members. What bit of code (or documentation) is leading you to believe otherwise?
Hi @richardpringle! The part of code that made me believe that three team records were being made is the following in boot/sample-model.js:
// add team members
Team.create([
{ownerId: project.ownerId, memberId: users[0].id},
{ownerId: project.ownerId, memberId: users[1].id}
], function(err, team) {
if (err) throw err;
console.log('Created team:', team);
});
and:
//add team members
Team.create({
ownerId: project.ownerId,
memberId: users[1].id
}, function(err, team) {
if (err) throw err;
console.log('Created team:', team);
});
It is my understanding that the above is programmatically creating three Team objects. The documentation confirms to me that passing an array creates an array of instances (http://apidocs.strongloop.com/loopback/#persistedmodel-create).
Furthermore, if I look in common/models/team.json, it seems to me that a team model instance can only reference one member:
"memberId": {
"type": "string",
"required": true
}
But, further down I notice that the relation is of course hasMany
:
"relations": { "members": { "type": "hasMany", "model": "user", "foreignKey": "memberId" } },
So, I see that it has a hasMany
relation, but I'm struggling to grasp how the team object being created in the example is just one object, when it looks to me like several team instances are being made, where each one only references one memberId.
Furthermore, if I persist the memory database to .json, I see that the one team with two members and one team with one member are represented as three separate objects:
{
"ids": {
"User": 1,
"AccessToken": 1,
"ACL": 1,
"RoleMapping": 2,
"Role": 2,
"user": 4,
"team": 4,
"project": 3
},
"models": {
"User": {},
"AccessToken": {},
"ACL": {},
"RoleMapping": {
"1": "{\"principalType\":\"USER\",\"principalId\":\"3\",\"roleId\":1,\"id\":1}"
},
"Role": {
"1": "{\"name\":\"admin\",\"created\":\"2016-06-02T20:18:49.341Z\",\"modified\":\"2016-06-02T20:18:49.341Z\",\"id\":1}"
},
"user": {
"1": "{\"username\":\"John\",\"password\":\"$2a$10$SIGqZ4gLjJBUVsLx7N1H/ua/nSAPH69j3DeMSNprhGAHw9CCIS51y\",\"email\":\"john@doe.com\",\"id\":1}",
"2": "{\"username\":\"Jane\",\"password\":\"$2a$10$RFCl.psxnBbvIMhLC/sIse4X0yy.20Yy7.DOnH91YoPzXHUihHxzq\",\"email\":\"jane@doe.com\",\"id\":2}",
"3": "{\"username\":\"Bob\",\"password\":\"$2a$10$fRX/V/aGkCDyEwIwePas1.KuYBWQqDPD/rYqNio6lvRhZvwKDE1GS\",\"email\":\"bob@projects.com\",\"id\":3}"
},
"team": {
"1": "{\"ownerId\":1,\"memberId\":\"1\",\"id\":1}",
"2": "{\"ownerId\":1,\"memberId\":\"2\",\"id\":2}",
"3": "{\"ownerId\":2,\"memberId\":\"2\",\"id\":3}"
},
"project": {
"1": "{\"name\":\"project1\",\"balance\":100,\"ownerId\":1,\"id\":1}",
"2": "{\"name\":\"project2\",\"balance\":100,\"ownerId\":2,\"id\":2}"
}
}
}
Woah... this isn't right at all.
@TrevorPage, checkout the relations example to learn more about relations.
The team model isn't well designed here. If you ignore the fact that there are three separate team instances, I believe that the example still correctly displays the ACL logic.
Let me know if there's anything else I can help you out with. And thanks for finding the example design flaw!
Any plans to update the example? Seems like maybe the idea was to do something like, Project
has many members through Team
.
Hey @bajtos, do you have an answer for @FreakTheMighty?
@richardpringle hey, glad to see you are still helping :)
Any plans to update the example? Seems like maybe the idea was to do something like,
Project
has many members throughTeam
.
I am not familiar with this example myself. @raymondfeng @superkhau could you PTAL?
@FreakTheMighty No plans that I know of and with regards to priority, I don't believe it's high up there ATM -- @ritch Can you confirm?
Seems like maybe the idea was to do something like, Project has many members through Team.
No, the idea is to demonstrate a user can start many projects like they do on kickstarter, and that same user can belong to a team with various members (some with admin perms, some without etc).
Remember the goal is to demonstrate access control mechanisms, not demonstrate relations.
I'm going to close this as won't fix -- please see https://github.com/strongloop/loopback-example-relations for examples on model relations. Please note though, this example doesn't show programmatic usage -- mostly how to query via REST -- we need an programmatic relation example too.
We do not have any examples for both access control with relations ATM.
@FreakTheMighty @TrevorPage I added an issue you can track and upvote at https://github.com/strongloop/loopback-example-relations/issues/42 for programmatic relation examples and access control with relations at https://github.com/strongloop/loopback-example-relations/issues/43.
Thanks guys. If I understand right, what we're saying is that the relations here are possibly a bit contrived, but the reason is because this is purely to demonstrate access control.
@TrevorPage That is correct, the relations are totally contrived as the intent is to demonstrate access control. Thanks for clarifying for other users who may run into this. ;)
Feel free to submit a PR if you have time to refactor the relations to make it feel less contrived. :beer:
So in this scenario, what would be the right way to set up relations for users and teams?
Where a user can be the owner of multiple teams and teams have multiple members (which are users).
I've sort of posed this question here: https://groups.google.com/forum/#!topic/loopbackjs/Oki-1H9S6Es
I'm using this project to learn how model relations work, and the thing that confuses me is why a team is represented as separate objects in the database, where each team object seems to provide just one mapping of user to owner. This means that, if for example a team has three members (users), then there are three distinct team objects in the database.
It would make more sense to me if a team was represented as a single object, where the members property is an array.
Is there a specific reason why it's done like it is, perhaps because of the way relations work?