我希望每天做一次午餐和#34;使用Phoenix Framework在线工作的应用程序。我想做的模型是Votation
,每个Votation包含许多嵌入式Restaurants
模式(有关嵌入式模式的信息,请阅读here)。该模型看起来像这样:
defmodule WhereToLunch.Votation do
use WhereToLunch.Web, :model
schema "votations" do
embeds_many :restaurants, Restaurant
timestamps()
end
@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [])
|> validate_required([])
|> #TODO: Is it !was_votation_inserted_today() ??
end
@doc """
Returns `true` if a `Votation` object was already inserted in the database
on the same day the function is called. Returns false otherwise.
"""
def was_votation_inserted_today() do
#TODO: How to check if a object was already inserted in the database
# on the same day the function is called?
end
end
defmodule WhereToLunch.Restaurant do
use Ecto.Model
embedded_schema do
field :name, :string
field :votes, :integer, default: 0
end
end
我想要做的是每天不要在表Insert
中允许多个where_to_launch.votations
。这样做的最佳方法是什么?
答案 0 :(得分:3)
我在表达式date_part('day', inserted_at)
上添加一个唯一索引,让数据库处理唯一性。
要创建唯一索引,请将以下内容添加到新迁移中:
def change do
create index(:posts, ["date_part('day', inserted_at)"], name: "post_inserted_at_as_date", unique: true)
end
然后将unique_constraint
添加到您的模型changeset/2
:
def changeset(...) do
...
|> unique_constraint(:inserted_at, name: "post_inserted_at_as_date")
end
数据库现在将禁止在inserted_at
中的同一天创建2个帖子:
iex(1)> Repo.insert Post.changeset(%Post{}, %{title: ".", content: "."})
[debug] QUERY OK db=0.3ms
begin []
[debug] QUERY OK db=3.4ms
INSERT INTO "posts" ("content","title","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" [".", ".", {{2017, 2, 6}, {16, 58, 0, 512553}}, {{2017, 2, 6}, {16, 58, 0, 517019}}]
[debug] QUERY OK db=0.9ms
commit []
{:ok,
%MyApp.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">,
comments: #Ecto.Association.NotLoaded<association :comments is not loaded>,
content: ".", id: 1, inserted_at: ~N[2017-02-06 16:58:00.512553], title: ".",
updated_at: ~N[2017-02-06 16:58:00.517019],
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: nil}}
iex(2)> Repo.insert Post.changeset(%Post{}, %{title: ".", content: "."})
[debug] QUERY OK db=0.4ms
begin []
[debug] QUERY ERROR db=6.6ms
INSERT INTO "posts" ("content","title","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" [".", ".", {{2017, 2, 6}, {16, 58, 1, 695128}}, {{2017, 2, 6}, {16, 58, 1, 695138}}]
[debug] QUERY OK db=0.2ms
rollback []
{:error,
#Ecto.Changeset<action: :insert, changes: %{content: ".", title: "."},
errors: [inserted_at: {"has already been taken", []}], data: #MyApp.Post<>,
valid?: false>}