davideghz davideghz - 1 year ago 141
Ruby Question

Rails content_tag method

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))

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.

Answer Source

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



class FooPresenter
  class << self

    def present(controller)

  end # class methods

  # instance methods

    def initialize(controller)
      @controller = controller

    def present
      content_tag :div, data: {foo: params[:foo]}, class: 'bar'


    def controller()  @controller                end
    def view()        controller.view_context    end
    def params()      controller.params          end

    def method_missing(*args, &block)
      view.send(*args, &block)


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.