Search code examples
elixirphoenix-frameworkecto

How to achieve many-to-many association in Ecto with primary keys?


I have three tables, permissions, permission_sets and their junction table permission_set_permissions.

The permissions table hold Permission model data, and the size of this table is deterministic. To clarify, we are not going to insert any data to this table when application is running.

The model PermissionSet persisted in permission_sets table has many-to-many relationship with Permission.

Normally, you would create a PermissionSet with that request:

POST /api/v1/permission_sets/

{
    "permission_set": {
        "name": "default",
        "description": "Default permission set.",
        "permissions": [
            {
                "type": "all",
                "required_grant_power": 200,
                "controller_name": "Elixir.MyApp.UserController",
                "controller_action": "index"
            },
            {
                "type": "one",
                "required_grant_power": 200,
                "controller_name": "Elixir.MyApp.UserController",
                "controller_action": "show"
            }
        ]
    }
}

However, this would create new Permissions with given data.

In my case, I'd like to reuse the existing permissions with their primary keys. An example would be:

POST /api/v1/permission_sets/

{
    "permission_set": {
        "name": "default",
        "description": "Default permission set.",
        "permission_ids": [
            2,
            7
        ]
    }
}

Do you have any suggestion on implementing this? Should I create a new model named PermissionSetPermission representing junction table?


Solution

  • Something like this should do the job:

    def changeset(struct, params \\ %{}) do
      permissions = 
        Permission
        |> where([p], p.id in ^params[:permission_ids])
        |> Repo.all
    
      struct
      |> cast(params, [:name, :description])
      |> put_assoc(:permissions, permissions)
    end