Elixir Phoenix未登录报function nil.id/0 is undefined错误排查
问题原因
报错触发逻辑非常明确:
- 未登录用户访问页面时,控制器传递给模板的
@current_user赋值为nil - 现有判断逻辑直接执行
@current_user.id,等价于调用nil.id/0函数,而nil是Elixir内置原子类型,不存在id成员方法,因此抛出UndefinedFunctionError异常 - 原判断逻辑没有做空值兜底,只要用户未登录就会触发报错,和帖子本身的权限归属判断无关
修复方案
1. 模板层快速修复
调整判断顺序,优先校验@current_user非空,再执行用户ID比对,利用Elixir&&运算符的短路特性,空值场景下不会执行后续的ID取值逻辑。修正后的模板代码如下:
<%= if @current_user && @current_user.id == @post.user_id do %> <span> <%= link "Edit", to: Routes.post_path(@conn, :edit, @post) %> </span> <span> <%= link "Delete", to: Routes.post_path(@conn, :delete, @post), method: :delete, data: [confirm: "Are you sure"] %> </span> <% end %>
2. 工程化规范实现
不建议把权限判断逻辑直接散落在模板中,后续迭代很容易出现漏判,推荐把权限逻辑抽成可复用的辅助函数:
- 在对应视图模块(通用权限逻辑可以放到全局Helper模块,帖子相关逻辑可以放到
PostView)编写带模式匹配的判断函数:
defmodule MyAppWeb.PostView do use MyAppWeb, :view # 未登录用户直接返回无权限 def can_modify_post?(nil, _post), do: false # 登录用户比对ID判断是否为帖子作者 def can_modify_post?(user, post), do: user.id == post.user_id end
- 模板中直接调用该函数即可,代码更简洁,后续扩展(比如增加管理员可编辑的权限规则)时只需要修改辅助函数,不需要逐个调整模板:
<%= if can_modify_post?(@current_user, @post) do %> <span> <%= link "Edit", to: Routes.post_path(@conn, :edit, @post) %> </span> <span> <%= link "Delete", to: Routes.post_path(@conn, :delete, @post), method: :delete, data: [confirm: "Are you sure"] %> </span> <% end %>
注意:模板层的按钮隐藏只是前端交互层面的体验优化,必须在控制器层的edit、update、delete动作中加同样的权限校验,避免用户直接构造请求绕过前端限制触发越权操作。
内容的提问来源于stack exchange,提问作者Aleksandr
相关产品推荐
相关产品推荐

