我在凤凰城写了一个简单的CRUD应用程序,管理员在创建一个新的组织时可以使用一个初始的员工帐户.
有效地组织与用户之间的关系是多对多的.
我想出了以下几点:
>用户架构
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.
>组织架构
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
>结点表org_staff_users和相应的Ecto Schema
user_id和org_id
>控制器具有以下新动作:
def new(conn,_params) do data = %Org{org_staff_users: [%User{}]} changeset = Org.provisioning_changeset(data) render(conn,"new.html",changeset: changeset) end
>具有以下摘录的模板:
<%= 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,:password_confirmation,class: "form-control" %> <% end %> <%= submit "Submit",class: "btn btn-primary" %> <% end %>
到目前为止这么好,表单很好看.
问题是,我真的不明白什么是规范的方式来构建我将要插入到创建的变更集,同时能够
将验证错误再次传递给视图.
是否应该使用一个变更集(和如何?)或明确地不清楚?
每个实体(用户,组织和联结表)有三个变化.
如何验证这种组合表单的更改,给定每个更改
模型/模式有自己的具体验证定义?
我在提交表单时收到的参数都在%{“org”=> …}
地图,包括实际上与用户有关的地图.我该怎么办
正确创建表单?
我已经阅读了最近更新的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.
任何提示将不胜感激.
解决方法
现在除了交易中的所有事情之外,您还没有任何其他选择.您将在交易中创建一个组织,该组织是自己的变更集,如果可以创建每个员工.这样的事情
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
注意我有效吗?检查非理想的变化集,因为它不考虑约束.如果在变更集中存在约束,则需要使用Repo.insert(不用bang!).
请记住,Ecto 2.0将会更容易.在Ecto master上,我们已经通过变更集支持belongs_to,这意味着你可以通过生成中间和结束关联来明确地做到这一点:
<%= inputs_for f,fn org_staff -> %> <%= inputs_for org_staff,:user,fn user -> %> # Your user form here <% end %> <% end %>
但是,我们也将支持多个,这将使它完全直截了当.