elixir - 如何在包含的模块中获取调用方模块名称?

标签 elixir phoenix-framework ecto

如何在包含的 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/

相关文章:

elixir - Phoenix - 管理多个数据库的迁移混合任务的问题

recursion - Elixir 中的递归是如何工作的

elixir - 使用 Ueberauth 不断收到跨站点请求伪造错误

postgresql - 设置 Phoenix Framework 和 Ecto 以使用 UUID : how to insert the generated value?

elixir - Phoenix : foreign key not being inserted

elixir - 无法连接 : ** (Postgrex. 错误)致命(invalid_catalog_name):数据库 "api_example_dev"不存在

postgresql - 如何在 Phoenix 框架上使用 mix 命令连接到 Postgres?

药剂Ecto : How to validate foreign key constraint?

postgresql - 如何使用 Ecto/Phoenix 从数据库中选择最新条目

elixir - 作为参数的 map 列表