2015-11-25 6 views
9

Ich habe ein ecto Modell für eine Adresse mit diesem (vereinfachte) Schema:Wie füge ich ein bedingtes Pflichtfeld hinzu?

defmodule Address do 
    use Ecto.Model 

    schema "addresses" do 
    field :zip, :string 
    field :country, :string 
    # snip 
    end 

    @countries_requiring_zip ~w(US) # snip 

    def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, ~w(country), ~w(zip)) 
    |> validate_zip 
    end 

    defp validate_zip(changeset) do 
    if get_field(changeset, :country) in @countries_requiring_zip do 
     # ???? 
    end 

    changeset 
    end 
end 

I zip nach Bedarf statt optional, aber nur, wenn das Land in einer weißen Liste markieren möchten ist, aber ich kann nicht finde einen sauberen Weg, die Validierung zu schreiben. Wie füge ich diese Einschränkung hinzu?

Antwort

11

Sie können einfach mehr definieren wirft auch:

def changeset(model, params \\ :empty) do 
    model 
    |> cast(params, ~w(country), ~w()) 
    |> cast_by_country(params) 
end 

defp cast_by_country(changeset, params) do 
    case get_field(changeset, :country) do 
    "US" -> cast(changeset, params, ~w(zip), ~w()) 
    _ -> cast(changeset, params, ~w(), ~w(zip)) 
    end 
end 

get_field/2 Wert aus den Änderungen lesen und auf die Struktur eines Rückfall, wenn es nicht ein. Dies ist der größte Vorteil von Changesets: Es ist nur die Datenstruktur und Sie können normalen Elixir-Code verwenden, um bedingte Prüfungen, Validierungen usw. durchzuführen. Einfach zum Schreiben, Lesen und Testen. :)

0

Es gibt keine explizite Funktion für die Forderung ein Feld außerhalb von cast. Sie können die Funktion validate_length/3 verwenden und die Option ': message' überschreiben.

validate_length(changeset, :zip, min: 1, message: "is required when country is US")