2016-12-14 74 views
3

我有兩個機型的用戶和地址嵌入的關聯,我連他們是這樣的:外生過濾空記錄

defmodule App.Address do 
    # ... 

    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:address, :city]) 
    end 
end 

當我使用:

inputs_for :addresses, [append: [App.Address{}]], fn address -> 
    text_input address, :address, class: "" 
end 

,我進入空的數據,它被保存爲零,我希望有一個解決方案,以過濾掉空的數據,並防止他們得到保存,所有我想出的是在控制器使用Enum.filter這將得到醜陋,因爲我認爲:

... 
filtered_addresses = Enum.filter(user_params["addresses"], fn {x, map} -> 
    map.address != "" and map.city != "" 
end) 

user_params = Map.put(user_params, :addresses, filtered_addresses) 

是否有更清潔的方式使用模型驗證,或在控制器中更乾淨的方式?

+0

我覺得函數[cast_embed/3](https://hexdocs.pm/ecto/Ecto.Changeset.html#cast_embed/3)應該接受一個類似':reject_if'的選項,類似於rails [accep_nested_attributes_for]( http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html)。我發佈了[問題到elixir-ecto郵件列表](https://groups.google.com/forum/#!topic/elixir-ecto/ScPo16tfllc) –

+0

@OleksandrAvoyants這是':with'選項的要點。您指定一個變更集,如果它無效,可以拒絕它。 –

+0

@JustinWood請糾正我,如果我錯了,但我認爲目前沒有辦法改變集拒絕記錄。 –

回答

0

您將要對變更集進行驗證。沿

def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:address, :city]) 
    |> validate_required([:address, :city]) 
end 

這東西線將確保有數據的列addresscity。如果沒有,該記錄將不會被保存。

你可以閱讀更多關於校驗和限制in the docs

+0

感謝賈斯汀的回答,地址不一定需要。當沒有設置地址字段時,沒有任何內容保存到數據庫中,而不會引發錯誤。 – kayne

+0

除非您使用'insert!/ 2',否則不會引發錯誤。如果使用'insert/2',它將返回'{:ok,struct}'或'{:error,changeset}'。什麼都沒有提出,它只是返回一個值,你可以做它想要的。 –

+0

是的,但它仍然必須驗證用戶模型,所以它需要能夠捕獲該模型的錯誤(用戶) – kayne

0

如果我理解正確的問題,你可能會尋找Phoenix.Controller.scrub_params/2

從文檔上面鏈接:

此功能是有用的,以除去通過HTML形式發送空字符串。

另外,this SO question似乎與您的問題類似,但目標是相反的。爲了超文本鏈接在這裏。

+0

這是否仍然會導致'nil'被放置在數據庫中? –

+0

謝謝你的回答,賈斯汀是對的,在這種情況下,scrub_params只會檢查「地址」鍵是否存在,而不是驗證地址映射(包含:地址和城市) – kayne

+0

我的印象是'默認情況下,空字符不會被Ecto保存到數據庫中,空字符串將會被保留。 – mudasobwa