【问题标题】:How to get caller module name in included module?如何在包含的模块中获取调用者模块名称?
【发布时间】:2023-03-17 21:31:01
【问题描述】:

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

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    编辑:虽然这个答案回答了问题的标题,但正如@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
    

    【讨论】:

      【解决方案2】:

      首先,我认为这里有两个不同的问题:

      1。 repo.get_by(从一条数据中获取schema)

      要获取MyApp.MyQueryableModule 这是一个架构,您可以使用 repo.get_by/3 函数如下:

      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
      

      2。投射变更集

      在这段代码中,

        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 changesget_by ??),我通常保留我的变更集函数,仅用于验证更改和应用更改。最后,Ecto.Changeset.cast/4 已被弃用,取而代之的是 Ecto.Changeset.cast/3 请参阅 here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-28
        • 1970-01-01
        • 2012-07-27
        • 2023-03-17
        • 2013-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多