2017-08-24 7 views
0

私は小さなモジュールからモジュールを構成したいと思います。エリクサーとエクトのコードの重複

これは私が今持っているモジュールである。

defmodule Api.Product do 
    use Ecto.Schema 
    import Ecto.Changeset 
    import Api.Repo 
    import Ecto.Query 

    @derive {Poison.Encoder, only: [:name, :brand, :description, :image, :rating, :number_of_votes]} 
    schema "products" do 
    field :name, :string 
    field :brand, :string 
    field :description, :string 
    field :image, :string 
    field :rating, :integer 
    field :number_of_votes, :integer 
    field :not_vegan_count, :integer 
    end 

    def changeset(product, params \\ %{}) do 
    product 
    |> cast(params, [:name, :brand, :description, :image, :rating, :number_of_votes, :not_vegan_count]) 
    |> validate_required([:name, :description, :brand]) 
    |> unique_constraint(:brand, name: :unique_product) 
    end 

    def delete_all_from_products do 
    from(Api.Product) |> delete_all 
    end 

    def insert_product(conn, product) do 
    changeset = Api.Product.changeset(%Api.Product{}, product) 
    errors = changeset.errors 
    valid = changeset.valid? 
    case insert(changeset) do 
     {:ok, product} -> 
     {:success, product} 
     {:error, changeset} -> 
     {:error, changeset} 
    end 
    end 

    def get_product_by_name_and_brand(name, brand) do 
    Api.Product |> Ecto.Query.where(name: ^name) |> Ecto.Query.where(brand: ^brand) |> all 
    end 

    def get_products do 
    Api.Product |> all 
    end 
end 

しかし、私はすべてがbrandを除きProductと同じフィールドのほとんどを持っているProduct以外の異なるものを持っていると思います。したがって、brandを除くすべてのフィールドを持つモジュールを作成し、それらのフィールドを含むすべてのモジュールがそのモジュールをフィールドとして持つことをお勧めしますか?ここで

は、すべてのモジュールが含まれます私のモジュールです:

defmodule Api.VeganThing do 
    use Ecto.Schema 
    import Ecto.Changeset 
    import Api.Repo 
    import Ecto.Query 

    @derive {Poison.Encoder, only: [:name, :description, :image, :rating, :number_of_votes]} 
    schema "vegan_things" do 
    field :name, :string 
    field :description, :string 
    field :image, :string 
    field :rating, :integer 
    field :number_of_votes, :integer 
    field :not_vegan_count, :integer 
    end 
end 

vegan_thingsために何のデータベーステーブルはありません。しかし、データベーステーブルを持ついくつかの異なるモジュールにはvegan_thingが含まれます。

これは、Elixirの各モジュールのすべてのフィールドを書き換えるコードの重複を避けるための良い方法ですか?ここで

は私の現在のチェンジです:

defmodule Api.Repo.Migrations.CreateProducts do 
    use Ecto.Migration 

    def change do 
    create table(:products) do 
     add :name, :string 
     add :brand, :string 
     add :description, :string 
     add :image, :string 
     add :rating, :integer 
     add :number_of_votes, :integer 
     add :not_vegan_count, :integer 
    end 

    create unique_index(:products, [:name, :brand], name: :unique_product) 
    end 
end 

だから私はvegan_thingになり、フィールド上のユニークさだけproductにあるフィールドを基づかよ。このようなことをすることはできますか?

defmodule Api.Repo.Migrations.CreateProducts do 
    use Ecto.Migration 

    def change do 
    create table(:products) do 
     add :name, :string 
     add :vegan_thing, :vegan_thing 
    end 

    create unique_index(:products, [:vegan_thing.name, :brand], name: :unique_product) 
    end 
end 

または私はproductに直接nameフィールドを配置する必要がありますか?ユニークな制約として使用するにはvegan_thingの代わりに?

+0

['Ecto.Schema.embedded_schema/1'](https://hexdocs.pm/ecto/Ecto.Schema.html#embedded_schema/1)に似ていますか? – mudasobwa

答えて

2

マクロはこのような状況のために使用することができる。Ecto.Changesetを扱う他の機能のために

defmodule Vegan do 
    defmacro vegan_schema name, fields do 
     quote do 
     schema unquote(name) do 
      unquote(fields) 
      field :name, :string 
      field :description, :string 
      field :image, :string 
      field :rating, :integer 
      field :number_of_votes, :integer 
      field :not_vegan_count, :integer 
     end 
     end 
    end 

    def changeset(struct_or_changeset, params) do 
     struct_or_changeset 
     |> Ecto.Changeset.cast(params, [:name, :description, :rating]) 
     |> Ecto.Changeset.validate_required([:name, :description]) 
    end 
    end 

    defmodule Product do 
    use Ecto.Schema 
    require Vegan 

    @derive {Poison.Encoder, only: [:name, :brand, :description, :image, :rating, :number_of_votes]} 
    Vegan.vegan_schema "products" do 
     field :brand, :string 
    end 

    def changeset(params) do 
     %Product{} 
     |> Vegan.changeset(params) 
     |> Ecto.Changeset.cast(params, [:brand]) 
     |> Ecto.Changeset.validate_required([:brand]) 
    end 
    end 

Product.changeset/1コール上記の例に示すように、その後、定期的なモジュールおよび機能は、任意の重複コードを因数分解するための微細であるべきですVegan.changeset/2を使用して共通フィールドをキャストして検証します。

+0

ありがとうございます。 'Vegan'モジュールにベースチェンジセットを入れ、サブモジュール化モジュールにそれより小さなバージョンを入れますか? – BeniaminoBaggins

+1

はい、私は簡単な例で答えを更新しました。特に、 'Ecto.Changeset.cast'は、スキーマ構造体または' Changeset'を最初の引数として受け入れ、チェンジセット関数の作成を可能にします。 –