Ecto

naive_datetimeでなく、utc_datetime_usecを使用したほうが良いという話 https://elixirforum.com/t/why-use-utc-datetime-over-naive-datetime-for-ecto/32532

preload

交差テーブルでpreloadする方法は、

例えば、

def get_user_by_role(role_name) when is_binary(role_name) do
  from(u in User,
    join: ur in UserRole,
    on: ur.user_id == u.id,
    join: r in Role,
    on: r.id == ur.role_id,
    where: r.name == ^role_name,
    select: u
  )
  |> Repo.all()           # ここでselect1回走る
  |> Repo.preload(:roles) # ここでselect2回走る
end

あるいはこう、

def get_user_by_role(role_name) when is_binary(role_name) do
  from(u in User,
    join: ur in UserRole,
    on: ur.user_id == u.id,
    join: r in Role,
    on: r.id == ur.role_id,
    where: r.name == ^role_name,
    preload: :roles,
    select: u
  )
  |> Repo.all()           # ここでselect3回走る
end

selectを1回で済ましたい場合は、明示的に書く。 see. https://hexdocs.pm/ecto/Ecto.Query.html#preload/3

def get_user_by_role(role_name) when is_binary(role_name) do
  from(u in User,
    join: ur in UserRole,
    on: ur.user_id == u.id,
    join: r in Role,
    on: r.id == ur.role_id,
    where: r.name == ^role_name,
    preload: [roles: r]
    select: u
  )
  |> Repo.all()           # ここでselect1回走る
end

You don’t have to use :put_assoc or :cast_assoc

https://medium.com/@lauraannwilliams/you-dont-have-to-use-put-assoc-or-cast-assoc-48b8575be3ce

assoc_constraint の 嬉しさが分からない。ドキュメントに

This is similar to foreign_key_constraint/3 except that the field is inferred from the association definition.

とあるが、以下のようにcastで :post_id を書いている時点で :post_id の存在を知っているので意味がないと感じる。

comment
|> Ecto.Changeset.cast(params, [:post_id])
|> Ecto.Changeset.assoc_constraint(:post)
|> Repo.insert

暗に使うくらいなら、 foreign_key_constraint で明にした方がいい気がする。

put_assocでなくbuild_assocを使うケース

def create_user_property(%User{} = user, attrs) do
  Ecto.build_assoc(user, :property)
  |> UserProperty.changeset(attrs)
  |> Repo.insert()
end

# changesetの後にput_assocするとuser_idにvalidationをかけたい場合にかけられない。
def create_user_property(%User{} = user, attrs) do
  %UserProperty{}
  |> UserProperty.changeset(attrs)
  |> Ecto.Changeset.put_assoc(:user, user)
  |> Repo.insert()
end