$ mix phoenix.new demo $ cd demo
$ mix test
$ mix phoenix.gen.model Group groups name:string $ mix phoenix.gen.model Post posts name:string body:text group_id:references:groups
$ mix phoenix.gen.model User users name:string group_ids:array:integer
# web/models/user.ex defmodule Demo.User do use Demo.Web, :model schema "users" do field :name, :string field :group_ids, {:array, :integer} timestamps() end @doc """ Builds a changeset based on the `struct` and `params`. """ def changeset(struct, params \\ %{}) do struct |> cast(params, [:name, :group_ids]) |> validate_required([:name, :group_ids]) end end
Note that the changeset method allows you to change group_ids. So, if we use this method to edit the user profile by the user, the user will be able to add himself to any group. If this logic does not suit you, then you can add additional validation, confirming that the value of group_ids is a subset of the groups allowed for the user. Well, or you can simply prevent the user from changing the group_ids.
CREATE INDEX users_group_ids_rdtree_index ON users USING GIST (group_ids gist__int_ops);
# test/models/post_test.exs defmodule Demo.PostTest do use Demo.ModelCase alias Demo.{Post, Group, User} # changeset test "accessible for user" do g1 = %Group{} |> Repo.insert! g2 = %Group{} |> Repo.insert! g3 = %Group{} |> Repo.insert! %Post{group_id: g1.id} |> Repo.insert! p21 = %Post{group_id: g2.id} |> Repo.insert! p22 = %Post{group_id: g2.id} |> Repo.insert! p31 = %Post{group_id: g3.id} |> Repo.insert! user = %User{group_ids: [g2.id, g3.id]} |> Repo.insert! post_ids = Post |> Post.accessible_by(user) |> Ecto.Query.order_by(:id) |> Repo.all |> Enum.map(&(&1.id)) assert post_ids == [p21.id, p22.id, p31.id] end end
# web/models/post.ex defmodule Demo.Post do use Demo.Web, :model schema "posts" do field :name, :string field :body, :string belongs_to :group, Demo.Group timestamps() end @doc """ Builds a changeset based on the `struct` and `params`. """ def changeset(struct, params \\ %{}) do struct |> cast(params, [:name, :body]) |> validate_required([:name, :body]) end def accessible_by(query, user) do from p in query, where: p.group_id in ^user.group_ids end end
# web/models/post.ex defmodule Demo.Post do use Demo.Web, :model schema "posts" do field :name, :string field :body, :string field :group_ids, {:array, :integer} timestamps() end @doc """ Builds a changeset based on the `struct` and `params`. """ def changeset(struct, params \\ %{}) do struct |> cast(params, [:name, :body, :group_ids]) |> validate_required([:name, :body, :group_ids]) end def accessible_by(query, user) do from p in query, where: fragment("? && ?", p.group_ids, ^user.group_ids) end end
Source: https://habr.com/ru/post/310406/
All Articles