Rails comments system with bb-code - ruby-on-rails

In my rails 4 app i want to add comments to my articles, but i want to add functional as most forum-engines do (like SMF), and i need to add bb-code for it.
Are there any good gem for it? With rails 4 support? How then in controller i can translate [quote] to some div with some style?
Also how is it good to store html data in database?
For example if i use haml, and somebody post comment as
- current_user.id
or something similar to this, how to secure my app from "bad boys" ? Sure i can change comments system to something like: quote_parent_id, but if i have multiple quotes in one comment? so it is hard to realise, better is to store html, but to secure it somehow.
Could i do this? And how? Please give good ideas, tutorials, gem-links.

Look into https://github.com/veger/ruby-bbcode
Since it converts to HTML and does not excecute user input as Ruby code - you'll be fairly safe. However, I havent tried the gem and its possible it introduces some XSS vulnerabilities.
Have you considered Markdown as an option?

You should also look into https://github.com/asceth/bbcoder ( I should note I am the original author ).
In the controller, changing a string such as "[quote=user]My post of epic importance[/quote]" into a div etc is just doing:
# assume params[:comment] is the text you are converting
params[:comment].bbcode_to_html
As for storing html in a database, there is no right or wrong answer. If you want to allow users to edit their posts later then I would lean towards not storing the html version but storing their original bbcode version. This way when you allow them to edit you aren't having to convert html back to bbcode.
To make sure you aren't open to XSS and other attacks I recommend combining other gems like sanitize.
Sanitize.clean(text.to_s).bbcode_to_html
Some more notes:
Multiple tags and nested tags are parsed as they are seen without any additional steps required. So a comment or post with lots of bbcode tags, multiple quotes, b tags or anything else is dealt with by just calling bbcode_to_html on the variable/string.
If a user tries to use haml in their post it should appear as-is. haml shouldn't try to eval the string unless you specifically tell it to which I'm not even sure how to do that unless haml as a special filter or operator.

Related

Replace URL in Text Body with an Image Tag for that URL

As the title suggests I would like to find a way to replace URLs within a body text (for a blog) with image tags for those URLs. I suspect I will need to do some form of regex. Has anyone done something like this before?
EDIT:
To describe the use case a bit more, I have a blog-esque site I am building. I would like blog writers to be able to 'drop' urls into text posts (separated by newlines), and have rails intelligently parse the string and replace any urls with images (perhaps in a helper method).
The sanest approach is to use something like Markdown (or exactly like it) and ensure that your posts are marked up correctly. This seems to be the most up-to-date gem for Markdown, https://github.com/vmg/redcarpet.
Alternatively, if you want to do this by yourself, it would still be prudent to mark up a link in some way. For example, {image src=link_to_the_image_here}.
This will make finding images within the body of text easier.

How the url should be stored in records?

I have a question.
I have comment model, in which it has body column that users can type anything in there.
obviously user might type the url link to other website.
In my guess, I think it should be replaced with < a href > tag when it is being saved.
Is there any good gem or something to handle this kind of thing?
If you don't want to use a full-blown markdown parser (Redcarpet), use Rinku. It's super fast and safe. Do not use any regex based solutions as you would most likely open yourself to security risks.
text = "Hello! Check this out: https://github.com/vmg/rinku"
Rinku.auto_link(text, mode=:all, link_attr=nil, skip_tags=nil)
Produces:
=> "Hello! Check this out: https://github.com/vmg/rinku"
Preserving for posterity's sake, but I feel it's important to note that this is NOT a secure way to solve the problem. Unless you want to figure out all the security implications for yourself, don't follow this advice. Jiří Pospíšil's answer is better. =D
You don't really need a gem to do that (I personally try to avoid gems for something so simple). Write a regular expression that is reasonably reliable for your purposes, and then use something like
input.gsub(regex, 'some text')
to convert the links into their html equivalent. Note that you'll need to use raw to display the results of this, otherwise rails will escape the output for you. This also means users will be able to put other arbitrary markup in, unless you escape it as it goes into the database. Make sure you do that.
Alternately, you could do the same thing as you display it, with slightly different considerations/steps necessary.

