2016-12-20 4 views
1

を置くために私は、コントローラで再利用したい共有コントローラ機能を持っている:どこに共有コントローラコード

def render_unprocessable_entity(conn, changeset) do 
    conn 
    |> put_status(:unprocessable_entity) 
    |> render(ExampleApp.ChangesetView, "error.json", changeset: changeset) 
    end 

質問:私はこれを置くことができますか?私はコントローラ/ヘルパー/ controller_helper.exに入れようとしましたが、それはundefined function put_status/2と書かれています。私はちょうどそれが既存のコントローラと競合するので、このヘルパーにuse ExampleApp.Web, :controllerを追加することはできません。私はそれを通常のモジュールとして使用してエイリアスを使用することができましたが、これはどこでもControllerHelperの型指定です。

私はおそらくweb.exに入れることができますか?しかし、私はそのファイルを大きすぎないようにすべきでしょうか?

コードをDRYするにはどうすればよいですか?

答えて

1

使用Kernel.SpecialForms.import/2明示的な名前空間なしに(この特定の場合において、ヘルパーから)所望のモジュールからエクスポートされたすべての(パブリック)の機能をインポートする:

controller_helper.ex(又は他のモジュール)

defmodule My.ControllerHelper do 
    def put_status(param), do: IO.puts(param) # whatever 
end 

my_controller.ex(又は他のモジュール)

import My.ControllerHelper # ⇐ HERE !!! 

defmodule My.Controller do 
    use Waveia.Web, :controller 

    def render_unprocessable_entity(conn, changeset) do 
    conn 
    |> put_status(:unprocessable_entity) # ⇐ HERE !!! 
    |> render(...) 
    end 
    ... 
end 

あなたはそれを使用しているすべてのものをに単一のモジュールからアクセスできるようにしたいかどうか、あなたはuse Helperを呼び出しているモジュールをインポートする__using__/2コールバックを上書きしてしまうことがあります。

この例は次のようになります。

defmodule ExampleApp.ControllerHelper do 
    defmacro __using__(opts) do 
    quote do 
     defp render_unprocessable_entity(conn, changeset) do 
     conn 
     |> put_status(:unprocessable_entity) 
     |> render(ExampleApp.ChangesetView, "error.json", changeset: changeset) 
     end 
    end 
    end 
end 
+0

申し訳ありませんが、私は十分にはっきりしませんでした。しかし、私は自分のコントローラーでその機能を使いたかったのですが、それを別のモジュールに入れて他のモジュールでインポート/使用できるようにしました。私はelixir内でルビモジュールのようなものを探していました。そこではヘルパーモジュールはモジュールを含むどのクラスにも定義されている既存のすべての関数にアクセスできます。例えば、 'has_many'や' attribute'メソッドもこれらのモジュールで使うことができます。 – randomor

+1

単一のモジュールからそれを使用するすべてのモジュールにアクセスしたい場合は、['__using__'](http://elixir-lang.org/docs/stable/elixir/Kernel.html#use/2 )コールバックを呼び出すと、 'use Helper'を呼び出します。 – mudasobwa

+0

ビンゴ!私はそれが私が必要としていたものだと思う。 ExampleApp.ChangesetView(>レンダリング| :|私は '' 'defmodule ExampleApp.ControllerHelper DO のdefmacro __using __(OPTS)を使用して終了 引用は defpのrender_unprocessable_entity(CONN、チェンジ)を行うのですか CONN を行う> put_status(unprocessable_entity) 、 "error.json"、changeset:changeset) end end end end ''私はあなたの答えを受け入れる前にこれをあなたの答えに追加しますか? – randomor

1

これらの関数(put_status/2render/3)は、あなたが行うことができますuse Waveia.Web, :controller

を行う際に輸入されている他のモジュールに存在する:

def render_unprocessable_entity(conn, changeset) do 
    conn 
    |> Plug.Conn.put_status(:unprocessable_entity) 
    |> Phoenix.Controller.render(ExampleApp.ChangesetView, "error.json", changeset: changeset) 
end 

これをモジュールで定義するとimportモジュール内にcontroller関数web.exでは、関数をモジュールにインポートするときはいつでも、モジュールが定義されている場所を隠すことに注意してください。これは、コードベースで作業している他の人が、関数の定義場所を見つけるためにコードをいくつか調べなければならないかもしれないことを意味します。代わりに、私はやってお勧めします:render_unprocessable_entity/2関数はどこから来るのコントローラコードを表示する

import MyModule, only: [render_unprocessable_entity: 2] 

この方法で誰かが正確に確認することができます。

+0

ありがとうございました!それはうまくいった!ちょうど奇妙なことですが、 'put_status'モジュールを明示的に指定する必要があります。これは、' use Phoenix.Controller'で隠されたディテールです。ルビーから来て、コードが私のコントローラーに/からコピーできるかのようにコードを書く方法があるのだろうかと思います。 – randomor

関連する問題