2017-11-07 2 views
0

Ich versuche, einige Validierungen in einem Schema für eine Phoenix-App, an der ich arbeite, zu implementieren. Ich habe ein Attribut in meinem Schema: Details, das (unter anderem) eine Karte enthält, die (unter anderem) Daten über Fragen und Antworten enthält. Ein Beispiel:Kontrollfluss für benutzerdefinierte Validierung in Phoenix-Schema

Das Schema hat auch ein Attribut: type, mit dem der Inhalt der Detailkarte beschrieben wird. Ich habe die folgende Validierung geschrieben, um sicherzustellen, dass die Map details eine Reihe von Optionen enthält, wenn der Typ "dialog" lautet.

def validate_dialogue_options(changeset) do 
    validate_change(changeset, :details, fn :details, details -> 
    if(changeset.changes.type == "dialogue") do 
     cond do 
     Map.has_key?(details, :options) -> 
      [] 
     true -> 
      [details: "must include options for dialogue events"] 
     end 
    else 
     [] 
    end 
    end) 
end 

Das funktioniert, aber es fühlt sich wirklich umständlich an. Ich bin ziemlich neu im Elixier, also bin ich mir sicher, dass es einen viel prägnanteren Weg gibt, das oben genannte zu erreichen. Kann jemand einen stromlinienförmigeren Weg empfehlen, das oben genannte zu implementieren?

Danke!

BONUS: Ich arbeite derzeit an einer zusätzlichen Validierung, um sicherzustellen, dass mindestens eine Option in der Detailkarte ausgewählt ist. Im Moment benutze ich das unten stehende, was funktioniert, aber ich wäre an einer prägnanteren Implementierung interessiert!

Enum.member?(Enum.map(details.options, fn(x) -> x.selected end), true) 

Antwort

3

Der erste Teil kann mit Pattern Matching vereinfacht werden. Wir sind an zwei Begriffen interessiert, changeset.changes.type und details, also passen wir auf ein Tupel dieser Begriffe.

validate_change changeset, :details, fn :details, details -> 
    case {changeset.changes.type, details} do 
    {"dialogue", %{options: _}} -> [] 
    {"dialogue", _} -> [details: "must include options for dialogue events"] 
    _ -> [] 
    end 
end 

kann der zweite Enum.any?/2

Enum.any?(details.options, fn x -> x.selected end) 

oder sogar

Enum.any?(details.options, & &1.selected) 
vereinfacht werden unter Verwendung von
Verwandte Themen