如何在包含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
答案 0 :(得分:3)
编辑:虽然这个答案回答了问题的标题,但是你的代码在几个地方是不正确的,正如@ stephen_m的答案所指出的那样。
虽然你can在运行时获取调用堆栈并从中提取调用模块,但它效率低下,通常不推荐使用。 Elixir中的惯用方法是使用宏和__using__
钩子。 Ecto uses the same method for Repo
以及许多其他模块。
基本上,您可以在__using__
宏的引号内定义要注入调用者模块的所有函数。在这种情况下,这看起来像(未经测试):
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
答案 1 :(得分:3)
首先,我认为这里有两个不同的问题:
要获取作为架构的[1,[2],{"foo":"bar"},4]
,您可以使用
Repo.get_by / 3函数如下:
MyApp.MyQueryableModule
在此代码中,
alias MyApp.MyQueryableModule
defmodule MyApp.MyUniversalModule do
def gen_and_check_unique(field_name) do
Repo.get_by(MyQueryableModule, [{field_name, random_string()}])
end
end
您似乎正在尝试返回 def changeset(model, params) do
model
|> cast(params, ~w(name), ~w(token))
|> gen_and_check_unique(:token)
end
,通常情况下会Ecto.Schema.t
。另外,我不确定,但你可能在这个函数中做了两件事(Ecto.Changeset.t
和applying changes
??),我通常会保留我的变更集功能,仅用于验证更改和应用更改。最后,我们弃用get_by
,转而使用Ecto.Changeset.cast/4
请参阅here。