'Rails view_context

I cannot get my head around the view_context. I am currently implementing datatable in my app, taking references from this video.

What I didn't understand is how to access the content of the view_context, that is passed to the datatable class.

  def index
    respond_to do |format|
      format.html
      format.json { render json: UsersDatatable.new(view_context) }
    end
  end

then I accessed it in my datatable class

  def initialize(view)
    @view = view
  end

I am using a gem called subscribem. I declare a Subscribem::Account and it pass around a variable current_account to every views. And in the datatable class I can access it like this

  def initialize(view)
    @view = view
    @current_account = @view.current_account
  end

but the problem is when in the controller, I add some variables like

  def index
    @date = DateTime.now #or date=DateTime.now
    respond_to do |format|
      format.html
      format.json { render json: UsersDatatable.new(view_context) }
    end
  end

I cannot grab the passed date or @date.

  def initialize(view)
    @view = view
    @current_account = @view.current_account
    @date = @view.date
  end


Solution 1:[1]

The key to understanding the view context is really to look at how a templating engine like ERB works (they all work pretty much the same on the high level).

You take a string (or buffer) and a context which is the data that you're inserting into the view as well as all the methods you could possibly want to use.

Take this trivial example:

require 'erb'

class Person
  def initialize(first_name, last_name)
     @first_name = first_name
     @last_name  = last_name
  end

  def get_binding
    binding
  end
end

template = "Hello my name is <%= @first_name %> <%= @last_name %>"
person = Person.new('John', 'Doe')
erb = ERB.new(template)
puts ERB.new(template).run(person.get_binding) # Hello my name is John Doe

Since we are running the template engine with the binding from inside the instance of Person we can access its instance variables. It essentially works the same way as the view context. This "magic" is how the instance variables of your controller are available in the view and in helpers and why beginners end up confusing them with globals.

However in other contexts such as decorators or serializers encapsulation still applies. That @date = DateTime.now is still an instance variable of the controller and if you want to access it you either need to use instance_variable_get to violate encapsulation:

def initialize(view)
  @view = view
  @current_account = @view.current_account
  @date = @view.instance_variable_get(:'@date')
end

Declare an accessor:

class UsersController
  attr_reader :date

  def index
    @date = DateTime.now #or date=DateTime.now
    respond_to do |format|
      format.html
      format.json { render json: UsersDatatable.new(view_context) }
    end
  end
end

class UsersDatatable
  def initialize(view)
    @view = view
    @current_account = @view.current_account
    @date = @view.date
  end
end

Or change the interface of your class so that it does not need to poke inside of another object.

class UsersDatatable
  def initialize(view, date: nil)
    @view = view
    @current_account = @view.current_account
    @date = date
  end
end

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 max