2016-03-21 16 views
1

Bir Ecto modelinde benzersiz bir alana sahip olmak isterim. Bu alan kolayca oluşturabileceğim rastgele bir dize içermelidir (örneğin, bkz here). Bununla birlikte, dizgenin oluşturulmasından kaçınmak ve veri tabanında zaten mevcut olup olmadığını kontrol etmek istiyorum, bu da beni yarış koşullarına maruz bırakacaktı.Ecto modeline rastgele ve benzersiz bir alan ekleme

Benzersiz bir dize bulunana kadar yeniden yerleştirmeyi yeniden denemek isterim. Ama nasıl yaparım? changeset/2 işlevinin içinde mi olmalı?

defmodule LetsPlan.Event do 
    use LetsPlan.Web, :model 

    schema "events" do 
    field :name, :string 
    field :from, Ecto.DateTime 
    field :to, Ecto.DateTime 
    field :slug, :string 

    timestamps 
    end 

    @required_fields ~w(from to) 
    @optional_fields ~w(slug) 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, @required_fields, @optional_fields) 
    |> unique_constraint(:slug) 
    end 
end 
+0

Evet, diğer alanlar hazır olduğunda 'in changeset' fonksiyonu ve controller içerisinde sınırlaması var, sümüklü böcek üretmek , değişiklikleri setine koyun ve kaydetmeyi deneyin. Sonra üç durumda a) a) o çalıştı -> devam b) slug hakkında changeset.error -> yinelemeli sümüklü üretmek için kendini çağır ve tekrar deneyin c) diğer hatalar -> GUI içinde ele veya mevcut. – tkowal

+0

@tkowal Tamam, anladım ama bir sorum var: hatalar arasında nasıl ayrım yapabilirim? Örneğin, ek bilginin sümük nedeniyle başarısız olduğunu veya başka hatalar olduğundan nasıl anlarım? – rubik

+1

@tkowal Nevermind. Ecto'nun kaynak kodunu okudum ve hataların "changeset.error" dizinine yerleştirildiğini gördüm. Sen söyledin ama daha önce anlamadım. – rubik

cevap

2

4 ay geçti, sanırım bunu anladınız. Yaptığınız aksiyona ve "read" (okuma) amaçlı bir temel değişiklik yapısına bağlı olarak farklı değişiklikler oluşturmalısınız.

Açık> Örtülü

böyle bitebileceğini Modeliniz:

defmodule App.Classified do 

    @rules_create %{ 
    :required_fields => ~w(tenant_id firstname lastname email password password_confirmation phone birthday description), 
    :optional_fields => ~w(), 
    } 

    @rules_update %{ 
    :required_fields => ~w(firstname lastname email phone birthday description), 
    :optional_fields => ~w() 
    } 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, [], []) 
    end 

    @doc """ 
    Changeset when you create a new classified 
    """ 
    def create_changeset(model, params \\ :empty) do 
    model 
    |> cast(params, @rules_create.required_fields, @rules_create.optional_fields) 
    |> validate_length(:description, min: 280) 
    |> validate_length(:password, min: 6) 
    |> validate_confirmation(:password) 
    |> unique_constraint(:email) 
    |> hash_password 
    |> make_token 
    |> make_search 
    end 

    @doc """ 
    Changeset when you update an classified 
    """ 
    def update_changeset(model, params \\ :empty) do 
    model 
     |> cast(params, @rules_update.required_fields, @rules_update.optional_fields) 
     |> validate_length(:description, min: 280) 
     |> make_search 
    end 

end 
+0

Güzel! Bu şekilde gerçekten çok daha okunabilir. – rubik

0

@tkowal öneri ardından, aşağıdakileri yazdım. denetleyici olarak

def changeset(model, params \\ :empty) do 
    unless params == :empty do 
    params = params |> cast_date("from") |> cast_date("to") 
    end 

    model 
    |> cast(params, @required_fields, @optional_fields) 
    |> unique_constraint(:slug) 
end 

defp cast_date(params, key) do 
    params |> Map.update(key, nil, &Utils.to_ecto_date/1) 
end 

: Model modülünde

def create(conn, %{"event" => params}) do 
    params = Map.put(params, "slug", Utils.random_string(10)) 
    changeset = Event.changeset(%Event{}, params) 

    case Repo.insert(changeset) do 
    {:ok, event} -> 
     conn 
     |> put_flash(:info, "Event created successfully") 
     |> redirect(to: event_path(conn, :show, event.slug)) 
    {:error, changeset} -> 
     if Keyword.has_key? changeset.errors, :slug do 
     create(conn, %{"event" => params}) 
     else 
     render conn, "new.html", changeset: changeset 
     end 
    end 
end 

geribildirim her türlü açığız!