2016-08-30 7 views
2

に特定の制約エラーの処理私はフィールドのいずれかに一意制約を持つチェンジがあります。コントローラの一フェニックス

defmodule Oauth.Shop do 
    use Ecto.Model 
    import Ecto.Changeset 
    alias Ecto.Changeset 

    schema "shops" do 
    field :shop, :string 
    field :access_token, :string 
    field :scope, :string 
    field :active, :boolean 
    timestamps 
    end 

    def changeset(shop, params \\ %{}) do 
    shop 
    |> cast(params, [:shop, :access_token, :scope, :active]) 
    |> Changeset.validate_required([:shop, :access_token, :scope, :active]) 
    |> unique_constraint(:shop) 
    end 
end 

を、私は新しいお店を挿入します。重複したお店が作成されている場合は、例外が発生します。%ショップが変数ながら、構造体であることを

def save_shop({:ok, access_params}, shop) do 
    Repo.insert(%Shop{shop: shop, access_token: access_params.access_token, scope: access_params.scope}) 
    hook_uninstall(shop, access_params.access_token) 
    {:ok} 
    end 

注:

** (exit) an exception was raised: 
    ** (Ecto.ConstraintError) constraint error when attempting to insert model: 

    * unique: shops_shop_index 

ここで私はレコードを保存コードがありますshopはクエリ文字列パラメータからの単なる値です。

Ecto.ConstraintErrorのプラグを作成することはできますが、詳細なユーザーのフィードバックに必要な細かい制御はできません。

例外をキャッチし、ショップが既に登録されていることをユーザーに通知する良い方法はありますか?

+1

はどのようにあなたがDBに挿入されています。また、可能な場合代わりに.fieldを使用してマップのフィールドへのアクセスのパターンマッチングを使用することがより慣用的と考えられていますか?あなたは 'Repo.insert!'や 'Repo.insert'を使っていますか? [docs](https://hexdocs.pm/ecto/Ecto.Changeset.html#unique_constraint/3)によれば、後者は簡単にパターンマッチすることができる2つのタプル '{:error、changeset}'を返すべきですon –

+0

'Changeset'を構造体ではなく' Repo.insert'に渡していますか? – Dogbert

+0

@Dogbert et al。 。 。 Repo.insert()を含む質問が更新されました。 – sheldonkreger

答えて

2

あなたはEcto.ChangesetShopあなたはどんな効果があると、その関数で定義された検証とunique_constraintをしたい場合は、直接のstruct Repo.insertShop.changeset/2によって返さなく渡す必要があります。また、エラーの場合を処理するためにパターンマッチングを使用する必要があります。

def save_shop({:ok, access_params}, shop) do 
    case Repo.insert(Shop.changeset(%Shop{}, %{shop: shop, access_token: access_params.access_token, scope: access_params.scope})) do 
    {:ok, _} -> 
     hook_uninstall(shop, access_params.access_token) 
     {:ok} 
    {:error, changeset} -> 
     # Put whatever value you want to return in case of an error here. 
     # You can get more details about the error using `changeset.errors`. 
     {:error} 
    end 
end 

(私はあなただけの挿入が成功した場合hook_uninstallを実行したいと仮定しました。それはケースではない場合は、他のブランチにその行をコピーしたりcase外に移動することができます。)

def save_shop({:ok, %{access_token: access_token, scope: scope}}, shop) do 
    case Repo.insert(Shop.changeset(%Shop{}, %{shop: shop, access_token: access_token, scope: scope})) do 
    {:ok, _} -> 
     hook_uninstall(shop, access_token) 
     {:ok} 
    {:error, changeset} -> 
     # Put whatever value you want to return in case of an error here. 
     # You can get more details about the error using `changeset.errors`. 
     {:error} 
    end 
end 
+0

これはどのように動作するのですか、ありがとう。 2番目の例ではTypo、2番目の行には閉じ括弧がありません。ソリューションと慣用的な実装を見ていただきありがとうございます。私はまだいくつかの古い習慣を壊しており、パターンマッチングについて覚えておく必要があります。 – sheldonkreger

+1

ありがとう、ありがとう。喜んで助けた!パターンマッチングには慣れるまでに時間がかかることがありますが、パターンマッチングを行わなくても言語を使用する必要があるたびにパターンマッチングは間違っています。 – Dogbert

関連する問題