Rails 3 - Friendly params in url (GET)

I have a rails 3 app and now i implementing filter for my catalog. Filters form pass data to controller through GET request. As a result i have link like this in my browser after i submit
my form (apply search):
http://localhost:3001/shoes?filter%5BShoeBottomType%5D%5B%5D=2&filter%5BShoeClassification%5D%5B%5D=1&filter%5BShoeClassification%5D%5B%5D=2&filter%5BShoeElation%5D%5B%5D=3&filter%5BShoeElation%5D%5B%5D=4&filter%5BShoeElation%5D%5B%5D=5&filter%5BShoeLiningColor%5D%5B%5D=2&filter%5BShoeLiningColor%5D%5B%5D=3&filter%5BShoeLiningColor%5D%5B%5D=4&filter%5BShoeTopColor%5D%5B%5D=1&filter%5BShoeTopColor%5D%5B%5D=2&filter%5Bonly_action%5D%5B%5D=1&page=2
Is there a way to do URL more beautiful?
PS i dont want use POST request, because I read that it is bad for SEO
TLDR: just leave it.
HTML forms serialize in a straightforward manner; the parameters are named after the HTML elements. The actual issue here is how the form elements are named. It looks like they have names like filter[ShoeBottomType][]; look into your HTML to see the name attributes. Since you're in Rails, I'm guessing you having a filter hash passed to your Rails controller method as a single argument, and since Rails expects hashes to use a certain URL format for hashes and arrays (it has to know how to deserialize it from the request), the form helper writes the form that way. And yours is especially complicated because the hash values are arrays, hence the extra set of brackets. Then it's URL encoded and you end up with an ugly mess.
You could avoid some of this problem by passing the inputs individually back to the controller instead of as a big hash. Something like:
def index
shoe_bottom_types = params[:bottom_types]
shoe_classifications = params[:classifications]
shoe_elations = params[:elations]
...
which will get you to: /shoes?bottomTypes[]=1&bottomTypes[]=2.... That doesn't seem much better, and now your controller is all gross. And I don't see how you're going to get rid of the brackets entirely if you want to have more than one of the same filter. I guess you could get crazy and do your own parsing in your controller, like breaking apart shoeBottomTypes=1|2, but then you'll have to do your own form serialization too. Again, just not worth it.
Backing up for a sec, the SEO stuff doesn't make much sense. Search engines won't fill out your form; they just follow links. The real reason you should use GET is that (presumably), submitting your form doesn't have side effects, since it's just a search. See here; it's important to use the right HTTP methods. If you use POST, you'll get weird warnings on reloads and you won't be able to bookmark the search.
Backing up even further, why do you care, especially now that SEO is out of the picture? Just as a quick demo, I did a google search for the word "thing" and this was the URL:
https://www.google.com/#hl=en&output=search&sclient=psy-ab&q=thing&pbx=1&oq=thing&aq=f&aqi=g2g-s1g1&aql=1&gs_sm=3&gs_upl=764l1877l0l1980l6l6l0l0l0l0l89l432l5l5l0&bav=on.2,or.r_gc.r_pw.r_cp.r_qf.,cf.osb&fp=220ef4545fdef788&biw=1920&bih=1086
So URLs for form submissions can be long. The user won't even look at it.
The only possibility I can think of for why you'd care about the length/ugliness of your URL here is that you want, separately from the form, to create links to certain searches. There are several ways to handle that, but since I don't know whether that's relevant to you, I'll let that be a follow-up.
So bottom line, it looks like I'd expect, and trying to fix it sounds ugly and pointless.
If you do not want to use a POST request, then there is no other way then to put the form values in the URL -- they have to get to the server one way or another.
On the other hand however, I do not see why doing a POST would be bad for SEO and I would love to see the article that stated so.
My suggestion is that you could add some custom routes to beautify your urls.
For example :
http://localhost:3001/shoes/Type/2/Classification/1,2/Elation/3,4,5/LiningColor/2,3,4/TopColor/1,2/only_action/1/page/2
This is far much shorter than your initial URL ;)
The counterpart is that, as far as I know, you have to use always the same order for params in your url.
The routing rule is the following :
match "shoes/Type/:type/Classification/:classification/Elation/:elation/LiningColor/:liningcolor/TopColor/:topcolor/only_action/:only_action/page/:page" => "shoes#show"
You can retrieve the passed values in params array. You have to split the string containing , in order to retrieve the multiple values.

