2016-06-10 56 views
6

Phoenix/Elixir'e gerçekten yeniyim ve kafamı changeet'lerin etrafına sarmaya çalışıyorum.Bir Ecto değişiklik kümesini repo'ya yerleştirmeden önce nasıl değiştirilir?

Bir model oluşturmak veya güncelleştirmek için kullanılan bir dizi değişiklik içerdiğini anlıyorum.

Bilmek istediğim, bir değişikliği veritabanına aktarmadan önce nasıl değiştirebilirim ve nasıl değiştirebilirim.

  • İnsanların veritabanında yeni sanatçıları oluşturmasına izin bir form var:

    Benim kullanım durumu şudur.

  • Bu formda bir uzmanlık alanı vardır.
  • sanatçı oluşturmadan önce, ben nedeniyle değişmezlik kısıtlamaları doğrudan changeset değiştirerek Bu mümkün bile emin değilim dize

bir dizi olarak saklamak "" ile özel alanını bölmek istediğiniz ama repo'ya eklemek için başka bir değişiklik yapabilirim.

Herhangi bir öneri memnuniyetle karşılanıyor ve yapmakta olduğum kötü uygulamaları veya aptalca şeyleri göstermekten çekinmeyin! yorumları sonrasında

DÜZENLEME: Ben böyle bir şey bakıyorum:

defp put_specialty_array(changeset) do 
    case changeset do 
    %Ecto.Changeset{valid?: true, changes: %{specialty: spec}} -> 
     put_change(changeset, :specialty, String.split(spec, ",")) 
    _ -> 
     changeset 
    end 
end 
+0

Bu, kullanıcının şifresini toplamak ve saklamak için benzer bir yaklaşımdır. ["Programlama Phoenix'i"] 'nin (https://pragprog.com/book/phoenix/programming-phoenix) bunu nasıl yaptığını kontrol edin (https://media.pragprog.com/titles/phoenix/code/authentication/listings /rumbl/web/models/user.change1.ex). DEFP put_specialty_array (değişiklik kümesi) % Ecto.Changeset {geçerli ?: gerçek, değişiklikleri yapmak değişiklik kümesi vaka yapın::% {uzmanlık: Spec – AbM

+0

Yani ben böyle bir şey yapabileceğini (özellikle nasıl 'registration_changeset' put_pass_hash'' çağırıyor) }} -> put_change (changeset,: uzmanlık, String.split (spec, ",")) changeset end end ? – Cratein

+0

Önerinizi biraz sabitleyin – AbM

cevap

9

ne aradığınız özel bir Ecto.Type olduğuna inanıyoruz. Bunu her zaman yapıyorum ve harika çalışıyor! Böyle bir şey olacaktır:

defmodule MyApp.Tags do 
    @behaviour Ecto.Type 
    def type, do: {:array, :string} 
    def cast(nil), do: {:ok, nil} # if nil is valid to you 
    def cast(arr) when is_list(arr) do 
    if Enum.all?(arr, &String.valid?/1), do: {:ok, arr}, else: :error 
    end 
    def cast(str) when is_binary(str), do: {:ok, String.split(",")} 
    def cast(_), do: :error 

    def dump(val) when is_list(val), do: {:ok, val} 
    def dump(_), do: :error 
    def load(val) when is_list(val), do: {:ok, val} 
    def load(_), do: :error 
end 

Sonra göçün, Nihayet şemada oluşturduğunuz alan türü belirtmek doğru tip

add :tags, {:array, :string} 

bir sütun ekleyin.

field :tags, MyApp.Tags 

Ardından, bunu değişiklik grubunuza alan olarak ekleyebilirsiniz. Türünüzün dökümü :error değerini döndürürse, değişiklik kümesinde {:tags, ["is invalid"]} gibi bir hata olacaktır. Model veya denetleyicinizdeki alanın işlenmesi hakkında endişelenmeniz gerekmez. Kullanıcı değer için bir dize dizisi veya yalnızca virgülle ayrılmış bir dize gönderirse, çalışır. Eğer farklı bir biçimde veritabanına değerini kaydetmek gerekirse

, sadece def type dönüş değerini değiştirmek ve def dump için bu türden bir değer döndürür sağlamak ve bu def load için bu tür bir değerini okuyabilir ediyorum ne olursa olsun İstediğiniz iç temsil. Yaygın bir model, içsel temsil için bir yapı tanımlamaktır; böylece, basit bir dizgeyi bile döndürebilen Poison'un to_json kendi uygulamanızı yapabilirsiniz. Bir örnek json olarak 12.12345N,123.12345W kodlayan bir LatLng tür, postgres bazı GIS türü olarak depolar, ancak iksir bazı basit matematik yapmanıza olanak sağlar %LatLng{lat: 12.12345, lng: -123.12345} gibi bir yapıya sahip. DateTime formatları çok işe yarar (iksir için bir yapı, db sürücüsü için bir tuple biçimi ve json için bir ISO formatı vardır).

Bu, parola alanları için gerçekten iyi çalışıyor btw.JSON temsilini ezberleyebilir, algoritmayı temsil eden bir yapı kullanabilir, algoritmadaki parametreleri algoritmadan ayıran ayrı bir tuz veya hayatı kolaylaştıran her şeyi yapabilirsiniz. Kodunuzda bir şifreyi güncellemek için sadece Ecto.Changeset.change(user, password: "changeme") olacaktır.

Bunun 6 aylık bir soru olduğunu ve muhtemelen bir şey bulmuş olduğunuzu anlıyorum, ancak bir Google aramadan geldim ve başkalarının da alacağını farz ettim.

+0

Geçerli kullanıcının içeriksel verilerini özel alana enjekte etmenin bir yolu var mı? Kullanıcının parola anahtarını kullanarak alanı şifrelemek/deşifre etmek istediğimde ve anahtarı özel alanın içinden başvurmak istediğimde sorun. –