2015-11-25 59 views
9

我有这个(简化)架构中的地址的外生模式:如何添加有条件的必填字段?

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 

我想所需,而不是可选的标记zip,但前提是该国正处于一个白名单,但我不能找出一个干净的方式来编写验证。我如何添加该约束?

回答

11

你可以简单地定义多个蒙上太:

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将读取的变化值,并退回到结构之一,如果没有一个。这是变更集的最大好处:它只是数据结构,您可以使用常规的Elixir代码进行条件检查,验证等。直接撰写,阅读和测试。 :)

0

对于要求cast以外的字段没有明确的功能。您可以使用validate_length/3函数并覆盖':message'选项。

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