Jacob
Jacob

Reputation: 23225

How can I automatically render partials using markdown in Rails 3?

I want to have some of my partials as markdown snippets. What is the easiest way to render them using the standard rails erb templating?

Ideally, I'd like to do something like this:

If I have a partial in app/views/_my_partial.md.erb:

My awesome view
===============

Look, I can **use** <%= language %>!

which I reference from a view like so:

<%= render "my_partial", :language => "Markdown!" %>

I want to get output that looks like this:

<h1>My awesome view</h1>
<p>Look, I can <strong>use</strong> Markdown!</p>

Upvotes: 41

Views: 12457

Answers (9)

akb
akb

Reputation: 21

Rails 7.1 update requires an extra ".to_s" to satisfy OutputBuffer:

"RDiscount.new(begin;#{ compiled_source };end).to_html"

changes to

"RDiscount.new(begin;#{ compiled_source }.to_s;end).to_html"

# frozen_string_literal: true

require 'rdiscount'

module MarkdownHandler
  def self.erb
    @erb ||= ActionView::Template.registered_template_handler(:erb)
  end

  def self.call(template, source)
    compiled_source = erb.call(template, source)
    "RDiscount.new(begin;#{ compiled_source }.to_s;end).to_html"
  end
end

ActionView::Template.register_template_handler :md, MarkdownHandler

Upvotes: 0

ytbryan
ytbryan

Reputation: 2694

You can use embedded Markdown in Rails 5. Embedded Markdown is based on the solution provided by Jacob above

  1. Add these to your application's Gemfile:
    gem 'coderay' #optional for Syntax Highlighting
    gem 'redcarpet'
    gem 'emd'
  1. bundle install.

  2. Then create a view app/view/home/changelog.html.md and paste your markdown in that .md file.

  3. Generate a home controller using the following command

    rails generate controller home

  4. Add the following line to your route.rb:

    get '/changelog', :to 'home#changelog'

  5. That's all. Visit http://localhost:3000/changelog to see your rendered markdown

Source: http://github.com/ytbryan/emd

Upvotes: 0

wpp
wpp

Reputation: 7313

Here is a version similar to @Jacob's but using Redcarpet.

module MarkdownHandler
  def self.erb
    @erb ||= ActionView::Template.registered_template_handler(:erb)
  end

  def self.call(template)
    options = {
      fenced_code_blocks:           true,
      smartypants:                  true,
      disable_indented_code_blocks: true,
      prettify:                     true,
      tables:                       true,
      with_toc_data:                true,
      no_intra_emphasis:            true
    }
    @markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
    "#{@markdown.render(template.source).inspect}.html_safe"
  end
end
ActionView::Template.register_template_handler :md, MarkdownHandler

Full credit to lencioni who posted this in this gist.

And if you'd like to evaluate erb:

erb = ERB.new(template.source).result
@markdown ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
"#{@markdown.render(erb).inspect}.html_safe"

Upvotes: 2

tjwallace
tjwallace

Reputation: 5688

Not a pure markdown solution but you can use HAML filters to render markdown, as well as other markup languages.

For example, in app/views/_my_partial.html.haml:

:markdown
  My awesome view
  ===============

  Look, I can **use** #{language}!

Upvotes: 21

Aidan Feldman
Aidan Feldman

Reputation: 5457

Leveraged your answer to make a gem to render for GitHub Flavored Markdown in Rails (via HTML::Pipeline): https://github.com/afeld/html_pipeline_rails

Upvotes: 2

Jacob
Jacob

Reputation: 23225

Turns out, the Right Way (tm) to do this is using ActionView::Template.register_template_handler:

lib/markdown_handler.rb:

require 'rdiscount'

module MarkdownHandler
  def self.erb
    @erb ||= ActionView::Template.registered_template_handler(:erb)
  end

  def self.call(template)
    compiled_source = erb.call(template)
    "RDiscount.new(begin;#{compiled_source};end).to_html"
  end
end

ActionView::Template.register_template_handler :md, MarkdownHandler

If you require 'markdown_handler' in your config/application.rb (or an initializer), then any view or partial can be rendered as Markdown with ERb interpolation using the extension .html.md:

app/views/home/index.html.md:

My awesome view
===============

Look, I can **use** <%= @language %>!

app/controllers/home_controller.rb:

class HomeController < ApplicationController
  def index
    @language = "Markdown"
  end
end

Upvotes: 86

Paul Fioravanti
Paul Fioravanti

Reputation: 16793

Piling on the solutions already presented, this is an interpolation-ary way in Rails 3 to render a pure Markdown file in a view from a partial without unnecessary indentation using Haml's :markdown filter and the RDiscount gem. The only catch is that your Markdown file is a Haml file, but that shouldn't matter for someone like a copy person.

In Gemfile:

gem 'rdiscount'

In app/views/my_page.html.haml

:markdown
  #{render 'my_partial', language: 'Markdown!'}

In app/views/_my_partial.html.haml

My awesome view
===============

Look, I can **use** #{language}!

If you didn't need the :language variable passed in to the markdown file, you could do away altogether with your Markdown being a Haml file:

In app/views/my_page.html.haml

:markdown
  #{render 'my_partial.md'}

In app/views/_my_partial.md

My awesome view
===============

Sorry, cannot **use** #{language} here!

Don't like those pesky underscores on your Markdown files?

In app/views/my_page.html.haml

:markdown
  #{render file: 'my_markdown.md'}

In app/views/my_markdown.md

My awesome view
===============

Sorry, cannot **use** #{language} here!

Upvotes: 4

Jo Liss
Jo Liss

Reputation: 33094

I just released a markdown-rails gem, which handles .html.md views.

You cannot chain it with Erb though -- it's only for static views and partials. To embed Ruby code, you'd have to use tjwallace's solution with :markdown.

Upvotes: 4

Roman Golomidov
Roman Golomidov

Reputation: 191

Have found way not to use haml in such situation.

in views/layouts/_markdown.html.erb

<%= m yield %>

in app/helpers/application_helper.rb

def m(string)
   RDiscount.new(string).to_html.html_safe
end  

in Gemfile

gem 'rdiscount'

So, in view you can call it like:

<%= render :partial => "contract.markdown", :layout => 'layouts/markdown.html.erb' %>

And contract.markdown will be formatted as markdown

Upvotes: 4

Related Questions