Jean-Théo
Jean-Théo

Reputation: 442

Prevent view to access models

To enforce separation of concerns and prevent dirty hacks in the views of a big project, I would like to inject the data in the views (through the controller for instance), and that the view would then not be able to access models, or any class of the project (only the data structure that has been injected).

With Rails, how can we prevent the embedded Ruby code in the views to access other parts of the project?

Upvotes: 0

Views: 138

Answers (1)

jvillian
jvillian

Reputation: 20263

Ok. Here's the nut of it. (This is incomplete code and is meant to indicate direction, I've removed a lot, so you'll have to fill in the blanks.)

First, I create a module called ActsAs::Rendering. This provides an instance of ActionView::Base, which is the key to rendering anywhere.

module ActsAs::Rendering
  private

    def action_view() @action_view ||= new_action_view end

    def new_action_view
      av = ActionView::Base.new
      av.view_paths = ActionController::Base.view_paths
      av.class_eval do
        include Rails.application.routes.url_helpers
        include ApplicationHelper
      end
      av
    end

    def method_missing(meth, *params, &block)
      if action_view.respond_to?(meth)
        action_view.send(meth, *params, &block)
      else
        super
      end
    end

    def render_partial(file_ref)
      render(partial: "#{file_ref}", locals: {presenter: self})
    end
end

Then, I create a PresenterBase that includes ActsAs::Rendering:

def PresenterBase
  include ActsAs::Rendering 

  class << self

    def present(args={})
      new(args).present
    end

  end # Class Methods

  #==============================================================================================
  # Instance Methods
  #==============================================================================================

    def initialize(args)
      @args = args
    end

  private

end

And now I create a Presenter class that implements present.

def FooPresenter < PresenterBase 

  #==============================================================================================
  # Instance Methods
  #==============================================================================================

    def present
      render_partial 'path/to/foo/partial'
      # or do a lot of other cool stuff.
    end

end

And my views all begin with:

- @presenter = local_assigns[:presenter] if local_assigns[:presenter]

And now, the view no longer has access to anything except its presenter.

* NOTE *

There's a bit more, but I have to run out. I'll update later.

Upvotes: 1

Related Questions