2017-11-07 10 views
0

私が取り組んでいるphoenixアプリケーションのスキーマにいくつかの検証を実装しようとしています。私のスキーマには、(とりわけ)質問と回答に関するデータを保持するマップが(詳細は)保持されているという属性があります。例:phoenixスキーマのカスタム検証用の制御フロー

%{ 
    question: "What's for dinner?", 
    options:[ 
    %{option: "Chicken", selected: false}, 
    %{option: "Fish", selected: true} 
    ] 
} 

スキーマには、:属性があり、:detailsマップの内容を記述するためにも使用されます。私は以下のバリデーションを書いています::詳細マップは、:typeが "dialogue"のとき、オプションの配列を含んでいます。

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 

これは機能しますが、実際には面倒です。私はエリキシル剤にはかなり新しいので、上記を達成するためのより簡潔な方法があると確信しています。誰も上記を実装するためのより合理的な方法をお勧めしますか?

ありがとうございます!

ボーナス:現在、詳細マップの少なくとも1つのオプションが選択されていることを確認するために、追加の検証を行っています。今、私は以下を使っていますが、もっと簡潔な実装に興味があります!

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

答えて

3

最初の部分は、パターンマッチングを使用して簡略化することができます。我々は、2つの用語、changeset.changes.typedetailsに興味がありますので、これらの用語のタプルにマッチします。第二つEnum.any?/2

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

あるいは

Enum.any?(details.options, & &1.selected) 
を使用して簡素化することができる

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 

関連する問題