我们有很多测试我们手动建立关系。我们做的事情如下:
defp build_relationships(relationship_map, user) do
relationship_map |> Map.put(:user, %{data: %{id: user.id}})
end
这很好用,但我想让它灵活接受任何类型的记录(不仅仅是用户)。作为参考,user
创建时ex-machina
为insert(:user)
。
有没有办法获取传入的type
记录?如果我能得到一个标有"user"
的字符串,我可以使用String.to_atom(param)
并将其传递给Map.put
,但我无法找到一种优雅的方式来执行此操作。
真正的问题是我如何获取user
之类的记录并返回:user
的原子?
感谢任何帮助。
答案 0 :(得分:1)
您可以使用.__struct__.__schema__/1
获取有关Ecto结构的一些信息,例如:
iex(1)> %Post{}.__struct__.__schema__(:source)
"posts"
但由于从Schema到ExMachina工厂没有1:1的映射,我可以想到3种可能的方式:
将工厂重命名为使用复数形式,与表名相同,并使用.__struct__.__schema__(:source)
获取名称。这将使您的工厂代码有点奇怪,因为您将使用insert(:users)
插入一个用户。
继续使用单数名称,但使用一些库将多个表名转换为单数名,例如将"users"
转换为"user"
和"posts"
转换为"post"
的内容。
保留一份Schema< - >列表工厂名称映射,像这样(或者您甚至可以将映射移动到单独的函数):
defp build_relationships(relationship_map, struct) do
mapping = %{MyApp.User => :user, MyApp.Post => :post} # add more here
relationship_map |> Map.put(mapping[struct.__struct__], %{data: %{id: struct.id}})
end
使用Module.split/1
获取模型的名称,并使用Macro.underscore/1
将其转换为小写+下划线名称,然后使用String.to_existing_atom
:
defp build_relationships(relationship_map, struct) do
name = struct.__struct__ |> Module.split |> List.last |> Macro.underscore |> String.to_existing_atom
relationship_map |> Map.put(name, %{data: %{id: struct.id}})
end
如果您使用嵌套模块作为模型,这将无法正常工作,例如MyApp.Something.User
。
如果所有模型都处于相同的嵌套级别,我会选择4,如果你想更明确,我会选择3。