Phoenix控制器中Repo的注入位置及未找到问题排查
Repo.get_by/2 is undefined的问题 别担心,新手遇到版本适配的问题太正常了,这绝对不是你的问题!你遇到的核心原因是Phoenix 1.1和1.3之间的架构变化,尤其是Repo模块的命名方式。
问题根源
在Phoenix 1.1中,Repo是全局可用的(默认被导入到所有controller和view中),但从Phoenix 1.3开始,官方引入了Context架构,Repo模块被放在了项目的命名空间下,比如你的项目是Rumbl,那么Repo的完整模块名是Rumbl.Repo,而不是全局的Repo。
你在session_controller.ex中传入的Repo其实是未定义的,因为1.3不再全局导入这个模块了。
解决方案
方案1:直接使用完整的Repo模块名
修改session_controller.ex中的调用,把Repo替换成Rumbl.Repo:
def create(conn, %{"session" => %{"username" => user, "password" => pass}}) do case Rumbl.Auth.login_by_username_and_pass(conn, user, pass, repo: Rumbl.Repo) do {:ok, conn} -> ... {:error, _reason, conn} -> ... end end
方案2:全局导入Repo到所有Controller
如果你想保持和1.1类似的写法(不用每次写全名),可以修改web/web.ex文件,找到controller的定义部分,添加import Rumbl.Repo:
def controller do quote do use Phoenix.Controller, formats: [:html, :json], layouts: [html: RumblWeb.LayoutView] import Plug.Conn import RumblWeb.Gettext alias Rumbl.Router.Helpers, as: Routes # 添加这行 import Rumbl.Repo end end
这样所有controller都能直接使用Repo,不用写全名了。
验证auth.ex中的Repo使用
你提到auth.ex的call函数能正常使用Repo,大概率是因为那里已经正确导入了Rumbl.Repo,或者使用了完整模块名。如果后续遇到问题,也可以检查auth.ex中是否有类似alias Rumbl.Repo或者直接用Rumbl.Repo的代码。
补充说明
Phoenix 1.3的Context架构是为了更好地组织代码,把相关的业务逻辑和数据访问封装在Context中,而不是直接在controller里操作Repo。你后续跟着《Programming Phoenix》学习时,可能需要把书中1.1的代码适配到1.3的Context模式,但当前先解决Repo的问题就能继续推进登录功能啦。
内容的提问来源于stack exchange,提问作者Robin

