Jen Wendling

September 1, 2010

Who needs a codesitter?

Filed under: Development, Ruby on Rails — Tags: , — jen @ 1:02 pm

Not this chick. Sorry Rails, I love you and all, but you have now taken a governmental stance by trying to regulate the output of my HTML and for that, I must say: “Quit it!!”. If you haven’t caught up yet, Rails 3 takes HTML escaping into its own hands and instead of requiring you to use h() to escape your output, it’s now automagically escaped for you. Yay, that’s great right? No. Wrong. Because it means now anywhere you *didn’t* want your code escaped, you’ll have to use raw() or #html_safe. Also wrong because it enables bad, bad storage techniques.

First things first, you should be sanitizing your code prior to storage. Worried about someone adding JS to your public blog and breaking the site? Easy solution, throw away the <script> tag before writing to the db. There are plenty of tools to help with this, xss_terminate being one of them, there are even built-in Rails sanitizers. If you do it right on the way in, you won’t have to worry about it on the way out. Ok, so let’s say you potentially miss something? It happens, no one is perfect. That’s the perfect case to use escape trickery ( i.e. h() ) in the areas where you might be worried about your output.

In general, if you develop applications that resemble ones I build in anyway, you have more HTML output that *doesn’t* need to be sanitized than does. Sorry to whichever genius thought it would be a great idea to escape everything, but you made a bad decision. It’s okay, have a beer, wallow in your sorrows and then give users the option to turn this off. In the mean time, it’s easy to disable it yourself.

In config/initializers create a file, call it whatever, I called mine output_buffer.rb and all you need is:

class Object
  def html_safe?
    true
  end
end

class String
  def html_safe?
    true
  end
end

April 22, 2010

The video upload marks the spot.

Filed under: Uncategorized — jen @ 8:50 pm

It’s about time I write on this thing since it has been months since my last post. I was sifting through some old code I’d written last year and I tell you what, sometimes I’m actually shocked at the things I’ve written that I have forgotten about. For instance, I had a client who wanted not only the ability to upload videos, but also link to videos through YouTube. Sounds easy right? Okay but make the videos play in the same player, and make them look like there is no difference. Not so easy. It took a lot of scrounging since this was last year, prior to the YouTube API, however it became a very fun little project involving ffmpeg and rvideo.

Basically what happens is if a video has a YouTube ID, then go get the thumbnail image and the original MPEG file from YouTube and convert it to flv before saving. If the user uploads a video, use ffmpeg to grab a still of the first frame to use as the thumbnail, then convert it to flv and save it.

I present thee Video model. (Unfortunately this was so long ago, I was using attachment_fu… maybe Paperclip would have helped a bit.)

class Video < ActiveRecord::Base
  include AASM

  aasm_column :state
  aasm_initial_state :pending
  aasm_state :pending
  aasm_state :converting
  aasm_state :converted, :enter => :set_new_filename
  aasm_state :error

  aasm_event :convert do
    transitions :from => :pending, :to => :converting
  end

  aasm_event :converted do
    transitions :from => :converting, :to => :converted
  end

  aasm_event :failure do
    transitions :from => :converting, :to => :error
  end

  def get_yt_video_data
    uri = URI.parse("http://www.youtube.com/get_video_info")
    post_args = { 'video_id' => self.url }
    res, data = Net::HTTP.post_form uri, post_args
    b = res.body
    CGI::parse(b) ## return a hash of k=>v pairs
  end

  def get_yt_video_thumb
    get_yt_video_data["thumbnail_url"].first
  end

  def get_yt_video_duration
    seconds = get_yt_video_data["length_seconds"].first.to_i ## format this better... seconds/60 = mins/60 = hours ... hh:mm:ss
    total_minutes = seconds / 1.minutes
    seconds_in_last_minute = seconds - total_minutes.minutes.seconds
    "#{total_minutes}:#{seconds_in_last_minute}"
  end

  def get_yt_embed_url
    return CGI::escape("#{public_filename}") unless self.url.present?
    data = get_yt_video_data
    fmt = '';
    fmt_map = data["fmt_map"]
    a = fmt_map[0..2]
    if a == '18/'
      fmt = '18'
    elsif a == '22/'
      fmt = '22'
      break
    end
    token = data["token"]
    uri2 = URI.parse("http://www.youtube.com")
    args2 = {:video_id => url, :t => token, :fmt => fmt }
    qstr = "video_id=#{url}&t=#{token}&fmt=18"
    res = ""
    Net::HTTP.start(uri2.host, uri2.port) {|http|
      res = http.head("/get_video?#{qstr}")
    }
    CGI::escape("#{res.header['Location']}")
  end

  protected

  def after_create
    return true if url.present?
    convert
  end

  def convert
    self.convert!
      spawn do
        success = system("ffmpeg -i #{full_filename} -ar 22050 -s 480x320 -f flv -y #{full_filename}.flv")
        if success && $?.exitstatus == 0
          self.converted!
        else
          self.failure!
        end
     end
  end

  def create_thumbnail
    system "ffmpeg -i #{full_filename}.flv -s 120x90 -vframes 1 -f image2 -an #{full_filename}.jpg"
  end

  def set_new_filename
    create_thumbnail
    update_attribute(:filename, "#{filename}.flv")
    update_attribute(:content_type, "application/x-flash-video")
    update_attribute(:width, "480")
    update_attribute(:height, "320")
  end

