a day in the pit my view from inside

2Nov/110

What’s New in Rails 3 & What I’m Excited About

Rails 3.1.0 was released on 8/31/2011, and as such marks a great day for the Rails community. For a while Rails felt stagnant (think 2.3.11 to 3.0.1RC) and so this is something I've been looking forward to. As I've been using Rails 3 for over a year now, and I've been following along in the change sets, I wanted to point out some of the features I think are really going to be game changers.

Sprockets, and the Asset Pipeline

Previously done through third party libraries, the Asset Pipeline is a built-in framework for managing your assets and writing these assets in other, some say more friendly languages, like CoffeeScript for JavaScript and Sass for CSS  style sheets. It's a very large change to Rails because it introduces a new mix of options for how you can write your JS/CSS and it moves the serving of these components to the Rack middle-ware. Your asset resources now can be pre-processed, minified, and compressed in one swoop. This process is done by Sprockets. I won't go into any further detail but you should know this is worth reading up on, so go check out the Asset Pipeline introduction by the RoR team. (You can disable this feature if you don't want to use it. So don't freak out!)

Streaming

Although it requires Ruby 1.9x to run, HTTP streaming has finally been added. Part of the confusion I often hear about Rails is why this feature was not there from day one. To be honest, I'm not sure but my hunch is that it didn't make sense in a prototyping stage to have to stream content. Further, it's very very error prone compared to building your response and then shipping it over (i.e. if computational errors occur mid stream you're dead in the water and the page will never finish loading). Further, Ajax helped mitigate this need by loading a light HTML shell and then using asynchronous calls to fetch your users' data. At any rate, I'm very excited for this feature because the last two years of PHP coding has had me used to buffering output and I really do see the value in being able to use streaming to show progress without making lots of asynchronous calls.

JSON

ActiveResource now defaults responses to JSON, as opposed to XML.

jQuery

Is now the default JavaScript library bundled with Rails 3. Further, RJS has been factored out as a gem.

Basic Authentication

Rails 3 comes with a quick and easy way of doing Basic Authentication (Username/Password) in your Controllers. Read up on Base.http_basic_authenticate_with - Check out the example here

Pluralize Names for Models

Yup! You can now set, on specific models, whether you want them pluralized or not. From within your controller class you'd set: self.pluralize_table_names = false

BCrypt Passwords

You now have a model attribute has_secure_password that will take care of password hashing/encryption.

26Apr/100

Rails, jQuery UI (Sortable), and Ordering of Slides

I am partly sharing this issue and solution to the world, but mostly just recording somewhere what I came up with. Now, onto the quick read.

A web design client recently asked me to build a web site for him that would allow him to create slide shows of his art work. One of the criteria was to create a way to set the order and, at a later date, re-arrange slides in the slide shows. Turning to jQuery UI, specifically the Sortable (doc), and a simple rails controller this task was pretty trivial. My initial concern was that a slide show could consist of hundreds of slides and doing any sort of ajax updating of the slides would be too slow. Turns out, this was a real concern and after reading all kinds of blogs I was unable to find a work-able ajaxively awesome solution. So, I turned back to the non web2.0 design of just having a Save Order button. The methodology of my solution is straight forward: allow the user to drag and drop to any order configuration they please and then save that order. Upon clicking save via the user interface, invoke the following javascript command that will build the query string and do a window relocation. I'd rather use GET than POST for no real reason outside of having to hack around the authenticity token. After all, what's the point of having an auth token if you're just going to override it in a members-only section. Here is the complete code for the view, broken into pieces for clarity.

CSS:

  #sortable { list-style-type: none; margin: 0; padding: 0; width: 100%; }
  #sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; font-size: 1.4em; height: 18px; }
  #sortable li span { position: absolute; margin-left: -1.3em; }

JS:

<script type="text/javascript">
// Initialize sortiable on #sortable div
$(function() {
	$("#sortable").sortable();
	$("#sortable").disableSelection();
});
// Prepare and go-to proper url for updating order of slides.
// Called via html anchor tag by user
function update_order() {
  window.location.href = "/slides/order?"+$('#sortable').sortable('serialize');
}

Sample #sortable:

<ul id="sortable">
	<li id="slide_2" class="ui-state-default full-width"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Lack of a better Title</li>
	<li id="slide_3" class="ui-state-default full-width"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>A fireplace for two</li>
	<li id="slide_1" class="ui-state-default full-width"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>My Super Sweet Villa</li>
	<li id="slide_4" class="ui-state-default full-width"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>A view from above</li>
</ul>

Anchor link:

<a href="#" onClick='update_order(); return false()'>Save Order</a>

Controller:

  def order
    if params[:slide]
      params[:slide].each_with_index { |slide, index| Slide.update(slide.to_i, :slide_position => (index +1)) }
      flash[:notice] = "Slide order has been updated."
      redirect_to(slides_path)
    else
      @slides = Slide.ordered
    end
  end

Now, for some disclaimers... You should add in error handling to all of these pieces! For brevity, I've included the main pieces of the task and not my error handling code. You can also use post and add in (instead of looking for params[:slide]) if request.post?... Just don't forget to put in the authenticity_token to your ajax or form post (forms do this automatically in rails if protect_from_forgery is enabled).

