Computers, Events, Linux, Open-source, Personal, Ruby, Software, Thoughts, Web, Windows

Adventures with Rails: Part Quatre

Looking back over my previous blog entry on my Rails application, I was quite surprised to find much has changed since my last update. I suppose time flies by when you are having run right?

At this point most of my controllers have been completed. The few that are remaining should be done within the next week. So without further ado, more screenshots of this fabulous website’s slow birth:

I am up to eight modules now, with ten total expected (that means 80% done!). The work involved in creating a new “module” is trivial, so this leaves a tremendous potential for growth in the future. Who sees what module is determined by their permissions. If you have a role of at least 1, then you get to see the module’s dashboard, but not necessarily have access to each method inside of it. Permissions are delegated out per method, so it is highly adaptable.

Sending a Targeted Announcement should have been something that was a piece of cake all along. The interface that the L****** portal provides is atrocious on its best day, so we have wrapped this functionality into something a little easier to work with. The wizard will take you through a few questions to setup a population selection to target your announcement to. Interestingly, this was provided out of a training workshop for the TA API. Instead of bothering to learn it, I just copied the shell script (and corresponding Java jars) and bootstrapped it.

Above is the form to create a population selection. A SQL query editor is included with syntax highlighting, and auto-completion for limited elements. Also, ‘generic’ population selections can be filled out ahead of time on the behalf of all/other users. Part of the model validation for a pop. sel. is actually making sure that the SQL query is valid by using the following code:

protected
def validate
begin
OCI8.new(BANNER_USERNAME, BANNER_PASSWORD, BANNER_DATABASE).exec(query)
rescue Exception => e
errors.add("query", "did not parse successfully: #{e.to_s}")
end
end

This screen shows the Targeted Announcement editor complete with TinyMCE (the rich-text editor), AJAX file uploads (using responds_to_parent), and Javascript live form validation. The real showcase here is outside of the Rails platform, with the shear number of options that the TinyMCE editor has. You can drag images from the web into the textarea and it graphically renders them, allowing you to tag, resize, apply formatting, etc all without knowing HTML. From the Rails end, a technical challenge was getting the files to upload asynchronously so that changes made in the editor are not lost after the upload.

An addition to the list of modules includes a channel module that, among other things, can search for offensive content inside of the host’s file system. The idea is to keep people from posting malicious content by deterrence, and to be quickly notified by email (via the cron module) when an instance does happen. On a side note, the number of freely available offensive content lists out there are quite lacking. Most lists offer a word such as (pardon me here) “shit” multiple times with different participals, including “shits”, “shitting”, etc. Obviously, these participals can be generated on the fly using a bit of Regular Expression magic. The resulting filter looked something like this (where BadContent is a table with each offensive word as a separate record):

def self.grep_search
@delimited = []
BadContent.find(:all).each {|x| @delimited << "#{x.name}"}
"\<(#{@delimited.join("|")})(s|es|ed|ing|er|ers|in|ings|off|os)?\>"
end

As the website scaled from development to testing, and production the need to accelerate the speed of permissions management became quite obvious. I offer two solutions here in addition to manually assigning permissions for each user per component by hand. The first is a global change of the user’s permissions for all modules. The second, will allow to clone from an existing account with autocompletion available on the textbox. From a Rails standpoint, this was easily accomplished by using the respond_to method in the controller class to redirect to a Javascript template:

In the view:

document.observe('dom:loaded', function() {
new Ajax.Autocompleter('clone','clone_entries','/permission/list', {
paramName: 'username',
indicator: 'spinner'
});
});

In the controller:

respond_to do |format|
format.html { (...removed for brevity...) }
format.js {
@data = User.find(:all, :conditions => ['username like ?', "#{params[:username]}%"])
render :template => 'permission/user', :object => @data
}
end

The new cron module can be seen here displaying content from the system’s crontab via the Ruby gem cronedit. A nice feature of rails is using the script/runner functionality to run methods inside your Rail’s application from the outside – in this case in Cron. I even went as far as to generate an email via ActionMailer when these jobs are run. PS, if anyone is interested in duplicating this functionality in Microsoft Windows – I would strongly advise you that it isn’t worth the effort.

The new log module allows for ‘tailing’ system logs from the website. It isn’t a true tailing of the file (-f) because the process would never end, thus your request never served to you. Instead, I have mimiced this functionality with very short intervals of AJAX updates (you can see the spinner next to the title). Any bad keywords are automatically highlighted using Ruby’s gsub method and regular expressions, similar to the offensive content implementation above.

And the page that no programmer wants the user to see – but would be pleased to know that if it had to happen that it did so gracefully. This catchall crash handler resides in the application controller. If an unhandled exception is encountered, the stacktrace, and all parameters are saved to the database for review later. I became a believer in this implementation after I used it in another website where a user encountered an issue, notified our helpdesk, and I was given an error number and was able to completly reconstruct the environment around which it occurred – all without having ever talked to the user. (And yes Chris, now your precious passwords are MD5 hashed before being saved!)

Nothing in this post so far has even mentioned that I checked this project into Subversion, and setup a production environment (actually that part was John), and deployed my application via Capistrano. What all that means is that (without ever having to shut down my development instance) I can make a change, commit it, and then run “cap deploy” to have it pushed to our production environment.

Now the project enters beta, and hopefully I can start getting some real use out of the system with some slav… I mean volunteers. It has been a very exciting few weeks…

Advertisements

One thought on “Adventures with Rails: Part Quatre

  1. I can’t wait to brea… I mean try it. I am pretty sure I have some some words that the list won’t filter out as bad. Words that end in t can cause you some troubles. Examples, tit – titties, shit – shitties. I know, probably trivial but also something that from the looks of it shouldn’t be too hard to fix.

    In all seriousness though I can’t wait to start playing with this. This interface looks to really allow us to streamline how we handle L****** in the call center. Just FYI, we are doing SPIRIT training the week of August 4th and on Thursday the 7th, there is a chance you might be able to present/train the HUB for a minute on this software. Also, whenever you want to start beta testing, let me know. After we walk though it, I am sure VS can be very helpful. Just let me know.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s