2016-08-13 11 views
1

は、私のような移行持っている:Phoenix guidelinesからの提案に続き複合キー、 `unique_constraint`問題

defmodule N.Auth do 
    use N.Web, :model 

    @primary_key false 
    schema "auths" do 
    field :oauth_id, :string, primary_key: true 
    field :provider, :string, primary_key: true 

    belongs_to :user, N.User 

    timestamps() 
    end 

    @doc """ 
    Builds a changeset based on the `struct` and `params`. 
    """ 
    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:oauth_id, :provider]) 
    |> validate_required([:oauth_id, :provider]) 
    |> unique_constraint(:oauth_id, :auths_oauth_id_index) 
    end 
end 

defmodule N.Repo.Migrations.CreateAuth do 
    use Ecto.Migration 

    def change do 
    create table(:auths, primary_key: false) do 
     add :oauth_id, :string, primary_key: true 
     add :provider, :string, primary_key: true 

     add :user_id, references(:users, on_delete: :nothing, type: :binary_id) 

     timestamps() 
    end 

    create index(:auths, [:user_id]) 
    end 
end 

とモデル次のように構成します。私のテストで

defmodule N.AuthTest do 
    use N.ModelCase 

    import N.Factory 

    alias N.Auth 

    test "changeset with duplicates" do 
    auth_params = 
     %{provider: :facebook, 
     oauth_id: "1234"} 
    insert(:auth, auth_params) 

    changeset = Auth.changeset(%Auth{}, auth_params) 

    assert {:error, changeset} = Repo.insert(changeset) 
    end 
end 

それらを実行している場合残念ながら、私はエラーを次ています

create unique_index(:auths, [:oauth_id, :provider]) 
:私はそれを正しく理解していれば

1) test N.Auth.changeset/2 changeset with duplicates (N.AuthTest) 
    test/models/auth_test.exs:31 
    ** (FunctionClauseError) no function clause matching in Access.fetch/2 
    stacktrace: 
     (elixir) lib/access.ex:147: Access.fetch(:auths_oauth_id_index, :name) 
     (elixir) lib/access.ex:179: Access.get/3 
     (ecto) lib/ecto/changeset.ex:1629: Ecto.Changeset.unique_constraint/3 
     test/models/auth_test.exs:37: (test) 

、これはが不足しているためであります

は、unique_constraint/3の説明書に記載されています。明らかに、複合主キーを設定することによって自動的に作成されるので、インデックスを作成したくありません。

これ以上の対応方法はありますか?

UPDATE

ここで使用されるインデックス名はEcto自体によって提案された - 私は、インデックス名を指定せずにコードを使用する場合、そのよう:

|> unique_constraint(:oauth_id) 

私は、テストを実行すると、エラーを

1) test N.Auth.changeset/2 changeset with duplicates (N.AuthTest) 
    test/models/auth_test.exs:31 
    ** (Ecto.ConstraintError) constraint error when attempting to insert struct: 

     * unique: auths_pkey 

    If you would like to convert this constraint into an error, please 
    call unique_constraint/3 in your changeset and define the proper 
    constraint name. The changeset defined the following constraints: 

     * unique: auths_oauth_id_index 

    stacktrace: 
     (ecto) lib/ecto/repo/schema.ex:403: anonymous fn/4 in Ecto.Repo.Schema.constraints_to_errors/3 
     (elixir) lib/enum.ex:1183: Enum."-map/2-lists^map/1-0-"/2 
     (ecto) lib/ecto/repo/schema.ex:393: Ecto.Repo.Schema.constraints_to_errors/3 
     (ecto) lib/ecto/repo/schema.ex:193: anonymous fn/11 in Ecto.Repo.Schema.do_insert/4 
     (ecto) lib/ecto/repo/schema.ex:595: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6 
     (ecto) lib/ecto/adapters/sql.ex:472: anonymous fn/3 in Ecto.Adapters.SQL.do_transaction/3 
     (db_connection) lib/db_connection.ex:973: DBConnection.transaction_run/4 
     (db_connection) lib/db_connection.ex:897: DBConnection.run_begin/3 
     (db_connection) lib/db_connection.ex:671: DBConnection.transaction/3 
     test/models/auth_test.exs:41: (test) 

私が試しているときに同じエラーが発生しますcheck_constraint/3、のように:それはキー:nameとキーワードリスト項目にする必要のに対し

|> check_constraint(:oauth_id, name: :auths_oauth_id_index) 
+2

てみ 'unique_constraint(:oauth_id、名前:auths_pkey)'。それがうまくいかない場合は、 ':auths_pkey'を作成された実際のインデックスの名前で置き換えてください。それが動作すれば、私は説明を投稿します。 – Dogbert

+0

こんにちは@Dogbert、あなたの提案に感謝!これはまさにこれまで私がやったことです。私があなたが示唆したようにすると、エラーメッセージはほぼ同じままです。 '(elixir)lib/access.ex:147:Access。fetch(:auths_pkey、:name) 'を実行します。私は 'auths_oauth_id_index'に行ったもう少しの情報で私の質問を更新しました –

+0

' |> unique_constraint(:oauth_id、name::auths_pkey) 'がうまくいきませんか?これを追加した後にサーバーを再起動できますか? – Dogbert

答えて

0

だから、問題はあなたがunique_constraintへの第三引数として直接インデックス名を渡したということでした。

Access.fetch(:auths_oauth_id_index, :name) 

、あなたが渡された第三引数が:auths_oauth_id_indexあったという事実:

私の最初の手がかりは、このエラーメッセージでした。このエラーは、Ectoが値から:nameキーにアクセスしようとしていたことを意味し、リストまたはマップではないため、エラーをスローしていました。

また、インデックス名は:auths_oauth_id_indexではなく、Ectoがプライマリキーに割り当てたデフォルトの文字::auths_pkey(形式はtable_name <> "_pkey")でした。

最終作業コード:

|> unique_constraint(:‌​oauth_id, name: :auths_pkey)