Reputation: 3685
I was browsing the source code of this gem and I found a use of content_tag that confuses me a lot.
def render(view)
view.content_tag(name, attributes[:content], attributes.except(:content))
end
I do not understand why content_tag is called on view. I generally use it as helper to generate HTML tags, but I've never called it as a method.
Upvotes: 0
Views: 3868
Reputation: 20263
Most commonly, content_tag
is called in the context of a view - so, you don't need to call view.content_tag
because the view knows how to respond to content_tag
(and simply calling content_tag
is the same as calling self.content_tag
).
The render
method that you're showing exists within the class MetaTag
which inherits from Tag
. Tag
is a plain old Ruby object (PORO), so it doesn't know how to respond to content_tag
.
But, as you can see, the render
method takes a view as an argument. And, naturally, the view
object knows how to respond to content_tag
. So, calling view.content_tag
is the way that MetaTag
is able to render the content tag.
This is pretty much an instance of the Presenter Pattern (different people use different terms). Ryan Bates has a good RailsCast on this here.
To your question in the comments, Rails doesn't "know" that view
is an instance of ActionView::Base
. You have the responsiblity of passing in an actual view instance. I tend to pass in the controller so that I have access to the view and params. Maybe something like this:
class FooController < ApplicationController
def foo_action
FooPresenter.present(self)
end
end
and...
class FooPresenter
class << self
def present(controller)
new(controller).present
end
end # class methods
#===================================================================
# instance methods
#===================================================================
def initialize(controller)
@controller = controller
end
def present
content_tag :div, data: {foo: params[:foo]}, class: 'bar'
end
private
def controller() @controller end
def view() controller.view_context end
def params() controller.params end
def method_missing(*args, &block)
view.send(*args, &block)
end
end
By including the method_missing
method, I no longer have to call view.content_tag
. I can just call content_tag
. FooPresenter won't find the method, so will send the call onto the view
where the method will be found and executed.
Again, Ryan does a great job explaining all of this.
Upvotes: 2
Reputation: 717
Without going into too much details, content_tag
is a method in the ActionView::Helpers::TagHelper
class. I believe this class' object is either automatically included in Rails views or the Rails view object delegates to this object.
This particular gem takes an ActionView::Base
object as a parameter for its render
method so that the method has access to content_tag
method, which is part of ActionView::Helpers::TagHelper
. This is a decent example of Dependency Injection which is a fundamental principle of object oriented programming.
Upvotes: 1