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>
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
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}!
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
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.
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!
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
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"
You can use embedded Markdown in Rails 5. Embedded Markdown is based on the solution provided by Jacob above
Add these to your application's Gemfile:
gem 'coderay' #optional for Syntax Highlighting
gem 'redcarpet'
gem 'emd'
bundle install.
Then create a view app/view/home/changelog.html.md and paste your markdown in that .md file.
Generate a home controller using the following command
rails generate controller home
Add the following line to your route.rb:
get '/changelog', :to 'home#changelog'
That's all. Visit http://localhost:3000/changelog to see your rendered markdown
Source: http://github.com/ytbryan/emd
Related
I want to store pages in the database that are dynamically added/edited/etc. Along with the page title and content I also supply which layout to use and a controller name and view name in order to support the instantiation of models which the view (e.g. text field in the pages table) will use.
I'm having trouble rendering the text from the database and having the layout still be used.
class AboutController < BaseController
def index
#model_data = ...
render_dynamic_page("about", "index")
end
end
class BaseController < ApplicationController
layout "public"
def render_dynamic_page(controller_name, action_name)
page = Page.where("`controller_name` = :controller_name AND `action_name` = :action_name", { :controller_name => controller_name, :action_name => action_name }).first
render :layout => page.layout_name, :text => page.content
end
end
I'm using :text here and I've also tried :inline but both seem to not render the content within the layout.
How can I accomplish this?
Normally if you want to allow users to edit the html pages in a rails application, and store the pages in a DB, the standard way is to use the template language called liquid.
It allows you to define dynamic content, ideal for CMS systems in rails, I think its better you have a look first.
following are some important links
liquid home page
rails cast about liquid
git hub page
and there are lots of resources in SO itself. :)
I was so close - I just had to switch the order of the parameters to the render method:
render :inline => page.content, :layout => (page.layout_name || "public")
I also added a default layout to use public in case a page.layout_name was not specified in the database. The other thing that's worth mentioning is the difference between :text and :inline - only :inline seems to actually "process" the content as if it were an ERB whereas the :text option just literally outputs the raw text.
Note : I ended up creating an ERB for each page using ERB.new(page.content), caching the list of dynamic ERBs and then pulling the pre-rendered ERB from the cache and displaying it using:
render :inline => the_cached_erb.result(binding), :layout => (page.layout_name || "public")
There is still some weird behavior going on but I think it will work in the end.
Just FYI and for greater tools variety you may want to check out Mercury editor:
http://jejacks0n.github.io/mercury/
https://github.com/jejacks0n/mercury
http://railscasts.com/episodes/296-mercury-editor
In my Rails 3.1 app, I have a text field for comments and I want to be able to allow people to include clickable links (instead of just the url showing as plain text), as well as having the text field recognize when a user had line breaks in their text field (without the user adding html). How can I do this?
This works for showing a link if a user puts the html for a href:
<%= simple_format(#user.description) %>
And this works for recognizing and displaying the line breaks from carriage returns in the text_field:
<%= h(#user.description).gsub(/\n/, '<br/>').html_safe %>
However, I haven't figured out how to do both, together.
How about this?
#Doesnt work in this case
#<%= simple_format( h(#user.description).gsub(/\n/, '<br/>') ).html_safe %>
EDIT:
Seems like you need auto_link function to achieve this. Though it is removed from rails 3.1 it is available as a gem. So if you are using rails 3.1 or later you need to get this from a separate gem
#in Gemfile
gem "rails_autolink", "~> 1.0.9"
#in application.rb
require 'rails_autolink'
#Run
bundle install
#now in you view use it like
<%= h auto_link(simple_format(text)) %>
auto_link not only converts urls but also email addresses in clickable link. Get the document here.
Reference Links:
http://rubygems.org/gems/rails_autolink
http://apidock.com/rails/ActionView/Helpers/TextHelper/auto_link
Use the Rinku Gem
Link is here.
It brilliantly solves the problem. Enjoy!
i am using wicked_pdf and generating pdf of users records.image tag is not working when pdf is generate.So i use this trick and write this code in application helper.
def pdf_image_tag(image, options = {})
options[:src] = File.expand_path(Rails.root) + '/public' + image
tag(:img, options)
end
and in my view i call like this
<%= pdf_image_tag(#image.snap.url(:thumb)) unless #image.blank? %>
This is working fine for chrome and display image perfectly but not for other browsers.
Can any one give better suggestion.
Thanks....
Use the built-in helper wicked_pdf_image_tag
<%= wicked_pdf_image_tag(#image.snap.url(:thumb)) unless #image.blank? %>
I'm running Rails 3.1.1, RSpec 2.7.0 and HAML 3.1.3.
Say I have the following view files:
app/views/layouts/application.html.haml
!!!
%html
%head
%title Test
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
%body
= content_for?(:content) ? yield(:content) : yield
app/views/layouts/companies.html.haml
- content_for :content do
#main
= yield :main
#sidebar
= yield :sidebar
= render :template => 'layouts/application'
app/views/companies/index.html.haml
- content_for :main do
%h1 MainHeader
- content_for :sidebar do
%h1 SidebarHeader
And the following spec file:
spec/views/companies/index_spec.rb
require 'spec_helper'
describe 'companies/index.html.haml' do
it 'should show the headers' do
render
rendered.should contain('MainHeader')
rendered.should contain('SidebarHeader')
end
end
When I run RSpec, I get the following error:
1) companies/index.html.haml should show the headers
Failure/Error: rendered.should contain('MainHeader')
expected the following element's content to include "MainHeader":
# ./spec/views/companies/index_spec.rb:7:in `block (2 levels) in <top (required)>'
At first, I thought RSpec was somehow missing the content_for blocks when rendering the view files. However, I was not able to find any issue related to it on RSpec's github repository, so I'm not sure who's to blame here.
One (recent) solution I found is at http://www.dixis.com/?p=571. However, when I try the suggested code
view.instance_variable_get(:#_content_for)
it returns nil.
Is there a way to test content_for in view specs?
Is there a better way to structure my layout files, such that I'm actually able to test them and still achieve the same end result?
Using Rspec 2 with Rails 3, in order to write view specs for usage of content_for, do this:
view.content_for(:main).should contain('MainHeader')
# instead of contain() I'd recommend using have_tag (webrat)
# or have_selector (capybara)
p.s. the value of a content_for(...) block by default is an empty string, so if you want to
write specs showing cases in which content_for(:main) does not get called, use:
view.content_for(:main).should be_blank
Your spec could be written as:
it "should show the headers" do
render
view.content_for(:main).should contain('MainHeader')
view.content_for(:side_header).should contain('SidebarHeader')
end
This way your spec shows exactly what your view does, independent of any layout. For a view spec, I think it's appropriate to test it in isolation. Is it always useful to write view specs? That's an open question.
Instead if you want to write specs showing what the markup served to the user looks like, then you'll want either a request spec or a cucumber feature. A third option would be a controller spec that includes views.
p.s. if you needed to spec a view that outputs some markup directly and delegates other markup to content_for(), you could do that this way:
it "should output 'foo' directly, not as a content_for(:other) block" do
render
rendered.should contain('foo')
view.content_for(:other).should_not contain('foo')
end
it "should pass 'bar' to content_for(:other), and not output 'bar' directly" do
render
rendered.should_not contain('bar')
view.content_for(:other).should contain('bar')
end
That would probably be redundant, but I just wanted to show how render() populates rendered and view.content_for. "rendered" contains whatever output the view produces directly. "view.content_for()" looks up whatever content the view delegated via content_for().
From the RSpec docs:
To provide a layout for the render, you'll need to specify both the template and the layout explicitly.
I updated the spec and it passed:
require 'spec_helper'
describe 'companies/index.html.haml' do
it 'should show the headers' do
render :template => 'companies/index', :layout => 'layouts/companies'
rendered.should contain('MainHeader')
rendered.should contain('SidebarHeader')
end
end
Do not bother with view specs. They're hard to write well, and they don't test enough of the stack to be worth using (especially in view of the difficulty writing). Instead, use Cucumber, and test your views in the course of that.
You generally don't want to test content_for specifically either: that's implementation, and you should instead be testing behavior. So just write your Cucumber stories so they test for the desired content.
If for some odd reason you do need to test content_for, RSpec has a syntax that's something like body[:content_name] or body.capture :content_name depending on the version (or something like that; haven't used it in a while). But consider carefully whether there's a better way to test what you actually want to test.
I would like to serve client side templates that have been pre-processed through HAML. I have tried using the haml_assets gem and adding the following code to an initializer:
Rails.application.assets.register_engine ".haml", Tilt::HamlTemplate
Both of these methods serve the raw HAML and not compiled HAML when I access the asset. How can I add HAML to the pipeline?
Just to clear things up, since I find the current answers a bit irritating (led me to the right direction though)
It works, if i have this line in an initializer file:
# config/initializers/haml_assets.rb
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
Throw your haml files into the assets folder, for example:
# app/assets/templates
Do not use the haml_asset gem though!
The following code in application.rb works for me in Rails 3.2 (both in development and in production after pre-compilation):
require 'haml'
config.assets.paths << Rails.root.join("app", "assets", "templates")
class HamlTemplate < Tilt::HamlTemplate
def prepare
#options = #options.merge :format => :html5
super
end
end
config.before_initialize do |app|
require 'sprockets'
Sprockets::Engines #force autoloading
Sprockets.register_engine '.haml', HamlTemplate
end
This allows you to put you templates in app/assets/templates named with the suffix .html.haml (you need the .html in there or else .htm files get generated instead of .html in the pre-compilation process).
This works for me:
# app/assets/javascripts/test.html.haml
%p hello
# config/initializers/haml_template.rb
Rails.application.assets.register_mime_type 'text/html', '.html'
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
This works for http://127.0.0.1:3000/assets/test.html.haml
Rails.application.assets is a Sprockets::Environment.
See here for API reference:
https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/processing.rb
https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/engines.rb
Using the same approach I've got:
%tr
%th
%a.action.link.show
%td
%td
returned as pure haml. But
%tr
%th
%a.action.link.show
%td cell 2
%td cell 3
was served as html chunk. So I think this is something with haml gem. You can force haml conversion with something like this:
%tr
%th
%a.action.link.show
%td  
%td  
Hope it helps...
Two of the previous answers here had to be combined before we had a full solution.
The following line works in development:
# config/initializers/haml_assets.rb
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
But then fails on any precompile.
For asset-served haml to work after a precompile, we also needed these lines in application.rb:
require 'haml'
config.assets.paths << Rails.root.join("app", "assets", "templates")
class HamlTemplate < Tilt::HamlTemplate
def prepare
#options = #options.merge :format => :html5
super
end
end
config.before_initialize do |app|
require 'sprockets'
Sprockets::Engines #force autoloading
Sprockets.register_engine '.haml', HamlTemplate
end
With sprockets 3 and 4
# in /config/initializers/haml.rb
Rails.application.config.assets.configure do |env|
env.register_mime_type "text/haml", extensions: %w(.haml .html.haml)
env.register_transformer 'text/haml', Tilt::HamlTemplate.default_mime_type, Tilt::HamlTemplate
end