Phoenix - 具有多个渲染的控制器

Ker*_*ael 29 elixir phoenix-framework

尝试使用Elixir + Phoenix创建一个应用程序,它将能够处理"浏览器"和"api"请求以处理其资源.

是否可以这样做而不必做那样的事情:

scope "/", App do
  pipe_through :browser

  resources "/users", UserController
end

scope "/api", App.API as: :api do
  pipe_through :api

  resources "/users", UserController
end
Run Code Online (Sandbox Code Playgroud)

这意味着必须创建两个控制器,这些控制器可能具有相同的行为,除了它将使用浏览器管道呈现HTML ,例如JSON,用于api管道.

我想的可能就是Rails respond_to do |format| ...

Chr*_*ord 30

正如Gazler所说,通过使用单独的管道可能是最好的服务,但是在相同的控制器操作上使用模式匹配可以很愉快地完成这样的事情:

def show(conn, %{"format" => "html"} = params) do
  # ...
end

def show(conn, %{"format" => "json"} = params) do
  # ...
end
Run Code Online (Sandbox Code Playgroud)

或者,如果函数体是相同的,并且您只想基于接受头呈现模板,则可以执行以下操作:

def show(conn, params) do
  # ...

  render conn, :show
end
Run Code Online (Sandbox Code Playgroud)

传递一个原子作为模板名称将导致phoenix检查接受头并呈现.json.html模板.

  • 它看起来不像传入`params`中有`format`吗?自从这个答案以来有什么变化? (2认同)

Gaz*_*ler 22

我不推荐它(我建议有两个控制器并将你的逻辑移动到两个控制器调用的不同模块),但它可以完成.您可以共享控制器,但仍需要单独的管道以确保设置正确的响应类型(html/json).

以下将使用相同的控制器和视图,但根据路径渲染json或html."/"是html,"/ api"是json.

路由器:

defmodule ScopeExample.Router do
  use ScopeExample.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", ScopeExample do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  scope "/api", ScopeExample do
    pipe_through :api # Use the default browser stack

    get "/", PageController, :index
  end
end
Run Code Online (Sandbox Code Playgroud)

控制器:

defmodule ScopeExample.PageController do
  use ScopeExample.Web, :controller

  plug :action

  def index(conn, params) do
    render conn, :index
  end
end
Run Code Online (Sandbox Code Playgroud)

视图:

defmodule ScopeExample.PageView do
  use ScopeExample.Web, :view

  def render("index.json", _opts) do
    %{foo: "bar"}
  end
end
Run Code Online (Sandbox Code Playgroud)

如果您使用如下路由器,您也可以共享路由器并使用相同路由服务的所有内容:

defmodule ScopeExample.Router do
  use ScopeExample.Web, :router

  pipeline :browser do
    plug :accepts, ["html", "json"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
  end


  scope "/", ScopeExample do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以?format=json在网址末尾指定格式- 但我建议您使用不同的网址为您的API和网站.