web-dev-qa-db-ja.com

フェニックスエリキシルの変更セットとは

モデルのchangesetの理解に問題があります。それは何ですか?単一のモデルに複数のチェンジセットを含めることはできますか?例えば1つは作成用、もう1つは更新用です。

誰かがフェニックスに来る他の人々を助けるように簡単な方法で詳しく説明できますか。

34
Murtza

ドキュメント から:

変更セットを使用すると、モデルの操作時に制約のフィルタリング、キャスト、検証、および定義が可能になります。

Ectoモジュールの入門ドキュメントには、チェンジセットの使用例があります。関数change/2とcast/4は、変更セットを作成するための通常のエントリポイントですが、残りの関数はそれらを操作するのに役立ちます。

変更セットは、モデルの作成と変更に使用されます。変更セットは、文字通り変更セット(および検証ルール)を格納する構造体です。変更セットが有効な場合は、変更セットをEcto Repoに渡します。

Ectoの現在のマスターブランチは、更新時にモデルをリポジトリに渡すときに暗黙的な変換を削除します。つまり、変更セットを使用してモデルを更新する唯一の方法です。

変更ログから:

Repo.update/2のモデルは、変更を追跡できないため、非効率的でエラーが発生しやすいため、廃止されました。

モデルごとに複数の変更セットを持つという点では、答えは確かに「はい」です。変更セットは単なる関数です。実際には、モデルにチェンジセット関数を配置する必要はありません必要はありませんが、それらを配置する一般的な場所です。

ユーザーの登録時に、ユーザーの更新よりも多くのフィールドが必要な場合は、aregister_changesetおよびcreate_changeset必須フィールドが異なります。

25
Gazler

Railsに少し精通している場合、ActiveRecordはデータベースアクセス、クエリ生成、検証をモデルで一元化し、Ectoはこれらの責任を個別のモジュールに分割します。

ActiveRecordメソッドはモデルクラスまたはインスタンス内で実行されますが、Ectoはモデル、クエリ、またはチェンジセットをその関数に渡すことを期待しています。

Ectoは、モデル内の検証を処理するのではなく、変更セットを使用して検証を実行します。

Ectoチェンジセットは検証と制約の両方を提供し、何かがうまくいかない場合には最終的にエラーになります。

それらの違いは、データベースと対話する必要なく検証を実行できるため、データベースにエントリを挿入または更新する前に常に実行されることです。

ただし、データベースで操作を実行する場合、制約は安全な方法でのみチェックできます。結果として、検証は常に制約の前にチェックされます。検証が失敗した場合でも、制約はチェックされません。

例を見てみましょう:

defmodule User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :name
    field :email
    field :age, :integer
  end

  def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> validate_inclusion(:age, 18..100)
    |> unique_constraint(:email)
  end
end

の中に changeset/2上記の関数では、2つの検証を定義します。1つは電子メール形式をチェックするため、もう1つは年齢をチェックするため、および電子メールフィールドの一意の制約です。

電子メールは送られたが、年齢が無効であると仮定しましょう。変更セットには次のエラーがあります。

changeset = User.changeset(%User{}, %{age: 0, email: "[email protected]"})
{:error, changeset} = Repo.insert(changeset)
changeset.errors #=> [age: "is invalid"]

この場合、データが検証されなかったため、電子メールフィールドの一意の制約を確認していません。年齢を修正して、電子メールがデータベースに既に存在すると仮定します。

changeset = User.changeset(%User{}, %{age: 42, email: "[email protected]"})
{:error, changeset} = Repo.insert(changeset)
changeset.errors #=> [email: "has already been taken"]

検証と制約は、チェックが発生したときに明示的な境界を定義します。制約をデータベースに移動することにより、ユーザー入力をチェックする安全で正しいデータ競合のない手段も提供します。

詳細はこちらをご覧ください Ecto Change Set

16
Subhash Chandra