2015-12-23 87 views
14

我正在凤凰城写一个简单的CRUD应用程序,管理员在创建新组织时可以使用初始工作人员帐户进行配置。Phoenix中处理嵌套窗体/ ecto变更集的正确方法是什么?

有效地,组织和用户之间的关系是多方面的。

我想出了以下内容:

  1. 用户模式:

    defmodule MyApp.User do 
    use MyApp.Web, :model 
    
    schema "users" do 
        field :name, :string 
        field :email, :string 
        field :password, :string, virtual: true 
        field :password_hash, :string 
    end 
    
    def changeset(...) # validate email, password confirmation etc. 
    
  2. 组织架构:

    defmodule MyApp.Org do 
        use MyApp.Web, :model 
    
        schema "orgs" do 
        field :official_name, :string 
        field :common_name, :string 
    
        has_many :org_staff_users, MyApp.OrgStaffUser 
        has_many :users, through: [:org_staff_users, :user] 
    end 
    
    def changeset(model, params \\ :empty) do 
        model 
        |> cast(params, ~w(official_name common_name), []) 
    end 
    
    def provisioning_changeset(model, params \\ :empty) do 
        model 
        |> changeset(params) 
        |> cast_assoc(:org_staff_users, required: true) 
    end 
    
  3. 结表org_staff_users和相应的外生模式与 user_idorg_id

  4. 控制器具有以下new行动:

    def new(conn, _params) do 
        data = %Org{org_staff_users: [%User{}]} 
        changeset = Org.provisioning_changeset(data) 
        render(conn, "new.html", changeset: changeset) 
    end 
    
  5. 模板有以下摘录:

    <%= form_for @changeset, @action, fn f -> %> 
         <%= if @changeset.action do %> 
         <div class="alert alert-danger"> 
          <p>Oops, something went wrong! Please check the errors below:</p> 
          <ul> 
          <%= for {attr, message} <- f.errors do %> 
           <li><%= humanize(attr) %> <%= message %></li> 
          <% end %> 
          </ul> 
         </div> 
         <% end %> 
    
        <%= text_input f, :official_name, class: "form-control" %> 
        <%= text_input f, :common_name, class: "form-control" %> 
    
        <%= inputs_for f, :org_staff_users, fn i -> %> 
         <%= text_input f, :email, class: "form-control" %> 
         <%= text_input f, :password, class: "form-control" %> 
         <%= text_input f, :password_confirmation, class: "form-control" %> 
        <% end %> 
    
        <%= submit "Submit", class: "btn btn-primary" %> 
    <% end %> 
    

到目前为止好,形式显示很好。

的问题是,我真的不明白什么应该是建立变更我即将上插入create的规范方式,同时能够 再次把它传递给在验证错误的观点。

目前还不清楚我是否应该使用一个变更(以及如何?)或每每个实体(UserOrg和结表)明确 3名的变更。

鉴于每个 模型/模式都定义了自己的特定验证,我如何验证此组合表单的更改?

提交表单后,我接受的参数都在%{"org" => ...} 图中,其中包括实际上与user有关的参数。我应该如何 正确创建表单?

我已阅读最近更新的http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/ 但我仍然困惑不管。

FWIW,我在Phoenix 1.0.4上,Phoenix Ecto 2.0和Phoenix HTML 2.3.0上。

任何提示将不胜感激。

回答

13

现在,除了在交易中做所有事情之外,您没有任何其他选择。您将在交易内部创建一个组织,该交易组织拥有自己的变更集,如果有效,则创建每个员工。事情是这样的:

if organization_changeset.valid? and Enum.all?(staff_changesets, & &1.valid?) do 
    Repo.transaction fn -> 
    Repo.insert!(organization_changeset) 
    Enum.each staff_changesets, &Repo.insert!/1) 
    end 
end 

通知我做的是不理想的,因为它不考虑约束的变更valid?检查。如果变更集中存在约束条件,则需要使用Repo.insert(不包括!)。

请记住,这将在Ecto 2.0上更容易。在外生的主人,我们已经通过变更支持belongs_to的,这意味着你将能够通过生成两个中间和结尾协会做明确:

<%= inputs_for f, :org_staff_users, fn org_staff -> %> 
    <%= inputs_for org_staff, :user, fn user -> %> 
    # Your user form here 
    <% end %>  
<% end %> 

然而,我们也将支持MANY_TO_MANY这将完全让它直前锋。

+0

@jose_valim,这将是巨大的博客文章,澄清这一点,或连结http://blog.plataformatec.com.br/2015/12/ecto-v1 -1发布和 - ecto-v2-0-计划/哪里更清楚地概述。我有完全相同的困惑。但是哦,我为Ecto 2.0感到兴奋。 –

+0

@JoséValim,首先感谢凤凰城所有的伟大工程,这是一个非常有前景的项目。至于嵌套表单的问题,我希望你在API文档中提供更多有关这方面的信息。生成器创建与其他实体有关系的实体(比如说发布给用户的帖子),但是没有任何表单域或方法允许在编写新帖子时将帖子分配给用户。请提供更多关于此的信息。 –

0

采用嵌入式架构描述here

相关问题