如何在Elixir/Ecto的Postgres数据库中存储模块名?
Ecto.Atom to Store Module Names in Postgres Correct? Great question—let’s unpack this. Using Ecto.Atom for this scenario isn’t the safest or most robust choice, and here’s why, plus what you should do instead.
Why Ecto.Atom is problematic
Atoms in Elixir/Erlang are immutable and permanently stored in memory—they never get garbage collected. When you use Ecto.Atom, Ecto converts the string stored in Postgres directly into an atom via String.to_atom/1, which creates two critical issues:
- Memory leaks: If your database ends up storing module names that aren’t part of your application (or are dynamically generated), each new name will create a new atom that clogs up memory over time.
- Security risks: Malicious input (e.g., extremely long strings or crafted names) could exhaust the Erlang VM’s atom table, leading to a crash.
The Correct Approach
Instead, store the module name as a string in Postgres, then safely convert it to an atom at runtime only when you need to call the function. Here’s how to implement this:
Step 1: Update your schema
Change the field type to :string:
schema "xyz" do field(:module, :string) end
Step 2: Safely convert and call the module function
When you need to retrieve the module and invoke its function, use String.to_existing_atom/1 instead of String.to_atom/1. This function only converts strings to atoms that already exist in the VM (i.e., modules your application has loaded), preventing new atom creation.
Add validation to ensure the module and function exist before calling:
def call_module_function(xyz_record) do case String.to_existing_atom(xyz_record.module) do module -> # Verify the function exists with the correct arity if function_exported?(module, :a, 0) do apply(module, :a, []) {:ok, :function_called} else {:error, :function_not_found} end rescue ArgumentError -> # Raised if the module atom doesn't exist {:error, :module_not_found} end end
Why this works better
- Memory safety: No new atoms are created, so you avoid memory leaks from untrusted or dynamic module names.
- Robustness: Validating the module and function existence ensures your code doesn’t crash unexpectedly when the database has invalid entries.
- Flexibility: Storing strings is more portable—you can easily inspect or modify the values in Postgres without worrying about atom-specific constraints.
内容的提问来源于stack exchange,提问作者Arjun Singh

