Reputation: 442
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
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