如何在router.ex文件中使用Repo功能?

时间:2018-01-23 02:10:57

标签: elixir phoenix-framework

所以我在Phoenix 1.3 router.ex文件中做了一些元编程魔术。

我需要使用Demo.Repo从数据库中获取一些数据,而我却神奇地组装了一些路线。我如何在router.ex中使用它?

当我运行mix phx.routes时,出现错误:

repo Demo.Repo is not started, please ensure it is part of your supervision tree

我是否需要以某种方式编辑application.ex文件以在不同的监督树中启动它?

以下是我所拥有的:

router.ex文件

defmodule DemoWeb.Router do

  use Utils

 # other routes not included
   car_resources("/cars", CarController, 1)
end

Utils模块

defmodule Utils do
  @moduledoc """
  Helper functions for autogenerating routes
  """
  alias Demo.Repo
  alias CarType

  defmacro __using__(_options) do
    # quote gets the representation of any expression
    quote do
      import unquote(__MODULE__) # import __MODULE__ into the user's code
      @before_compile unquote(__MODULE__)
    end
  end

  defmacro car_resources(path, controller, level) do
    quote do
      resources unquote(base_path(path, level), unquote(controller)
    end
  end

  def base_path(path, level) do
     # do stuff
  end

  def cars do
    %{
      1 => Repo.get_by!(CarType, name: "ford"),
      2 => Repo.get_by!(CarType, name: "honda"),
    }
  end
end

2 个答案:

答案 0 :(得分:2)

Ecto.RepoGenServer in a nutshell,因此人们可能会使用明确的开始/停止生命周期:

def cars do
  with {:ok, pid} <- Demo.Repo.start_link() do
    cars = %{
      1 => Repo.get_by!(CarType, name: "ford"),
      2 => Repo.get_by!(CarType, name: "honda"),
    }
    Demo.Repo.stop(pid)
    cars
  else
    error -> IO.inspect(error, label: "unable to connect")
  end 
end

虽然这可能有用,但我强烈建议使用一些文本文件(或任何其他独立源)而不是数据库。首先,在每次后续运行中重新创建测试数据库,并且在测试会话期间您可能最终会得到空路径文件。另外,从同一配置配置的东西读取配置就像鸡蛋问题一样。

答案 1 :(得分:1)

这种方法不起作用,因为在编译期间依赖于数据库。因此,为了定义路由,您需要编译CarType,然后通过调用start_link来启动存储库。

虽然Elixir足够聪明,可以将这些依赖关系排除在外,但它显示出一种危险的耦合程度。例如,如果添加新的CarType,则需要重新编译代码。由于在数据库中添加了新类型的汽车,因此部署新代码感觉很尴尬。

相反,我会按:car_type嵌套路线并始终动态获取车型:

scope "/cars/:car_type" do
  resources "/cars", CarController
end

然后你在插件中获取:car_type并将其存储在连接中。