How good is the Rails sanitize() method?

Can I use ActionView::Helpers::SanitizeHelper#sanitize on user-entered text that I plan on showing to other users? E.g., will it properly handle all cases described on this site?
Also, the documentation mentions:
Please note that sanitizing
user-provided text does not guarantee
that the resulting markup is valid
(conforming to a document type) or
even well-formed. The output may still
contain e.g. unescaped ’<’, ’>’, ’&’
characters and confuse browsers.
What's the best way to handle this? Pass the sanitized text through Hpricot before displaying?
Ryan Grove's Sanitize goes a lot farther than Rails 3 sanitize. It ensures the output HTML is well-formed and has three built-in whitelists:
Sanitize::Config::RESTRICTED
Allows only very simple inline formatting markup. No links, images, or block elements.
Sanitize::Config::BASIC
Allows a variety of markup including formatting tags, links, and lists. Images and tables are not allowed, links are limited to FTP, HTTP, HTTPS, and mailto protocols, and a attribute is added to all links to mitigate SEO spam.
Sanitize::Config::RELAXED Allows an even wider variety of markup than BASIC, including images and tables. Links are still limited to FTP, HTTP, HTTPS, and mailto protocols, while images are limited to HTTP and HTTPS. In this mode, is not added to links.
Sanitize is certainly better than the "h" helper. Instead of escaping everything, it actually allows the html tags that you specify. And yes, it does prevent cross-site scripting because it removes javascript from the mix entirely.
In short, both will get the job done. Use "h" when you don't expect anything other than plaintext, and use sanitize when you want to allow some, or you believe people may try to enter it. Even if you disallow all tags with sanitize, it'll "pretty up" the code by removing them instead of escaping them as "h" does.
As for incomplete tags: You could run a validation on the model that passes html-containing fields through hpricot, but I think this is overkill in most applications.
The best course of action depends on two things:
Your rails version (2.x or 3.x)
Whether your users are supposed to enter any html at all on the input or not.
As a general rule, I don't allow my users to input html - instead I let them input textile.
On rails 3.x:
User input is sanitized by default. You don't have to do anything, unless you want your users to be able to send some html. In that case, keep reading.
This railscast deals with XSS attacks on rails 3.
On rails 2.x:
If you don't allow any html from your users, just protect your output with the h method, like this:
<%= h post.text %>
If you want your users to send some html: you can use rails' sanitize method or HTML::StathamSanitizer

Sanitize output in Rails

What is the best solution to sanitize output HTML in Rails (to avoid XSS attacks)?
I have two options: white_list plugin or sanitize method from Sanitize Helper http://api.rubyonrails.com/classes/ActionView/Helpers/SanitizeHelper.html . For me until today the white_list plugin worked better and in the past, Sanitize was very buggy, but as part of the Core, probably it will be under development and be supported for a while.
I recommend http://code.google.com/p/xssterminate/.
I think the h helper method will work here:
<%= h #user.profile %>
This will escape angle brackets and therefore neutralize any embedded JavaScript. Of course this will also eliminate any formatting your users might use.
If you want formatting, maybe look at markdown.
Personally I think it's not a small decision to accept any HTML entry in any web app. You can test for white/blacklisted tags as much as you like, but unless you're testing for correct nesting, someone could enter a series of closing tags, for example
</td></tr></span></div>
and really mess with your layout.
I'd usually give people something like Textile to enter their markup, since I'd rather spend my time working on business logic than HTML parsing.
Of course, if this text entry is more fundamental to your app (as for example it is for stackoverflow) then you probably should give more attention to hand-rolling your own.

Resources