Ecto Schema默认值调用同模块函数报错undefined my_perfect_random/0求助
解决Ecto Schema中默认值函数调用报错的问题
嘿,这个问题我之前也碰到过,其实是Ecto处理schema默认值的规则和编译顺序的问题导致的,咱们一步步来解决:
问题根源
你之前的写法default: my_perfect_random或者default: MyModule.my_perfect_random是直接在编译时调用函数,但Ecto在解析schema定义的时候,要么你的函数还没被定义(比如写在schema之后),要么这种直接调用的方式不符合Ecto对动态默认值的要求——Ecto需要你传递函数的引用,而不是函数执行后的结果,这样它才会在每次创建新记录时去调用这个函数。
两种正确的写法
写法一:函数定义在schema之前,使用函数引用
如果你的my_perfect_random/0函数和schema在同一个模块里,把函数放在schema定义前面,然后用&函数名/0的形式传递引用:
defmodule MyApp.SomethingGreat do use Ecto.Schema # 先定义随机函数 def my_perfect_random do # 这里写你的随机字符串生成逻辑,比如: "random_#{:crypto.strong_rand_bytes(8) |> Base.encode16()}" end schema "something_great" do field :my_amazing_field, :string, default: &my_perfect_random/0 timestamps() end end
写法二:使用MFA(模块-函数-参数)形式,不受编译顺序限制
如果你的函数写在schema之后,或者想更明确地指定运行时调用,用{模块名, 函数名, 参数列表}的MFA格式,这里参数列表是空的因为你的函数是0参数:
defmodule MyApp.SomethingGreat do use Ecto.Schema schema "something_great" do field :my_amazing_field, :string, default: {__MODULE__, :my_perfect_random, []} timestamps() end # 函数可以放在schema之后定义 def my_perfect_random do "random_#{:crypto.strong_rand_bytes(8) |> Base.encode16()}" end end
额外注意点
别用直接调用的方式(比如default: my_perfect_random()),那样会在编译schema的时候只执行一次函数,所有新创建的记录都会用同一个随机值,这肯定不是你想要的。用上面两种方法,Ecto会在每次插入新记录时都调用一次你的随机函数,生成新的字符串。
内容的提问来源于stack exchange,提问作者denqxotl
相关产品推荐
相关产品推荐

