Contexte
Document de formation avec quatre tables liées :
- Clients (Adresse_mail, etc.)
- Produits
- Commandes (Client → Référence vers Clients)
- Lignes de commande (Reference_commande → Référence vers Commandes, qui elle-même référence Client)
Objectif : que chaque client connecté (via un attribut utilisateur basé sur l’email) ne voie et ne modifie que ses propres commandes.
Attribut utilisateur configuré :
- Nom :
Client - Propriété d’appairage :
user.Email - Table d’appairage :
Clients - Colonne cible :
Adresse_mail
Comportement observé
On cherche à paramétrer ces règles d’accès dans « Permissions avancées » (le panneau de gestion des Access Rules de Grist). Sur la table Commandes, toutes les formulations suivantes échouent silencieusement (aucune erreur affichée, mais la ligne n’est jamais considérée comme correspondant à la condition, même pour un client qui devrait légitimement y avoir accès) :
user.Client == rec.Client
user.Client.id == rec.Client.id
user.Email == rec.Client.Adresse_mail
rec.Client and user.Client.id == rec.Client.id
Résultat concret : avec une règle générique de refus (« Tous les autres ») active en dessous, l’utilisateur ne voit aucune commande, y compris celles qui lui appartiennent. Sans cette règle de refus, l’utilisateur retombe sur les règles par défaut du document (accès complet aux Editors), ce qui prouve que la règle spécifique ne matche jamais, dans un sens comme dans l’autre.
Preuve que les données sont pourtant identiques
Une colonne de diagnostic en formule déclenchée, testée en conditions réelles (un utilisateur avec droit U temporaire modifiant effectivement une ligne) :
return str(user.Client) + " | id=" + str(user.Client.id if user.Client else "None") + " || rec.Client=" + str($Client) + " | id=" + str($Client.id if $Client else "None")
Résultat affiché : Clients[14] | id=14 || rec.Client=Clients[14] | id=14
Les deux objets Référence sont donc rigoureusement identiques (même table, même id), mais la comparaison échoue quand même dans le contexte d’une condition de règle d’accès.
Point commun de tous les échecs
Toutes les formulations qui échouent déréférencent un champ à travers une colonne de Référence côté rec (rec.Client, rec.Client.id, rec.Client.Adresse_mail…). En revanche, le déréférencement côté user fonctionne normalement (user.Client.id, user.Email fonctionnent très bien isolément).
Confirmation par analogie : sur un autre document du même auteur (table de gestion de formateurs), une règle d’accès fonctionnelle et éprouvée en production suit exactement ce schéma :
$Offreur_txt == user.Inspecteur.Code_offreur_txt # fonctionne (colonne texte plate côté rec)
user.Email.lower() == $Cree_par.lower() # fonctionne (colonne texte plate côté rec)
Dans les deux cas, côté rec, c’est toujours une colonne déjà stockée en texte plat sur la ligne elle-même, jamais une valeur allant chercher plus loin à travers une Référence.
Solution de contournement (fonctionne, testée)
Ajouter une colonne « miroir » en formule classique (pas en règle d’accès) qui aplatit la valeur nécessaire directement sur la ligne :
# Sur Commandes, colonne "Client_email"
return $Client.Adresse_mail if $Client else None
# Sur Lignes de commande, colonne "Client_email"
return $Reference_commande.Client_email if $Reference_commande else None
La règle d’accès devient alors triviale et fonctionne immédiatement :
$Client_email == user.Email
Question
Est-ce un comportement connu et documenté (auquel cas une référence serait bienvenue, je n’ai rien trouvé de précis en cherchant), un bug à signaler, ou une limitation volontaire du bac à sable d’évaluation des règles d’accès (peut-être pour des raisons de performance ou de sécurité liées à l’évaluation en cascade des permissions sur la table référencée) ? Merci d’avance pour vos éclairages !