2017-02-06 10 views
1

Я хочу сделать «ежедневный обед для голосования» для людей здесь, на работе, используя Phoenix Framework. Модель, которую я думал о создании, была Votation, с каждой версией, содержащей много встроенных схем Restaurants (Прочитайте here для информации о встроенных схемах). Модель выглядит так:Phoenix Framework: limit Вставить в базу данных по 1 в день

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 в день. Каков наилучший подход для этого?

+1

Воспользуйтесь уникальным индексом ваших баз данных в поле даты. –

ответ

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 

База данных теперь запрещает создание 2 сообщений с таким же днем ​​в inserted_at:

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>}