2016-08-10 8 views
5

挿入されていない私は別のモデルB.フェニックスエクト:外部キーが

defmodule MyApp.ModelA do 
    use MyApp.Web, :model 

    schema "model_a" do 
    field :type, :string, null: false 
    field :data, :string, null: false 
    belongs_to :model_b, MyApp.ModelB 
    timestamps() 
    end 

    @required_fields ~w(type data) 
    @optional_fields ~w() 

    @doc """ 
    Builds a changeset based on the `struct` and `params`. 
    """ 
    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, @required_fields, @optional_fields) 
    |> assoc_constraint(:model_b) 
    end 
end 

とモデルBへの外部キー含まモデルAを挿入しています:

defmodule MyApp.ModelB do 
    use MyApp.Web, :model 

    schema "model_b" do 
    field :username, :string 
    field :pass, :string 
    has_many :model_a, MyApp.ModelA 
    timestamps() 
    end 

    @required_fields ~w(username pass) 
    @optional_fields ~w() 

    @doc """ 
    Builds a changeset based on the `struct` and `params`. 
    """ 
    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, @required_fields, @optional_fields) 
    |> cast_assoc(:model_a) 
    |> validate_required([]) 
    end 
end 

モデルBが存在し、 Repo.all(ModelB)を介して取得することができます。

モデルAチェンジセットは正常に検証され、モデルAチェンジセット構造体を印刷するとmodel_b_id値が確認できます。

ただし、挿入すると参照が挿入されません。モデルAのチェンジセットを印刷するときに、MySQLログでこのフィールドが完全に欠落していることがわかりますが、INSERTクエリにはありません。

私はちょっと試してみましたが、この参照フィールドをMySQLテーブルで強制的にヌルにしないと、Repo.insert(...)レスポンスとして挿入するときにこの外部キーフィールドに{"does not exist", []}が表示されますモデルBはデータベースに存在しますが、

+0

チェンジセットの検証では外部キーの検証はチェックされないため、存在しません "というエラーメッセージが表示されます。モデルのスキーマと、実行したコードとSQ​​Lログを投稿できますか? – Dogbert

+0

ソリーリー、多分私は自分自身を説明しなかった。私はRepo.insert(...)の応答として "存在しない"ということを得ます。チェンジセットの検証は、この場合、常に正常に機能します。 – David

+0

チェンジセットに 'model_b_id'がありますか? '@ optional_fields'はちょうどあなたが掲示したコードに従って空です。 '@ optional_fields'に' model_b_id'を追加できますか? – Dogbert

答えて

0

私はエクトがあなたのためのstructオフIDフィールドを引くとは思わない - 私はこのような何かをやってきた:

defmodule MyApp.ModelA do 
    use MyApp.Web, :model 

    schema "model_a" do 
    field :type, :string, null: false 
    field :data, :string, null: false 
    belongs_to :model_b, MyApp.ModelB 
    timestamps() 
    end 

    @required_fields ~w(type data model_b_id) 
    @optional_fields ~w() 

    @doc """ 
    Method head to define what's coming. 
    """ 
  def changeset(model, params \\ :empty) 

    @doc """ 
    Catches the case where you're passing in a model_b struct instead of an integer. 
    Just makes a recursive call with the correct type. 
    """ 
  def changeset(model, %{model_b_id: nil, agency: %MyApp.ModelB{} = model_b} = params) do 
    changeset(model, %{params | model_b_id: model_b.id}) 
  end 

    @doc """ 
    I normally use assoc_constraint on the table index itself like so 
    """ 
    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, @required_fields, @optional_fields) 
    |> assoc_constraint(:model_b, name: :model_as_model_b_id_fkey) 
    end 
end 
0

が、私はこの質問に応答して、最高に興味がありました。

「私はこの行が作成されたことを知っていますが、なぜチェンジセットは私に参照を保存させないのですか?

と同じ不満を持っている人には、データベース移行リファレンスをご確認ください。

私はトリプルをチェックしたと確信していましたが、良い夜の眠りの後、明日は明白でした。間違ったテーブルへのセットアップ参照がありました。

これにより、誰かが時間を節約できることを望みます。あなたは時々

model_b = Repo.get(MyApp.ModelB, 2) 
model_a_changeset = Ecto.build_assoc(model_b, :model_as, 
    type: "Model type", 
    data: "Model data" 
) 
Repo.insert! model_a_changeset 

(数がmodel_bのidの一例である、あなたは正しい親IDを取得する方法を把握する必要があり)

次られた私のために働いた何

0

次のように変更セットの外部キーを明示的に指定する必要があります。

model_a_changeset = Ecto.build_assoc(model_b, :model_as, 
    type: "Model type", 
    data: "Model data", 
    model_b_id: model_b.id 
)