BBCode with Ruby on Rails, Part 1
This is a short tutorial for how to add bbcode to your Ruby on Rails app. bbcode is my favorite method for allowing users to format their posts, it is great because it is easy to implement and many users are familiar with it from the popular forum software phpbb.
What does some bbcode look like?
[b]Bold Text[/b] -> Bold Text
[u]Underline Text[/u] -> Underline Text
[color=red]Red Text[/color] -> Red Text
[url=http://www.8tasp.com]8TASP[/url] -> 8TASP
For more tag examples you can check the bbcode wikipedia entry. Now that you’re familiar with it, lets get started!
Adding bbcode to a rails app turns out to be pretty easy. First we will create a helper called bbcode_helper.rb and place that in the helpers folder. Then in your application_helper.rb add:
app/helpers/application_helper.rb
include BbcodeHelperOur bbcode_helper will be doing all the work for us. Lets add a method to it to convert some simple bbcode tags into html:
app/helpers/bbcode_helper.rb
1 2 3 4 5 6 7 | def parse_bbcode(param_string) # Simple Text Styling param_string.gsub!( /\[b\](.*?)\[\/b\]/im, '<span style="font-weight: bold;">\1</span>' ) param_string.gsub!( /\[u\](.*?)\[\/u\]/im, '<span style="text-decoration: underline;">\1</span>' ) param_string.gsub!( /\[i\](.*?)\[\/i\]/im, '<span style="font-style: italic;">\1</span>' ) return param_string end |
Now if we pass this method a string such as: ‘Green..yellow..[b]RED![/b]‘, we will get back: ‘Green..yellow..<span style=”font-weight: bold;”>RED!</span>’.
In the method we used regular expressions to search through the text and replace “[b](any content)[/b]” with “<span style=”font-weight: bold;”>(any content)</span>”, and then do the same for underline and italic bbcode tags. If you are unfamiliar with regular expressions, a good starting place to learn to use them with ruby is the pickaxe book section on them.
In our views now, we would put parse_bbcode in front of any user-generated content that may display it, ex.
1 2 3 4 | <div class='forum_post'> <div class='subject'><%=h forum_post.subject -%></div> <div class='message'><%=h forum_post.message -%></div> </div> |
Would become:
1 2 3 4 | <div class='forum_post'> <div class='subject'><%= parse_bbcode forum_post.subject -%></div> <div class='message'><%= parse_bbcode forum_post.message -%></div> </div> |
To make this a little safer for our app, we should now disable any html the user may have entered and instruct them to only use bbcode. So we will add to the top of our bbcode_helper a few methods:
app/helpers/bbcode_helper.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | def parse_text(param_string) strip_html(param_string) parse_bbcode(param_string) parse_spacing(param_string) return param_string end # escape < and > to remove any html def strip_html(param_string) param_string.gsub!('<', '<') param_string.gsub!('>', '>') return param_string end # turn new lines into <br /> to format the spacing properly def parse_spacing(param_string) param_string.gsub!( /\r\n?/, "\n" ) param_string.gsub!( /\n/, "<br />" ) return param_string end |
and now we would update our views to call parse_text instead of parse_bbcode, so that first any html the user may have had in their post is escaped. We also added a method to parse the spacing for the user, so that any new lines they enter will be replaced with <br />.
1 2 3 4 | <div class='forum_post'> <div class='subject'><%= parse_text forum_post.subject -%></div> <div class='message'><%= parse_text forum_post.message -%></div> </div> |
Everything looks pretty good now, lets add a few more bbcode tags our users may appreciate. How about adding images, urls, font size, font color and for some extra-niceness embedding youtube and google videos:
app/helpers/bbcode_helper.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | def parse_bbcode(param_string) # Simple Text Styling param_string.gsub!( /\[b\](.*?)\[\/b\]/im, '<span style="font-weight: bold;">\1</span>' ) param_string.gsub!( /\[u\](.*?)\[\/u\]/im, '<span style="text-decoration: underline;">\1</span>' ) param_string.gsub!( /\[i\](.*?)\[\/i\]/im, '<span style="font-style: italic;">\1</span>' ) # size and color param_string.gsub!( /\[size=['"]?(.*?)['"]?\](.*?)\[\/size\]/im, '<span style="font-size: \1px;">\2</span>' ) param_string.gsub!( /\[color=['"]?(.*?)['"]?\](.*?)\[\/color\]/im, '<span style="color: \1;">\2</span>' ) # images param_string.gsub!( /\[img size=['"]?(\d+)x(\d+)['"]?\](.*?)\[\/img\]/i, '<img src="\3" style="width: \1px; height: \2px;" />' ) param_string.gsub!( /\[img\](.*?)\[\/img\]/i, '<img src="\1" />' ) # urls param_string.gsub!(/\[url target=['"]blank['"]\]([^\[]+?)\[\/url\]/i, "<a href=\"\1\" target=\"_blank\">\1</a>") param_string.gsub!(/\[url=['"]?(.*?)['"]? target=['"]?_?blank['"]?\](.+?)\[\/url\]/i, "<a href=\"\1\" target=\"_blank\">\2</a>") param_string.gsub!(/\[url\]([^\[]+?)\[\/url\]/i, "<a href=\"\1\">\1</a>") param_string.gsub!(/\[url=['"]?(.*?)['"]?\](.+?)\[\/url\]/i, "<a href=\"\1\">\2</a>") # youtube and google videos param_string.gsub!( /\[youtube\](.*?)\?v=([\w\d\-]+)\[\/youtube\]/i, '<object width="400" height="330"><param name="movie" value="http://www.youtube.com/v/\2"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/\2" type="application/x-shockwave-flash" wmode="transparent" width="400" height="330"></embed></object>' ) param_string.gsub!( /\[youtube\](.*?)\/v\/([\w\d\-]+)\[\/youtube\]/i, '<object width="400" height="330"><param name="movie" value="http://www.youtube.com/v/\2"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/\2" type="application/x-shockwave-flash" wmode="transparent" width="400" height="330"></embed></object>' ) param_string.gsub!( /\[gvideo\](.*?)\?docid=([-]{0,1}\d+)\[\/gvideo\]/i, '<embed style="width:400px; height:326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=\2" flashvars=""> </embed>' ) return param_string end |
That’s quite a bit to go through, but you will see they are all handled the same way. We use regular expressions to search through the string and replace the bbcode tag with its appropriate html. The above options are rather flexible also, allowing a few different ways to do urls, and allowing the user the option to include quotes around attributes - ie [img size=96x96] or [img size='96x96'] or [img size="96x96"] would all work.
From the above then, now users can enter all the following tags:
# Standard Text
[b]Bold Text[/b]
[u]Underline Text[/u]
[i]Italic Text[/i]
# Different sized and colored text
[size=12]12px Text[/size]
[color=red]Red Text[/color]
# Images
[img]/path/to/image[/img]
[img size=96x96]/path/to/image[/img] (img resized to 96×96)
# URLs
[url]http://www.8tasp.com[/url]
[url=http://www.8tasp.com]8TASP[/url]
[url=http://www.8tasp.com target='_blank']8TASP[/url]
# Videos
[youtube]http://youtube.com/watch?v=E4Fbk52Mk1w[/youtube]
[gvideo]http://video.google.com/videoplay?docid=-2200109535941088987[/gvideo]
And now we have a pretty good bbcode system in place for your users to use. In part 2 I will show how to make the bbcode easier for your users to work with by adding some javascript into the mix.
* update, part 2 is available here.
About this entry
You’re currently reading “BBCode with Ruby on Rails, Part 1,” an entry on Nazgum’s Blog
- Published:
- Tuesday, January 8th, 2008 at 12:45 am
- Author:
- Nazgum
- Category:
- Rails
2 Comments
Jump to comment form | comments rss | trackback uri