Sheharyar
Sheharyar

Reputation: 75820

Rails' before_filter equivalent in Phoenix

I've just started working on my first Phoenix app, and the issue is that I have some common lines of code in every action in my controller, that I would like to separate out. They fetch data from multiple Ecto Models and save them to variables for use.

In Rails, I could simply define a method and call it using before_filter in my controller. I could access the result from an @variable. I understand that using Plugs is the key but I'm unclear on how to achieve this, more specifically:


As a reference, this is the rails version of what i'm trying to do:

class ClassController < ApplicationController
    before_filter :load_my_models

    def action_one
        # Do something with @class, @students, @subject and @topics
    end

    def action_two
        # Do something with @class, @students, @subject and @topics
    end

    def action_three
        # Do something with @class, @students, @subject and @topics
    end

    def load_my_models
        @class    = Class.find    params[:class_id]
        @subject  = Subject.find  params[:subject_id]

        @students = @class.students
        @topics   = @subject.topics
    end
end

Thanks!

Upvotes: 17

Views: 3479

Answers (2)

Paweł Obrok
Paweł Obrok

Reputation: 23184

You can indeed achieve this with a Plug and Plug.Conn.assign.

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

  plug :store_something
  # This line is only needed in old phoenix, if your controller doesn't
  # have it already, don't add it.
  plug :action

  def index(conn, _params) do
    IO.inspect(conn.assigns[:something]) # => :some_data
    render conn, "index.html"
  end

  defp store_something(conn, _params) do
    assign(conn, :something, :some_data)
  end
end

Remember to add the plug declaration before your action plug, as they are executed in-order.

Upvotes: 25

Foggy
Foggy

Reputation: 66

This is better as a comment but I lack the rep; with the current version of Phoenix (1.3.4, August of 2018), if you use the top answer's code, you would only want to do plug :store_something: do not use plug :action as it is redundant. The actions will run after the plugs which you listed.

If you include plug :action you will get (Plug.Conn.AlreadySentError) the response was already sent as the action will run twice and Phoenix will be mad at you.

Upvotes: 3

Related Questions