Efficiency: This is a O(n) algorithm, because it has to iterate over each element being sorted and do three things: fetch from the database, update the attribute, and save. The last two steps can be combined. I'm using the handy ActiveRecord::Base extension in Rails called update to do this. Here's that code so you don't have to look it up:

     # File vendor/rails/activerecord/lib/active_record/base.rb, line 744
744:       def update(id, attributes)
745:         if id.is_a?(Array)
746:           idx = -1
747:           id.collect { |one_id| idx += 1; update(one_id, attributes[idx]) }
748:         else
749:           object = find(id)
750:           object.update_attributes(attributes)
751:           object
752:         end
753:       end

I was unable to locate any kind of conditional MySQL update that would allow different values to be updated for different rows all in one swoop. I'll admit my research on this topic was about 30 minutes of blog and StackOverflow reading... If you have something more efficient please reply.

Here are the link(s) to relevant information:
jQuery UI Demos (and download) -- I'm using the latest code base as of this post. The styles you see within the bullet list items are from the jQuery UI theme.

19Aug/090

That Was Mean

For the past few weeks I have been spending a few minutes here and there putting together a catalog web site. Now, you may be asking what kind of catalog system would Mike be working on? Let me fill you in....

It all started with a co-worker, an awesome guy, and a few tasteful jokes. One bad joke later I wanted to get him back in a way that no man can deny: publishing a public wronging on the Internet. And, with that, thatwasmean was born.

It started as a very simple logging of things said in the office.

The categories grew for different needs.

The color schemes changes as suggestions came in.

But what I have found most interesting so far is the cohesiveness between posts. They relate to each other, even spread across multiple days, and you can generally figure out what goes with what and the livelihood of that incident within our office.

So, with all that said, ThatWasMean.com launches to a little more of a public scale. It was developed in Ruby on Rails, hosted using Phusion Passenger and Apache, and is evolving slowly... Check it out and provide any feedback.

go to ThatWasMean

14Aug/090

Ruby Regular Expressions – Security Risk

This post is a half reminder to elaborate when I have free time... But in short, there is nothing wrong with Ruby regular expressions, except that they behave differently than one might expect (in general and if coming from Perl RegEx).

Here is the dealy, from the Programming Ruby book by Dave Thomas:

The patterns ^ and $ match the beginning and end of a line, respectively. These are often
used to anchor a pattern match: for example, /^option/ matches the word option only if it
appears at the start of a line. The sequence \A matches the beginning of a string, and \z and
\Z match the end of a string.

All sounds good right? Well, it turns out that Ruby will execute code within a regular expression if you can pass multi-line input to the parser. For example... Given

class EmailAttachment < ActiveRecord::Base
validates_format_of :attachment, :with => /^[\w\.\-\+]+$/
end

You can easily pass in

attachment.txt%0A<script>alert('open_sesame')</script>

which is converted (as %0A is a URL encoded new line), by ROR, into

"attachment.txt\n<script>alert('open_sesame')</script>"

You can think about the implications of this, feel free... I have been able to have some fun with my own personal site and getting arbitrary JavaScript and (worse) shell commands to execute. Also, I believe this may cause a larger security whole within routes for Rails (at least 2.1.0). I'll investigate this more later, as the beginning of this post says.

25Jul/090

Validating Emails in Ruby on Rails

It's time to validate e-mail addresses and you're sitting in a Ruby on Rails application. Fortunately, there are a few methods to tackle such a task, and a combination of them can yield a pretty nice solution.

The first idea is to use some lengthy regular expressions. But why enumerate/describe in regular expressions what we are looking for when TMail has it built in... Using TMail, it is possible to let our Ruby Net SMTP wrapper class parse the email address and decide if it is correct or not.

The second task is to make up for some of TMail's odd shortcomings: the fact that the text "bob" passes as valid for TMail is alarming, but throwing in some simple regular expression to get past this provides a pretty solid solution. (For the curious, "bob" is a valid e-mail to TMail because you could be sending messages to the local domain.)

First, here is our regular expression for a basic e-mail address...

/^([^@\s'"]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i

Next, we create a TMail object with our e-mail address...

tmail = TMail::Address.parse(address.to_s) rescue nil

I am rescuing nil here. You can rescue whatever error message you want, but for example sake I am not so concerned if the TMail fails to parse the e-mail address. You can pass in a multitude of e-mail formats and TMail will do its best to match the RFC standard for e-mail addresses.

You now have access to a TMail object with a flurry of options (TMail & documentation). Let's proceed.

My simply method calls TMail and then follows it with the regular expression match to ensure this e-mail address in question is ready to be used on the web. Here is my final result to a pretty safe-proof (so far, tested on a rather large web site) e-mail handler. This method will return the TMail object.

def validate_email e-mail
  tmail = TMail::Address.parse(address.to_s) rescue nil
  tmail if tmail.address =~ /^([^@\s'"]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
end

And for those of you who want the extra step, I have attached a helper method that takes a TMail object and gives you back the e-mail address in string format fully qualified.

def formatted_email tmail
  if !email.blank?
    friendly_name = (tmail.name.blank? ? "" : tmail.name.blank?).tr('"',"'")
    quote = '"' if friendly_name =~ /[&lt;,@;]/
    "#{quote}#{friendly_name}#{quote} &lt;#{address}&gt;"
  end
end

As always, test this code and do not trust it blindly. I could have fat fingered something...