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!
Related
I'm trying to automatically generate a list of links to pages that have certain frontmatter in them, but every time I try to use sitemap.where(), I get a NoMethodError. For example, the following line:
<%= sitemap.where(:title=>"about") %>
produces this output:
NoMethodError at /
undefined method `where' for #<Middleman::Sitemap::Store:0x007f9b95c7d890>
Ruby layouts/layout.erb: in block in singleton class, line 20
Web GET localhost/
I was wondering if I accidentally messed something up in my project, so I generated a new Middleman project, but I had the same problem when I tried to use sitemap.where. Is there a solution to this or another way that I can query all of the pages?
The where method is part of ActiveRecord and might not work in Middleman.
To get only those pages in the sitemap which have a particular property, you can use Ruby's select:
<% sitemap.resources.select{|p| p.data.title == 'about'}.each do |page| %>
<%= page.url %>
<% end %>
This code will print a (very basic) list of the URLs of pages that match your criteria.
I have a problem with the normal way rails operates when using nested forms / resources and routing.
I have two tables, Words and Definitions...
Words have many definitions, but I do not create a Word until it has at least one definition.
Everything on the model and controller end works but I cannot figure out how to handle the form helpers.
<%= semantic_form_for [#word, #definition] do |f| %>
This works perfectly but only if #word actually exists and is not a new UNSAVED record. IE in the controller I am doing a find_or_initialize_by call for Word then building a definition off of that.
<%= semantic_form_for [:word, #definition] do |f| %>
This words but only if the word doesn't exist. IE if I try to edit using this construction I get an odd url (which doesn't work). words/12345/definition/12345
I tried using the url_for helper but had similar results as above...
Any other ideas?
Mongoid doesn't initialize embedded documents by default. You need to build them yourself most likely with a callback in your Word model:
after_initialize :build_definition
def build_definition
self.definitions.build unless self.definitions.any?
end
If you wanna stay CRUD and allow definitions to be created before words, you must duplicate routes for definitions, one inside words and one outside, so you can do:
<%= semantic_form_for [#definition] do |f| %>
Using Carrierwave 0.5.4 on Rails 3.1 RC4.
In Rails console, I do:
#foo.attachment
returns:
=> http://cdn.site_name.com/uploads/users/2/banners/banner.png
However:
#foo.remove_attachment!
returns:
=> [:remove_versions!]
The record still remains in the DB, BUT the file is removed in the S3 bucket.
What is going on?
Ahhh, after further investigating. This is what I have found out. remove_attachment! is meant to remove the image from S3, but is not meant to remove the uploader object in the attachment column, in the db. This is the normal behavior of Carrierwave.
Jnicklas provided a test spect at https://github.com/jnicklas/carrierwave/commit/ecabc618d0fce22c1931c6d2eb134886e3b60e4c which uses #doc.remove_image = true. This is the key, because when one submits a form to remove an attachment / image / photo / whatever. They normally include a check box that looks like:
<input type="checkbox" value="1" name="user[remove_attachment]" id="user_remove_attachment">
Which can be rendered with the helper tag as:
<%= f.check_box :remove_attachment %>
If the check box is clicked and the form is submitted. Params will look something like:
{"utf8"=>"✓", "_method"=>"put", ....., "user"=>{"remove_attachment"=>"1"}, "controller"=>"das....}
Rails will interpret this as #user.remove_attachment = true to clear the db column and also trigger .remove_attachment! to remove the file from S3.
Also worth noting. If attr_accessible is defined in the User model. Then it must have :attachment, :remove_attachment as well.
Hope this helps someone out.
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
I have a description text field in my Model.
No I want to add this description on the show page.
But the text renders ugly because of no linebreaks.
If i replace them with <br/> then the rails escape them with.
So i tried to use the raw() method.
I want to escape bad HTML but have the linebreaks in my output.
I end up with some ugly code.
raw(h(#place.description.gsub("\n","#linebreak#")).gsub("#linebreak#","<br/>"))
Do you have any suggestions?
you should use the simple_format helper:
<%= simple_format #place.description %>
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-simple_format
3 years later, but it's never too late to provide a good working solution
This will escape all HTML chars but the newlines (compatible Linux, Windows and Mac)
html_escape(#place.description).gsub(/(?:\n\r?|\r\n?)/, '<br />').html_safe
is what you are looking for
#place.description.html_safe.gsub("\n", '<br/>')
? But on second thought, doesn't the html_safe usage like that make it easy for the site to get XSS attack? (because it assumes the description is safe).
So won't a better solution be
<%= (h #place.description).gsub("\n", '<br/>') %>
at first I thought
<%= (h #place.description).gsub("\n", '<br/>'.html_safe) %>
is needed but actually both versions work. I then tested by adding some HTML tags to description and it got escaped into < etc, so it does prevent XSS attack.
Here's a solution that works:
<%= sanitize(#place.description.gsub("\n", "<br />"), :tags => %w(br), :attributes => %w()) %>
More reading:
Parsing newline characters in textareas without allowing all html tags
Documentation:
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
From sanitize:
This sanitize helper will html encode all tags and strip all attributes that aren’t specifically allowed.
It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out the extensive test suite.
You can specify allowed tags with :tags option, and attributes with :attributes option.