web-dev-qa-db-ja.com

フェニックス-複数のレンダリングを備えたコントローラー

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

これは、2つのコントローラーを作成する必要があることを意味します。これは、browserパイプラインでHTMLをレンダリングし、apiパイプラインでJSONをレンダリングすることを除いて、同じ動作をする可能性があります。

私は多分Rails respond_to do |format| ...のようなものを考えていました

30
Kernael

私はそれをお勧めしません(2つのコントローラーを用意し、両方のコントローラーによって呼び出される別のモジュールにロジックを移動することをお勧めします)が、それは可能です。コントローラーを共有することはできますが、正しい応答タイプ(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

コントローラ:

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

  plug :action

  def index(conn, params) do
    render conn, :index
  end
end

見る:

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

  def render("index.json", _opts) do
    %{foo: "bar"}
  end
end

次のようなルーターを使用する場合は、ルーターを共有して、すべてを同じルートで処理することもできます。

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

次に、URLの最後に?format=jsonを使用して形式を指定できます。ただし、APIとサイトに異なるURLを使用することをお勧めします。

23
Gazler

Gazlerが言ったように、おそらく別々のパイプラインを使用するのが最善ですが、このようなことは、同じコントローラーアクションでパターンマッチングを使用して快適に行うことができます。

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

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

または、関数本体が同じで、acceptヘッダーに基づいてテンプレートのみをレンダリングする場合は、次の操作を実行できます。

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

  render conn, :show
end

テンプレート名としてatomを渡すと、phoenixはacceptヘッダーをチェックし、.jsonまたは.htmlテンプレートをレンダリングします。

30
Chris McCord