2017-09-23 46 views
0

我有兩個型號 - OrganizationUser 組織有許多用戶,也屬於一個所有者(老闆是User模型太)。在父對象的多個關聯保存一個模型一次

我報名形式組織,在那裏用戶可以爲組織和namepassworduser進入nameuser是在形式上organization嵌套對象)。成功註冊後,我需要有一個Organization及相關的ownerUser模型),並且此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 

用戶模型

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 
相關問題