end

November 24, 2009

Updating Multiple DOM Elements (Unobtrusively) with AJAX in Rails

Filed under: AJAX, Development, Ruby on Rails, jQuery — jen @ 10:35 am

Okay, so you're like me and you have a complex app that requires AJAX calls to update numerous areas on the page with content from partials. For instance, a date range changes, gets submitted, and that updates a calendar, the list of items below it, and so on and so forth. And, like me, you're choosing to use sexy, unobtrusive javascript to do so. (I'll be using jQuery as it's my flavor of choice, but feel free to apply the same principles to your JS library). The purpose of this article is not to explain AJAX or Rails, I will assume if you're reading, you have some education on both subjects.

First, we have a template that looks a little something like this:

HTML:
  1. <div id="events-calendar">
  2.   <%= render :partial => "events/calendar" %>
  3. </div>
  4. <% form_tag events_path, :id => "update_dates", :name => "update_dates" %>
  5.   <%= label_tag :start_date %>
  6.   <%= text_field_tagĀ  :start_date %>
  7.   <%= label_tag :end_date %>
  8.   <%= text_field_tagĀ  :end_date %>
  9.   <%= submit_tag "Go!" %>
  10. <% end %>
  11. <div id="events-list">
  12.   <%= render :partial => "events/list" %>
  13. </div>

Now, in the past using RJS, this was a very easy thing to do, you just did something to the effect of:

render :update do |page|
  page.replace "events-calendar", :partial => "events/calendar"
  page.replace "events-list", :partial => "events/list"
end

(more...)

November 3, 2009

Fluid Icons

Filed under: Random — Tags: , , — jen @ 10:09 am

Rock out. I'm uploading several high-res Fluid icons for your pleasure.

Click Here to Download (.zip)

Credits to:

Facebook: http://cootelibeau.files.wordpress.com

Github: http://github.com/blog/47-new-fluid-icon

Mint and Pivotal: http://sneaky.me/2008/11/fluid-app-icons-for-mint-and-pivotal-tracker/

Campfire: http://www.flickr.com/photos/indiekid/2555128022/

Gmail: http://iconexpo.com/


June 7, 2009

Rails Collection Blocks

Filed under: Development, Ruby on Rails — jen @ 1:19 pm

My great friend and mentor Jake Dempsey is always preaching about code readability and keeping logic out of views, etc, and therefore he's always writing nice little helpers to do some of the magic -- for instance, collection_content_for(collection) which will takes a block and will only render that block if that collection is not empty.

Now, it's my turn to give back:

I wanted something completely reusable, simple and easy-to-read that would allow me to iterate over a collection, whilst producing an html block of content specific to the type of object in the collection. Understand? No. Okay then, here you go:

BEFORE

