Using the sanitize gem - Clean HTML

by Jess Brown

I recently had a need to sanatize html entered by users in an app. The app (www.csepub.com) allowed professors to enter homework assignments for their ebooks. One type of homework assignment is a written assignment. The app needed to allow the user/student to create and submit an assignment. At first we were using uploaded documents, but with thousands of students, this became a heap of uploaded word docs. Recently we decided to allow the student to submit their assignment via html using an html editor (trimmed way down to just basic text formatting).

My fear was that allowing this many people to enter html into my database, that something might get wonked up. I'm not a security expert, but I figured I should be sanitizing the html.

After a bit of research I found the sanitize gem (https://github.com/rgrove/sanitize). It does 2 basic things: 1) clean the html of unwanted tags and closes any open tags. Hopefully this won't be a problem for me because I'm preventing the user from editing actual html with a slimmed down html editor, but I don't want to take a chance.

The gem is pretty straight forward. Just place it in your gem file and then bundle.

Next, in the AR model you want to store your html in, I added a 'before_save' hook.

class AssignmentUpload < ActiveRecord::Base
  before_save :clean_html

  private
  def clean_html
    self.html = Sanitize.clean(html, whitelist)
  end
end

The biggest decision you have to make is which tags you want to whitelist. Sanitize has several pre built levels for you to use. Sanitize::Config::BASIC looked like the option for me. However, I realized that I needed to allow a span tag with a inline style (professors wanted to make notes to the assignments and highlight text). I didn't want to recreate the pre setup from scratch, so I figured out Sanitize::Config::BASIC is just a hash so I just slightly modified it.

def whitelist
  whitelist = Sanitize::Config::BASIC
  whitelist[:elements].push("span")
  whitelist[:attributes]["span"] = ["style"]
  whitelist
end

Ruby on Rails - Increment and decrement

by Jess Brown

If you're using rails and have an integer column in database that you want to increment or decrement, rails provides a nice abstraction for you to use. Normally you'd have do something like this:

def increase_credits
  update_attributes(:credits => credits + 1)
end

Then you can call it like:

@user.increase_credits

With the increment and decrement you can do it this way:

@user.increment!(:credits)

or

@user.decrement(:credits, 2)  # decrease credits by 2

It just saves setting up the method and allows you to pass an integer to increment by!

Decrement: http://apidock.com/rails/ActiveRecord/Base/decrement! Increment: http://apidock.com/rails/ActiveRecord/Base/increment%21

Rails uniq_by - Unique Results From ActiveRecord Relations

by Jess Brown

I just discovered a neat method in rails called uniq_by. ( http://apidock.com/rails/Array/uniq_by )

It allows you to get a unique set of results from an active record relation.

Ruby provides a way to get unique results from an array like so:

a = [1, 2, 3, 3, 4]
a.uniq # results [1, 2, 3, 4]

But if you have an active record relation, the normal uniq won't work. Say you have a list of stores and you want to find their location, but you only want 1 location from each store/company. You can use:

Location.near("monroe, ga").uniq_by(&:store_id)

And that will give you a nice unique Array from an AR relation!

Read The Code

by Jess Brown

Several monts ago, John Nunemaker bloged "Stop Googling". It was about reading the code in an open source project oppsed to Googleing it. He was a bit funstrated at someone who Googled, polled friends, and basically searched everywhere besides the source to look for an answer for their problem.

Today I found out the hard way how right he was. I was trying to access the object info passed along to a delayed_job record. I googled for 30 or 45 minutes trying to find an answer and couldn't get any bites. I knew the handler field had the info I needed, but it was a string. I also knew that somehow that info had to be extracted when my job was processed. Finally on a whim, I looked to the source code. In the second file I opened, I found a method called payload_object.

def payload_object
  @payload_object ||= deserialize(self['handler'])
end

I saw object, deserialize, and handler. That's all I needed to know. It was exactly what I wanted. It took less than a minute. I tried it out and that was it.

That's when I remembered John's blog. Note to self: if a quick google search doesn't display the obvious answer...LOOK AT THE CODE!

Ditch FTP For GIT

by Jess Brown

Ever since I started learning Ruby On Rails several years ago, I’ve been using git. Git is a cool tool you can use for version control, or in some cases, simple incremental backups. It basically keeps track of your code and file changes, you commit/save the changes and can revert back, review history and do all sorts of cool stuff. It additionally will allow you to setup a remote repository to push changes to. That’s where this article comes in.

Using git in rails is really a must, but in the static world, FTP mostly dominates.

I’m really tired of using FTP. I probably hit Command + Shift + Upload 200 times a day. Sometimes I edit files very quickly and hop from file to file, add images to a images directory and javascript files to the js directory. How can I remember which files to FTP? It can be as simple as “git push” and only my changes are updated.

First off, requirements:

  • web server with shell access
  • web server with git installed
  • local machine with a terminal
  • local machine with git installed
  • local machine to test (if you can’t run your code on your local machine or local server, it doesn’t make much sense to setup git...it would be painful to add, commit, push every tiny change)

Get Started

Server Side

Take care of the server side first. ssh into your web server and find a place outside your public folder. For example, a cpanel server is /home/account_name/public_html. I’d store it in /home/account_name.

mkdir account_name.git && cd account_name.git
git init --bare

Now we’ll tell git where to store the actual files:

git config core.worktree /home/account_name/public_html
git config core.bare false
git config receive.denycurrentbranch ignore

Now we have to tell git what to do after we push changes.  Create and open a new file:

vim hooks/post-receive

In this file place this code:

#!/bin/sh
#tell git to copy over the files
git checkout -f
#change ownership of files so your web server can serve them (I’m logging in as root so it may not be necessary if you logging in as account_name
chown -R account_name:account_name /home/account_name/public_html/*

Note: This file (post-receive) needs to be executable. To be sure:

chmod 755 hooks/post-receive

Local Side

Navigate to the directory where your website code lives. If you haven’t already setup git:

git init
git add .
git commit -m ‘initial commit’

Now link up the remote repository:

git remote add origin ssh://user@yourwebserver.com/home/account_name/account_name.git

Now it’s time for the magic:

git push origin master

Your website should now be live. You can now make changes locally, test and then push. Example:

#...make some changes to your code
# test them (this could be a visual QA test or automated test)
git add .
git commit -m ‘my first changes’
git push #no need for the origin master now

Navigation