Daniel Doubrovkine bio photo

Daniel Doubrovkine

aka dB., CTO at artsy.net, fun at playplay.io, NYC

Email Twitter LinkedIn Github

There’s got to be a prettier way of implementing this.

We use the following code to render API documentation, which is written in Markdown.

Add a route that will capture the document filename in config/routes.rb. Bonus features: a namespaced controller and a redirect to /api/v1/docs for /api/v1.

scope 'api', :module => 'api' do
  match '/:version' => redirect('/api/%{version}/docs')
  match '/:version/docs/(/:page)' => "docs#show"
end

Create a controllers/api/docs_controller.rb.

class Api::DocsController < ApplicationController

  # GET /api/docs/:version/:page
  def show
    @version = params[:version]
    @page = (params[:page] || "index").downcase.gsub(/[^a-z0-9]/, '') # strip any non-alpha-numeric characters
    filename = File.join(Rails.root, 'public/api/' + @version + "/docs/" + @page + '.md')
    begin
      file = File.open(filename, "rb")
      @markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true)
      render :text => @markdown.render(file.read), :layout => true
    rescue Errno::ENOENT
      render :file => "public/404.html", :status => 404
    end
  end

end

You can now create public/api/v1/docs/something.md and it will render under api/v1/docs/something.

What I’d like to do is take the Markdown renderer out of this controller, define it as a generic handler, and swap the template being rendered to the filename instead. How do I do that?