<% if @blog_posts && @blog_posts.size > 0 %>
  <% @blog_posts.each do |blog_post| %>
    <div class="blog_post">
      <%= link_to blog_post.title, blog_post %>
      <%= truncate blog_post.content, :length => 500 %>
    </div>
  <% end %>
<% end %>

That's a lot of ugliness, logic, just --- ugh.

(more...)

April 17, 2009

When you get really bored, and want to find a problem for this solution:

Filed under: Uncategorized — jen @ 12:22 am

Getting the intersection and lowest values of a hash. :)

def hash_intersect_min(*hashes)
  hashes.inject(hashes.pop.dup) { |i,h| i.delete_if { |k,v| hv=h[k]; next true unless hv; i[k]=hv if hv<v; false }; i }
end

So the following:

hash_intersect_min({:a => 1, :d => 2, :k => 2, :j => 6}, {:k =>1, :a => 4, :j => 4}, {:e => 4, :k => 2, :d => 4, :j => 9})

Produces:

{:k=>1, :j=>4}

I'm completely aware of the extreme triviality this introduces to most programming, but ya know what... sometimes you need quirky crap to get you through the day. :) Happy coding!

March 23, 2009

Fancy Forgot Password with jQuery/ui and Rails

Filed under: Development, Ruby on Rails, jQuery — jen @ 11:04 am

By now, you have to know how fascinated I am by jQuery, and how much I love using it with Rails to make things simple, yet slick. Last week I did some wireframes for a client, and one of them was the "Forgot Password" feature... which I displayed in a modal dialog in the w/f. It seems to me that popups make sense for these kinds of things, rather than fully redirecting to another page, then upon successful password email, redirecting to even another page. So here was my fast, easy solution using jQuery (+jQuery-UI) and Rails.

First, make it work without Javascript and write your unit tests so they pass accordingly. Accessibility is at stake here people and we want to make sure anyone can retrieve their password at any time. My approach, just so you can follow the logic easily, is the following:

  1. User clicks Forgot Password link
  2. User enters email address
    • Invalid?
      1. Throw an error
    • Valid?
      1. Set new password
      2. Send email containing new password
      3. Alert with success message

So we create our controller method, our view, our notifier, and, if you like (I did), a method on our user model that does the setting and delivering of new password.

Code after the jump!

(more...)

March 13, 2009

Install Ruby, Rails and Subversion … in under 15 minutes.

Filed under: Development, Ruby on Rails, Subversion — jen @ 4:46 pm

Quick and Dirty Install

Assumes you are logged in as root. Use sudo where necessary (like any make or gem installs). Skip the steps that you already have (i.e. Ruby/RubyGems installation)

Install dependencies:

yum -y install zlib openssl-devel readline-devel gcc-c++

Install Ruby and RubyGems (if the REE installer fails for lack of finding an interpreter):

wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz
tar -zxvf ruby-1.8.7-p72.tar.gz
cd ruby-1.8.7-p72
./configure
make && make install
wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
tar -zxvf rubygems-1.3.1.tgz
cd rubygems-1.3.1
ruby setup.rb

Install Ruby Enterprise (if you are on a 64-bit distro, you may have duplicate i386 AND x86_64 versions of libstdc++ and you will get an error... either uninstall the i386 version, or add --no-tcmalloc option to installer command):

wget http://rubyforge.org/frs/download.php/51100/ruby-enterprise-1.8.6-20090201.tar.gz
tar -zxvf ruby-enterprise-1.8.6-20090201.tar.gz
./ruby-enterprise-1.8.6-20090201/installer
/opt/ruby-enterprise-1.8.6-20090201/bin/passenger-install-apache2-module

Add the following directory to your path (you could use symlinks too)

/opt/ruby-enterprise-1.8.6-20090201/bin

Add the following to Apache config:

LoadModule passenger_module /opt/ruby-enterprise-1.8.6-20090201/lib/ruby/gems/1.x/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
PassengerRoot /opt/ruby-enterprise-1.8.6-20090201/lib/ruby/gems/1.x/gems/passenger-2.0.6
PassengerRuby /opt/ruby-enterprise-1.8.6-20090201/bin/ruby

Install any gems you want or that are required that *did not* get installed as a result of the REE installer..

