如何在包含的 MyApp.MyUniversalModule
中获取调用者模块并通过 field_name 参数获取?
defmodule MyApp.MyUniversalModule do
def gen_and_check_unique(changeset, field_name) do
token = random_string()
# MyApp.MyQueryableModule |> Repo.get_by(field_name, token)
end
def random_string(length \\ 8) do
:crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length)
end
end
defmodule MyApp.MyQueryableModule do
use MyApp.Web, :model
import MyApp.MyUniversalModule
schema "items" do
field :name, :string
field :token, :string
end
def changeset(model, params) do
model
|> cast(params, ~w(name), ~w())
|> gen_and_check_unique(:token)
end
end
最佳答案
编辑:虽然这个答案回答了问题的标题,但正如@stephen_m 的回答所指出的那样,您的代码在几个地方是不正确的。
虽然你can在运行时获取调用堆栈并从中提取调用模块,这将是低效的,通常不推荐。 Elixir 中惯用的方法是使用宏和 __using__
钩子(Hook)。 Ecto uses the same method for Repo
以及许多其他模块。
基本上,您在 __using__
宏的引号内定义了所有要注入(inject)到调用方模块中的函数。在这种情况下,它看起来像(未经测试):
defmodule MyApp.MyUniversalModule do
defmacro __using__(_opts) do
quote do
def gen_and_check_unique(changeset, field_name) do
token = random_string()
__MODULE__ |> Repo.get_by(field_name, token)
end
def random_string(length \\ 8) do
:crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length)
end
end
end
end
然后,在 MyApp.MyQueryableModule
中,更改:
import MyApp.MyUniversalModule
到
use MyApp.MyUniversalModule
你可能不想用 random_string
污染调用模块,在这种情况下你可以这样做(同样未经测试):
defmodule MyApp.MyUniversalModule do
defmacro __using__(_opts) do
quote do
def gen_and_check_unique(changeset, field_name) do
token = MyApp.MyUniversalModule.random_string()
__MODULE__ |> Repo.get_by(field_name, token)
end
end
end
def random_string(length \\ 8) do
:crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length)
end
end
关于elixir - 如何在包含的模块中获取调用方模块名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39221484/