2017-09-23 18 views
0

で私は2つのモデルを持っている - OrganizationUser 機関は、多くのユーザーを持っており、また(所有者があまりにもUserモデルである)1つの所有者に属します。保存一つのモデルに一度

Iは、ユーザが組織とnameuserためpasswordためnameを入力することができる組織、(userフォームでorganizationためのネストされたオブジェクトである)のためのフォームをサインアップしています。登録に成功した後、ownerUserモデル)のOrganizationが必要です。また、userはこの組織に属している必要があります。したがって、基本的には作成したユーザーはownerで、登録後にhas_many :usersのリストに登録する必要があります。

私は所有者の関連付けとしてユーザーと組織を作成することに成功しましたが、作成後にユーザーにhas_many :usersの関連付けをさせていただきたいと思います。 Railsでは、after_createコールバックを追加し、この場合はorganization_idを設定しますが、ectoにはコールバックがないので、どうすればよいですか?私はEcto.Multiについて読んだことがありますが、それが正しいアプローチ(それは私のために過度のように見えます)と、この場合にどのように使用できるかわからないのです。

場合によっては、モデルとサインアップフォームのコードはこちらです。

defmodule HappyClient.Organization do 
    use HappyClient.Web, :model 

    schema "organizations" do 
    field :name, :string 
    belongs_to :owner, HappyClient.User, foreign_key: :owner_id 
    has_many :users, HappyClient.User 

    timestamps() 
    end 

    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:name]) 
    |> validate_required([:name]) 
    end 

    def registration_changeset(struct, params) do 
    struct 
    |> changeset(params) 
    |> cast_assoc(:owner, required: true, with: &HappyClient.User.registration_changeset/2) 
    end 
end 

Userモデル

defmodule HappyClient.User do 
    use HappyClient.Web, :model 

    schema "users" do 
    field :email, :string 
    field :name, :string 
    field :password_hash, :string 
    field :is_admin, :boolean, default: false 
    field :is_operator, :boolean, default: false 
    belongs_to :organization, HappyClient.Organization 

    field :password, :string, virtual: true 

    timestamps() 
    end 

    @required_fields ~w(email name)a 
    @optional_fields ~w(is_admin is_operator)a 

    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, @required_fields) 
    |> validate_required([:email, :name]) 
    |> validate_format(:email, ~r/@/) 
    |> assoc_constraint(:organization) 
    end 

    def registration_changeset(struct, params) do 
    struct 
    |> changeset(Map.merge(params, %{"is_admin" => true})) 
    |> cast(params, [:password], []) 
    |> validate_required([:password]) 
    |> validate_length(:password, min: 6, max: 100) 
    |> hash_password 
    end 

    defp hash_password(changeset) do 
    case changeset do 
     %Ecto.Changeset{valid?: true, 
         changes: %{password: password}} -> 
     put_change(changeset, 
        :password_hash, 
        Comeonin.Bcrypt.hashpwsalt(password)) 
     _ -> 
     changeset 
    end 
    end 
end 

サインアップフォーム

<h1>Registration</h1> 

<%= form_for @changeset, organization_path(@conn, :create), fn f -> %> 
    <%= if @changeset.action do %> 
    <div class="alert alert-danger"> 
     <p>There are some errors</p> 
    </div> 
    <% end %> 
    <div class="form-group"> 
    <%= text_input f, :name, placeholder: "Organization Name", class: "form-control" %> 
    <%= error_tag f, :name %> 
    </div> 

    <div class="form-group"> 
    <%= inputs_for f, :owner, fn of -> %> 
     <%= text_input of, :name, placeholder: "Name" %> 
     <%= error_tag of, :name %> 
     <%= text_input of, :email, placeholder: "Email" %> 
     <%= error_tag of, :email %> 
     <%= password_input of, :password, placeholder: "Password" %> 
     <%= error_tag of, :password %> 

    <% end %> 
    </div> 
    <%= submit "Create Organization", class: "btn btn-primary" %> 
<% end %> 

答えて

0

Ecto.Multiは、私の場合に使用するのは難しいではないように思われます。ここで

は、私がやったきたし、それは完全に

changeset = %Organization{} |> Organization.registration_changeset(params) 

multi = Multi.new 
|> Multi.insert(:organization, changeset) 
|> Multi.run(:user, fn %{organization: organization} -> 
    organization 
    |> Repo.preload(:users) 
    |> Changeset.change 
    |> Changeset.put_assoc(:users, [organization.owner]) 
    |> Repo.update 
end) 

case Repo.transaction(multi) do 
    {:ok, %{organization: organization}} -> 
    conn 
    |> put_flash(:info, "#{organization.name} created!") 
    |> redirect(to: organization_path(conn, :show)) 
    {:error, :organization, changeset, %{}} -> 
    render(conn, "new.html", changeset: changeset) 
end 
を働いたものです
関連する問題