gem install passenger rake rails fastthread rack sqlite3-ruby postgres
gem install mysql -- --with-mysql-config='/usr/bin/mysql_config'

Install Subversion:

yum install subversion

Create repository:

mkdir /usr/local/svn/repos/
svnadmin create /usr/local/svn/repos/project
chown -R apache:apache /usr/local/svn/repos/project

Add the following lines to subversion.conf (or whatever apache config file you choose to use):

<Location /svn/repos>
DAV svn
SVNParentPath /usr/local/svn/repos
</Location>

Create a password file:

htpasswd -cm /etc/svn-auth-file username

Add more usernames/passwords:

htpasswd -m /etc/svn-auth-file username

Modify your subversion.conf to use whatever security method you deem necessary

Create your rails app:

rails rails_app

Import your rails app:

svn import -m "Initial import" rails_app file:///usr/local/svn/repos/project

Add virtual host for rails app (this will entirely depend on your server/application setup, but mainly concern yourself with the fact that your DocumentRoot and Directory directives should have /public at the end):

<VirtualHost *:80>
ServerAdmin webmaster@yourdomain.com
DocumentRoot /path/to/rails_app/public
ServerName yourdomain.com
ErrorLog logs/yourdomain.com-error_log
CustomLog logs/yourdomain.com-access_log common
</VirtualHost>

Done. Time to go caffeinate.

Full install approach after the break.
(more...)

February 12, 2009

Quick, Clean & Easy Form Popups (Dialogs) w/ jQuery … Eeeee!

Filed under: Uncategorized — jen @ 1:48 pm

The following itty-bitty snippet loads a page from my site (the new connection type page in this case), grabs the form out of it, injects it into a div which gets injected into the body of the page, then calls dialog on it. :) ComPLETEly unobtrusive, and I don't have to mess with any of my controllers or views to make it work. :) Ahhh the simplicity.


<a href="/connection_types/new/" class="popup">Add Connection Type</a>


$('a.popup').click(function() {
	$('<div />').appendTo('body').load($(this).attr('href') + ' form').dialog({
		title: $(this).text()
	});
	return false;
});

Read the docs for more info...

December 15, 2008

Association IDs with Ease

Filed under: Development, Ruby on Rails — jen @ 8:55 pm

Holy crap, that is a corny title. Oh, but it does have a point! I found this out the other day, and who knows how long it's been in Rails ( didn't check the old docs ) , but you can actually assign collection ids to an associated object! Ok that's confusing, just here's the example already:

I was working on a trip booking site in Rails, and I needed the ability to assign optional "excursions" to "passengers". So of course UI-wise, I'm using checkboxes... but backend-wise I'm thinking 'crap, I don't want to loop through each of the selected ones and assign them one at a time'. Literally, that's what I was thinking. So I did some snooping of the Rails docs in the Association::ClassMethods area... and found the following VERY useful info. :)

My example, uses the checkboxes, so in my view I have the following (note the empty string as the last param on the check_box, so that the default/unchecked value is NOT 0 (zero) .. that is unless you want to do more logic in your controller to check for 0 values to throw out).. anyway, the code:


<% @trip.excursions.each do |excursion| %>
  <%= check_box :trip_excursion, :excursion_id, { :id => "excursion_#{excursion.id}", :name => 'excursions[]' }, excursion.id, "" %>
  <%= label 'trip_excursion', 'excursion_id', "#{excursion.name} #{excursion.days_offered}", :for => "excursion_#{excursion.id}" %>
<% end %>

Then in my passengers controller (both create and update methods), I simply have:


@passenger = @trip.passengers.create params[:passenger]
@passenger.excursion_ids = params[:excursions]

One of my favorite things is, you can say collection_ids = *anything .. it can be null, an empty array, an empty string, a not-empty array, a single integer, and so on and so forth. This was actually very useful for doing the update (moreso than the create), since doing the update would have otherwise required checking for already selected excursions and comparing the values of the params, deleting those that were no longer "checked". This takes care of that by just setting the IDs explicitly, which will automatically remove the associations that are no longer in the new value-set. :) Happy coding...

Older Posts »

Powered by WordPress