Best practices for defining Ecto associations

Hello everyone,

My team and I are looking for perspectives on best-practices when defining associations in Ecto. Currently, we are using a Postgres database, and have defined a number of schemas in Ecto, some of which have associations. Our current pattern has been to use the Ecto.Query Macro API to define queries. When performing joins across tables / schemas, we don’t use our defined associations, and instead elect to join using the table name and an :on query expression.

Our questions are:

  • Since we are not using associations in our queries, should we eliminate the association definitions altogether?
  • Is there a benefit to keeping the unused association definitions, perhaps as documentation of underlying foreign keys?
  • Is there added benefit to using the associations when defining Ecto queries?

Thanks in advance!

Offhand, here’s a few:

  • filtering with the where option
  • composing associations with the through option
  • Repo.preload etc

Counter-question: what’s the advantage to doing this? It seems mostly harmless - foreign keys don’t change names very much, reducing the risk of duplication - but it’s still repeating things that don’t need to be repeated…

1 Like

This one is quite handy as well: Ecto.assoc

I find associations useful when preloading data and doing joins:

defmodule Account do
  schema do
    has_many :users, User
  end
end

defmodule User do
  schema do
    belongs_to :account, Account
  end
end

and then:

user = Repo.get(User, 1) |> Repo.preload(:account)

or

from user in User,
  join: account in assoc(user, :account),
  where: account.foo = ...
3 Likes
  • Answer 1: Yes. But I prefer using them.
  • Answer 2: Yes. I think it’s better to maintain association at schema level. Generally, migrations are broken code snippets, they can’t give you a panoramic view.
  • Answer 3: Yes. Read more in following content.

Suppose A has many B:

  • When you just want to get B, use Ecto.assoc.
  • When you want A and related B, use Ecto.preload or Ecto.Query.preload.
  • When :join is required, try assoc which make use of the associations defined in schema. Then, generally, you don’t need to use :on.

If you don’t define associations at schema level, you can’t use all of these good stuff.

1 Like