5minutenPause

father and developer from Berlin. coffee-geek. tea lover.

Submit remote forms with jQuery in Rails

The other day I had created a form without a submit button. It is a simple checkbox, which toggles if a user is admin for a project.
It looks like this:

Controller

Ticking the box should toggle the state for the user. So I created a controller action:

1
2
3
4
def toggle_admin_state
  @project = Project.find(params[:id])
  @result = ProjectAdministrationPolicy.new(current_user, @project).create? && ProjectAdministration.toggle!(params[:user_id], @project.id)
end

ProjectAdministrationPolicy is about authorization. I use the Pundit gem for these tasks.
ProjectAdministration.toggle!(params[:user_id], @project.id) toggles the admin? state for the given user. I return a boolean representing the outcome of the action. Perhaps there was an error of some kind, or the current_user isn’t allowed to change the admin state for the given user. Either way we get a true/false result, which we use in our view.

View

There are two views at play here. The first is the view with the form itself. The other view is what gets rendered after the form was submitted. Let’s start with the view that contains the form.

1
2
3
4
5
<%= form_tag toggle_admin_state_path, method: :post, remote: true, id: 'toggle_admin_form' do %>
  <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
  <%= hidden_field_tag :user_id, membership.user_id %>
  <%= check_box_tag 'user_id', "#{membership.user_id}", ProjectAdministration.where(user_id: membership.user_id, project_id: membership.project_id).any?, class: 'admin_checkbox', id: "user_#{membership.user_id}" %>
<% end %>

The important parts of the form are the options to the form itself. method: :post makes sure, we use the right HTTP action. remote: true makes this a form which we can submit via javascript. The other form elements are just standard rails form tags. A little trick you’re perhaps not aware of: If you use checkboxes in your form, the checkbox’ value only gets submitted, if it is checked. We need the value (the user id) all the time, to actually find the user and toggle its admin state. That’s why we always submit the user_id using a hidden_field. This makes sure, we always have the value, no matter the state of the checkbox.

Next up the view for the action. As the action should only respond to javascript I created the following view:

1
2
3
4
5
6
7
8
9
<% if @result %>
  $('#main-content').prepend("<div id='flash_notice' style='overflow: hidden;'>Change successful.</div>");
<% else %>
  $('#main-content').prepend("<div id='flash_warning' style='overflow: hidden;'>You are not allowed to do that or there was an error.</div>");
<% end %>

setTimeout(function() {
  $('#flash_notice, #flash_warning').hide(400);
}, 1500, false);

This adds a <div> at the top of the page, just below the topbar. This is where I show my warnings and notices. It’s of course up to you to decide where you want to show this flash message. Or you don’t show it at all.
The last three lines set a timeout of 1.5 seconds. After the countdown completes the warning or notice is hidden with a little animation, courtesy of jQuery. I set the speed for the hide animation to 400ms.

Route

As we use toggle_admin_state_path in our form, and because we defined the controller action, we need to set up a route for this to work. That’s easy:

1
post 'projects/:id/toggle_admin_state' => 'projects#toggle_admin_state', as: 'toggle_admin_state'

Submitting the form

The final step is submitting the form. The naive way (read: the way I tried first) is to use an event handler and just call submit() on the form. It may look like this:

1
$('form#toggle_admin_form').submit();

This actually works. Only problem is, it’s not submitted as JS, but as HTML:

1
2
Started POST "/projects/3/toggle_admin_state" for 127.0.0.1 at 2014-03-28 13:03:51 +0100
Processing by ProjectsController#toggle_admin_state as HTML

If you want to submit as a truely remote form, and use your .js.erb view, you have to do things a little differently.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$('.admin_checkbox').bind('change', function() {
  $.ajax({
    url: $(this).parents('form')[0].action,
    headers: {
      Accept : "text/javascript; charset=utf-8",
      "Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    type: 'POST',
    data: {
      'user_id': $(this).siblings('[id*=user_]').val(),
      'authenticity_token': $(this).siblings('#authenticity_token').val()
    }
  });
});

Let’s take it from the top:
Line 1 binds to the change event of this checkbox. If you check or uncheck it, the function is called.
Line 2 uses jQuery to make an asynchronous HTTP request
Line 3 the url for the request

These were basic options. Now we have to set the correct headers.
Line 5 Set the accept header. By default it depends on the dataType. But if you set the dataType to script, your POST request get submitted as a GET request. Which doesn’t work for us.
Line 6 Set the content-type. This is important. Otherwise your form parameters won’t be submitted in a way that your server understands and processes them.

Line 8 make sure this is a POST request
Line 9 get the form data and set it as request data (body)

Now if we toggle the checkbox, the request is sent as a JS request:

1
2
Started POST "/projects/3/toggle_admin_state" for 127.0.0.1 at 2014-03-28 13:32:41 +0100
Processing by ProjectsController#toggle_admin_state as JS

This wraps it up. I hope you’re successful with your remote forms. This time there won’t be a Github repository. The content of this post is quite specific to my app. I believe you can implement your remote forms quite easily wih the right jQuery asynchronous HTTP request syntax.

Happy coding.

I am just like you.

I have a list in my simplenote app that contains ideas, headline and snippets for possible future blog posts. Right now there are about ten entries. It’s hard to tell how many exactly, because some are just a headline for a kind of mini series about something. Some of these possible posts are about ruby/rails technologies. Some are about workflows (e.g. deployment). One or two are about things I did earlier in my career, so they are something about funny or interesting anecdotes, or just for reliving and remembering things. Some ideas are even about me.
But all these posts have one thing in common: They are for me. Every single post would eventually be written by me for me. What I mean is, that these topics are things I have a personal interest in. Let me make an example:

Comparison of Rails cloud hosting and deployment

There are quite many cloud hosting solutions for Ruby on Rails applications on the market. I don’t know very many. I know Heroku and some smaller ones, especially from Germany. But I don’t know which one would be the best choice for a specific project. One could look for differences in data security, location and other things. Group this in a table to make it easily accessible.
I would like to know this and read an article about it. You would probably be interested as well.
So you see: These topics are certainly interesting for a lot of people and would drive my traffic numbers upwards. But this is not the reason to write them. The reason is that I want to know this stuff. Other topics are about things I want to learn. Take a look into my archives. You will see that I write down, what I learn. Partly for me to reference in the future. But mostly to share my knowledge and help other people who might want to know this as well.

That’s what I mean when I say I am just like you. That is the reason I write my articles. I want to learn. I want you to learn. I want to share. And it’s just a lot of fun. People often use the end of the year to reflect on what they did during that year. For me it was a whole lot of things (I became a father of a wonderful little girl besides other things…). But one of these things was my desire to blog about what I learn and share it with the world. So that’s why I write, in a nutshell.

It’s your turn?

If you want to take a swing at one of my broader topics, here is the list. Please send me a link to your article when you are finished or need a second opinion/an editor.

List of topics

  • Comparison of Rails cloud hosting and deployment
  • Compare deployment with capistrano, vlad and mina
  • Authorization from scratch with puppet
  • Real world examples and stories about refactoring code (one can learn a ton from these)

If you write these, or find them online somewhere please tell me on Twitter (@5minpause).

Thank you for reading.

So, he doesn’t know this, huh?

You and I, we develop software. The things we create run inside browsers and on smartphones. They run on computers and on servers. They serve the need of some, and sometimes the needs of hundreds. Or thousands. Or, if we are lucky or have the right setting, millions use our software or parts of it. The systems we develop and write have many moving parts. They consist of a lot of different technologies. Depending on what you develop, you have to be a generalist, more than a specialist. But it depends.

Evolution

A thing that is the same no matter what you do is the constant evolution of our tools. On any given day I need at least two applications to do my job: a text editor (my choice is vim) and a browser. Most of my days I use emails to communicate with colleagues. I do development of frontend code for websites, I write code in Objective-C. I extend functionality for users or optimize older code in Ruby projects. I create command-line scripts or tools to optimize my workflow. I even use Photoshop (it came pre-installed with the Mac my employer gave me) to crop or manipulate images. I test my software and code in an array of various environments (Internet Explorers 6-10, Chrome, Firefox, Opera, Safari and MobileSafari, Windows and Mac OS, iOS and sometimes Android). These techonologies are just off the top of my head what I have to use on a day to day basis. Now as I said earlier: these tools and technologies are constantly evolving (yes, even you, Internet Explorer!). You have to keep up with the latest developments. You have to know these tools, even though you don’t need to know everything by heart. But you have to read up on the latest technology. You have to know how the latest public release of an operation system—millions of people use everyday—works. If you don’t read up on the latest developments in your chosen field, you fall behind. There are many many young developers who are eager to step into your shoes and do your work. There are many people who realize the opportunity of changing into a profession you chose yourself some years ago. These people have a need. They have a desire to become successful as a developer. They have a burning passion. And they will do what it takes to make their dreams come reality.

We’ve always done it this way

Sadly, the phrase “We’ve always done it this way.” is the worst thing you can use but it gets said way too often. Especially in a field where your tools evolve, you just cannot keep doing things the way you did them 10 years ago. I mean I get it. You are a seasoned developer. Your code stood the test of time. Your old C routines still run and you know how to do memory management on iOS ‘the old way’. Guess what: Thousands of other people do as well. But that doesn’t make it the best way. If all you have is a hammer, everything looks like a nail. Perhaps it’s time to head to the hardware store and acquire some other tools.

Resources

If you are keen on learning new stuff, broadening your horizont and trying new things I want to give you a small list of places to look for material and inspiration.

Blogs

Perhaps an obvious thing are blogs. I mean, you are reading one right now and I teach things. So you made the first step. A really good one I want to add. Here are some other blogs that I read myself and can recommend:

  • Giant robots smashing into other giant robots – Thoughbot is an agency doing Ruby and iOS contract work. They write about best practices in OO software design, testing and using your tools (e.g. vim) properly. And they have the best name for a blog.
  • Inessential.com – Brent Simmons is one of the good guys and one of the more experienced. But he doesn’t use the phrase “I’ve always done it this way.” He tries new stuff and writes about his experiences. Mostly iOS/Mac OS. Recently he has a series about synching between client/server.
  • Peter Steinberger – Peter blogs very infrequently about Objective-C. But when he writes a new post it is highly informative, technically demanding and really interesting. I don’t always understand everything he writes. It’s sometimes too low-level for me, but you can almost always take something away from it.
  • Dave Winer – Scripting News – Dave Winer invented RSS. And did many other great things. He writes about his learning about recent web technologies and his point of view on the world (of tech).
  • iOS App Dev Libraries – A collection of (new) libraries, controls and other open source software useful for iOS developers.
  • NSHipster – A journal of the overlooked bits in Objective-C and Cocoa.

Websites

These are no blogs but websites with regular articles and/or screencasts:

  • Practicing Ruby – Monthly lessons about software and Ruby things.
  • Ruby Tapas – Short screencasts for intermediate to advanced Ruby developers.
  • Vimcasts – Free screencasts about Vim. Drew Neil really has the most soothing screencast voice I’ve ever heard.
  • Railscasts – Over 400 screencasts about many things for Ruby on Rails developers. Currently on hiatus, but still worth it.
  • Objc.io – A high quality periodical about Objective-C/iOS.
  • Ray Wenderlich – He came out of nowhere some years ago and made many many many tutorials for iOS developers. Now he is one of THE best sources for beginners and advanced developers for all things Objective-C/iOS/Mac OS.
  • 24Ways – An advent calendar for web geeks. Each day throughout December you get something interesting about web dev and/or design. (Relevant since it’s Xmas soonish.)

Newsletters

You can get newsletters to almost every possible topic these days. Here are some that are relevant to developers:

  • iOSDevWeekly - Hand picked iOS development links with sections on News, Tools, Code, Design and Business.
  • Ruby Weekly – A free round-up of Ruby news and articles.
  • node weekly - A round-up of Node.js news and articles.
  • HTML5 Weekly – You guessed it: A round-up of HTML5 and browser technology news and links.

I could give you even more links to websites and blogs that teach stuff and have really interesting content, but this is supposed to be a rather short list. It is still really long I think and should give you a starting point for learning. Now you don’t have an excuse if you’re stuck with the old ways of doing things. Read, listen, watch and learn and then go out and teach others. The developers of tomorrow will thank you for it.

Thank you for reading.

Website analytics and statistics for Github repositories

If you use Github.com and have some popular repositories you might want to know where your traffic comes from. Github doesn’t offer anything to track visitors so you completely in the dark. The only way to track the popularity of your repository is to count the stargazers. This didn’t satisfy me.

Enter Bitdeli

If you search around the web for a solution you stumble upon Bitdeli. Bitdeli offers “Analytics for GitHub”. All you have to do is sign in with your Github account and authorize Bitdeli to access your repositories. They then fork your repo and send you a pull request. This pull request inserts a bitdeli.com badge into your repos readme file. With this badge they count your repositories visitors and track their origins. On the Bitdeli website you get a nice grahical overview for your repository and a timeline to track visitor count over a longer period. So this is a really quick and simple solution for this problem.

Use custom solution with Piwik

As I use Piwik for visitor statistics on this blog, I wanted to create my own solution to track my visitors. I use Piwik for counting my RSS subscribers (thanks to Felix Schwenzel(in german)) and now I use the same technique for my Github repository. Here’s how to do it:

  1. Go to your Settings -> Websites, click Add a new website

  2. Enter the appropriate settings for your repository

  3. Click ‘View Tracking Code’ Copy your image tracking code and insert it into your project’s readme file. This could look like this: You have to make sure the protocol is https for the link. Github changes http links and makes your image tracker link useless. The only way to make it work is to make sure you specify its url as https.

1
2
3
4
5
6
7
8
<!-- Piwik Image Tracker -->
<noscript>
<img src="https://yoursite.com/piwik/piwik.php?idsite=site-ID&rec=1" style="border:0" alt="" />
</noscript>
<!-- End Piwik -->

// Rest of Readme ommitted for brevity
// ...

Google Analytics

Unfortunately it seems as Google removed the option of image tracking codes for Google Analytics. If you browse their help sites, you come across a solution for older mobile phones.
This solution requires the use of PHP on your server. If that’s something you want to use (Why would you? It’s PHP!?) check out this link: Google Analytics for Mobile Websites. Then you can generate an image tracking url and place it inside an <img> tag like shown above. As I don’t use GA anymore I can’t show you how to do it. Why don’t you try using Piwik instead?

This wraps it up. Now you can go ahead and insert tracking codes for all your repositories. Thank you for reading.

Github repository

This time I don’t have a special Github repository to show you, but you can take a look at the README files in 5minpause/multiple-file-upload or 5minpause/pixelletter for inspiration.

Free programming books

Because one of my main themes for this blog is learning, I want to share with you a resource I just stumbled upon. It’s a collection of links to free programming books. The collection has its origin on stackoverflow but migrated to Github for collaborative updating. There are links to several languages available so you don’t necessarily read an English book. You can find the collection on Github.

Happy reading.

How to: HTML5 video that works on every browser

tldr;

HTML5 video sucks. Flash sucks. If you want to use HTML5 video anyway you should consider using a third party library. I suggest mediaelement.js.

Introduction

Integrating HTML5 video in your website and making it work in every browser (yes, Internet Explorer as well) still is no piece of cake. As I had the ‘pleasure’ of dealing with this task in the last weeks I want to write down what I found. There are some hoops you have to jump through, surprisingly even when dealing with a modern browser like Chrome. The only ‘just works’ solution seemed to be .mp4 files with Safari. But as I am on a Mac that might just be only my point of view. So let’s get this going one browser at a time.

Safari and mp4

Safari was really the easiest one for me. Just hand it a video file encoded with h.264 with results in a .mp4 video file and Safari will happily play it for you.
An example implementation might look like this:

1
2
3
<video id='video' autoplay controls>
  <source src='videos/my-file.mp4' />
</video>

Chrome and mp4/webm

Older versions of Chrome play .mp4 files just like Safari. Recently Chrome switched to .webm format by default. This means that you might be able to play your video file using Chrome. But some users might not. Welcome to the world of HTML5 video. Now you have to start making adjustments to cater for the individual browser your users have. You could do all that yourself, but you also could take a bath in ice water. Definitely not for everyone!

Libraries

There are several libraries out there to make your life easier. Some are open source and usable free of charge even on commercial projects. Others require you to buy a license. Gerrit van Aaken and Philip Bräunlich went all the way and created a nice chart of all major (and minor) contenders. So you can just choose which one fits your needs. You can find the HTML5 video comparison chart on the website praegnanz.de

I went with mediaelement.js. It’s a solution using jQuery that offers a Flash fallback. Yes that’s right, Flash. I actually envy the developers back in the day when all they had to do was implementing a Flash player. You either had Flash and it worked or you clicked the link and downloaded it. But today it’s supposed to be better, and I didn’t really like Flash anyway. But having a Flash fallback is useful when it comes to Interner Explorer < IE9. More on that later.

Chrome (again)

mediaelement.js doesn’t really help you with your Chrome problem though. I decided it’s best to assume that Chrome users are on auto-update and will get the latest Chrome version rather sooner than later. This might not be the case for every user and you might want to check for that situation. I recommend using Modernizr:

Modernizr and video format support

Modernizr is an open source, MIT-licensed JavaScript library that detects support for many HTML5 & CSS3 features.
(source: Dive into HTML5)

The linked website also tell you how to include it. So go ahead and click that link. We’ll use Modernizr to detect for HTML5 video support in your browser and also for the special formats your browser is able to play.

detect video formats link
1
2
3
4
5
6
7
8
9
10
if (Modernizr.video) {
  // let's play some video! but what kind?
  if (Modernizr.video.webm) {
    // try WebM
  } else if (Modernizr.video.ogg) {
    // try Ogg Theora + Vorbis in an Ogg container
  } else if (Modernizr.video.h264){
    // try H.264 video + AAC audio in an MP4 container
  }
}

Now let’s adjust the code to make Chrome play that .webm file.

adjust source for chrome
1
2
3
4
5
6
7
8
if (Modernizr.video) {
  if (Modernizr.video.webm) {
    // replace the DOM node <video> and replace it with itself but only with a .webm file as source
    $('#video').replaceWith("<video id='video' autoplay controls src='videos/my-file.webm'></video>");

    [...] // I cut the rest for brevity
  }
}

So now we should be able to play on Safari and Chrome. Please note, that you have to encode the video in .webm as well as in h.264 for this wo work properly.

Firefox

Firefox doesn’t like h.264 (.mp4) encoded video files. Firefox likes something different, namely .ogg/.ogv files. Thats why you have to encode your video in a third format. Otherwise Firefox is fairly simple to handle—at least inside your HTML/JS. (Firefox supposedly also plays .webm files but I found it works best with .ogg/.ogv video files. Your mileage may vary.)

adjust video sources for Firefox
1
2
3
4
<video id='video' autoplay controls>
  <source src='videos/my-file.mp4' type='video/mp4' />
  <source src='videos/my-file.ogg' type='video/ogv' />
</video>

Sometimes Firefox doesn’t want to play your video. There’s an error message that the MIME type isn’t supported: No Video with Supported Format and Mime Type Found
The solution is to register your content type inside an .htaccess file:

register MIME types
1
2
3
AddType audio/ogg .oga
AddType video/ogg .ogv
AddType application/ogg .ogg

Now we have basic support for three major browsers. So far we didn’t need any third party library. Why should we use it then? I like mediaelement.js for its support of mobile devices and its Flash fallback. I won’t go into detail how to setup mediaelement.js. You find a very extensive documentation on their website. On to Internet Explorer land!

Internet Explorer

(I never thought I would write these words on this website, but I just did…)
Recent versions of IE(9.0+) play h.264 encoded video and can even play .webm files with a little plugin. For everything earlier you should either use a picture instead of a video or you use Flash. Mediaelement.js provides you with a flash file you can include and link to from your website. Once you configure your player to use mediaelement.js this should work well for you.

setup flash fallback for IE
1
2
3
4
5
6
7
8
9
<video id='video' autoplay controls>
  <source src='videos/my-file.mp4' type='video/mp4' />
  <source src='videos/my-file.ogg' type='video/ogv' />
  /* data and value hold the path to your .swf file */
  <object width="1080" height="720" type="application/x-shockwave-flash" data="js/flashmediaelement.swf">
    <param name="movie" value="js/flashmediaelement.swf" />
    <param name="flashvars" value="controls=true&amp;autoplay=true&amp;file=videos/my-file.mp4" />
  </object>
</video>

Please note the html encoded ampersand (&) inside the flashvars. If you set the correct paths for your .swf and .mp4 files you are set and everything should work.

Mobile devices (iOS)

iOS devices play h.264 encoded mp4 video files just alright. mediaelement.js allows you to skin your player and use custom controls which might be necessary for your website.

Mobile devices (Android)

Android plays mp4 video files as well. If you followed the advice above for the different browsers everything should work for you on Android. There might be encoding issues which prevent playback though.

So that’s it. Your video should be able to play without further problems. These solutions worked for me. There might be different steps necessary for your particular setup and different audio/video encoding might hinder playback. Thanks for reading.

Not-invented-here vs. moving

You may have heard of ‘Not invented here’, or short NIH. NIH is called ‘not-invented-here-syndrome’ when used in relation to software development. It describes the fear or philosophy of not using already existing ideas or solutions to a problem. The reasons for that decision can be diverse. Some may think that existing solutions don’t really cover their needs. Others try to find a different solution to a problem than the ones that already exist. And some might just have other reasons. Or money. Money is always a good reason.

I usually try to use existing solutions. Be it ruby gems or software libraries for iOS projects. I find that open source software generally does what I need and I like to give back to OSS by using it and trying to enhance it. That’s why you find me writing here, and that’s why I try to open-source almost everything I code. And of course I like to concentrate on creating new and interesting things and solutions to actual business problems instead of reinventing the wheel.

Short detour: I recently moved into a new appartment. My girlfriend and I decided to do the packing and moving ourselves. We enlisted some family and friends to help us carry all the boxes and furniture onto the truck and into the new appartment. My co-workers asked me why I decided to do this myself. They would surely use a company for that. That got me thinking. There are obviously some similarities between NIH and my move.

This move was my 4th move in my adult life. I did all of them the same way – with family and friends. I know what to expect and I actually find some joy in moving when everything just works and you get over with it quickly. To sum it up: I am fast, well organized, know exactly what I want and how I want it. A company makes nothing better – only differently.

This stands in stark contrast to my attitude towards NIH. Here I intentionally decided against a ‘good enough’ solution and tried to ‘roll my own’. Why was that?
Well I believe I couldn’t gain anything by using a company and wasn’t off worse by doing everything myself. So I chose a solution that resulted in ‘having a good time with friends and family’ (sort of). At certain points throughout the day (washing machine!) I actually cursed myself and swore to the heavens that I would get a company to do it next time. But at least I learned something that day:
Don’t judge to quickly if some people try to do everything themselves. It is not neccessarily NIH that drives them to that decision. It might just be because it’s fun to them and the actually really enjoy doing it – and because of all the reasons above.

PS: I actually learned two thing that day. The second one is that when you are over thirty, your body needs more than two days to recover from ‘great ideas’ like carrying a washing machine.

Multiple file upload with jQuery, Rails 4 and Paperclip

In a recent project I needed a convenient file uploader. I wanted multiple file upload and progress bars. I wanted everything to work well together with Bootstrap. I needed jQuery File Upload. On first look it didn’t seem to be trivial to include and after a search I found that Ryan Bates did a railscast on jQuery file upload. Unfortunately this railscast used Rails 3 and an older jQuery version. So I had to tweak it. Other blogposts about the topic are from 2012 or older, so here is the new Rails 4 version.

We don’t live inside a vacuum and constantely use pre-existing ideas (everything is a remix. So I didn’t try to come up with a completely original solution. My implementation below is based on Ryans work.

Update: I created a Github repository for this article. You can use it as a fully working copy of everything that I used for this article. I used the commits to follow along the blog post so you can use them to ‘replay’ my implementation. If you have any questions please open an issue on Github.com and ask over there as I don’t have any comments on this blog. Thank you.

Gem and assets

We start with the Gemfile and add the jquery-fileupload-rails gem.

Gemfile
1
gem 'jquery-fileupload-rails'

Install your gem with bundle install.

After installing you need to include the javascripts in your application.js:

application.js
1
2
3
4
5
//= require jquery
//= require jquery_ujs
//= require jquery-fileupload/basic
//= require jquery-fileupload/vendor/tmpl
//= require_tree .

We use the basic version here and include the jquery-fileupload/vendor/tmpl so we have the option to render our own template.

The view

We have a form which we use to upload files and include the javascript template at the bottom of the file. One thing to note: The template script has to be a one-liner without line breaks or whitespace. Otherwise jQuery will complain: Uncaught Syntax error, unrecognized expression: [object Object]. Another solution is to use $.parseHTML();. I’ll show you how to do that inside the uploads.js.coffee further down.

show.html.erb
1
2
3
4
5
6
7
8
<%= form_for Upload.new, :url => uploads_path, html: { multipart: true } do |f| %>
  <%= f.label :uploaded_file, t('.upload_new_file') %>
  <%= f.file_field :uploaded_file, multiple: true, name: 'upload[uploaded_file]' %>
  <%= f.submit t(:save), class: 'btn' %>
<% end %>

<% # jquery upload template # %>
<script id="template-upload" type="text/x-tmpl"><div class="upload">{%=o.name%}<div class="progress"><div class="bar" style="width: 0%"></div></div></div></script>

We return javascript so here is the file to render after a successful :create

create.js.erb
1
2
3
4
5
<% if @upload.new_record? %>
  alert('Failed');
<% else %>
  $('ul.thumbnails').append("<%=j render partial: 'photosets/upload', locals: { upload: @upload } %>");
<% end %>

When you click submit to upload your pictures what actually happens is a multiple submit for every picture you upload. Now we need to handle these submits. We do that inside a coffeescript file:

upload.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
jQuery ->
  $('#upload_uploaded_file').attr('name','upload[uploaded_file]')
  $('#new_upload').fileupload
    dataType: 'script'
    add: (e, data) ->
      types = /(\.|\/)(gif|jpe?g|png|mov|mpeg|mpeg4|avi)$/i
      file = data.files[0]
      if types.test(file.type) || types.test(file.name)
        data.context = $(tmpl("template-upload", file))
        $('#new_upload').append(data.context)
        data.submit()
      else
        alert("#{file.name} is not a gif, jpg or png image file")
    progress: (e, data) ->
      if data.context
        progress = parseInt(data.loaded / data.total * 100, 10)
        data.context.find('.bar').css('width', progress + '%')

What happens here is that we check the file’s type to be either a picture or a movie. Otherwise we show the user an alert that this file is not allowed. If the file is allowed we render the template with the file’s data and append it to our list of pictures (not shown in code here - you can easily figure that one out). Then we submit the file to actually upload and save it to the database. Additionally we show a progress bar for each uploaded file.

Line 2 in upload.js.coffee serves the purpose to change the name of the uploaded_file from an array to a single upload (from upload[uploaded_file][] to upload[uploaded_file]). Otherwise you try to upload an array and that makes Paperclip throw an error Paperclip::AdapterRegistry::NoHandlerError. You can set the value with the name attribute for the file_field but that did not work realiably for me.

I wrote before that you have to avoid line breaks inside your template. If you change line 9 to this

upload.js.coffee
1
  data.context = $($.parseHTML($(tmpl("template-upload", file)))[1])

you can supposedly keep your line breaks. I found this on stackoverflow but haven’t tried it. But it looks okay.

The controller action is really simple:

uploads_controller.rb
1
2
3
def create
  @upload = Upload.create(upload_params)
end

And that wraps it up. This is a simple implementation. You could much more. Have a look at jQuery File Upload’s documentation. If you have any questions ask me on twitter or app.net and I am happy to help. Thanks for reading.

Exercism.io: Talk and learn about programming languages and code.

I stumbled upon exercism.io this morning. I believe Twitter showed me the way. Exercism.io describes itself this way:

The goal of exercism is to think deeply about simple, expressive, readable code.

Now if you are like me you like to code and you like to learn how to get better at coding. Sometimes I try to learn from blog posts I find or from stackoverflow questions and their answers. I think these are really good ways and will bring you a long way. At least that’s my hope and that’s why I am writing things on this website.
From time to time it’s important that you test your knowledge and challenge yourself. There are some programming challenges. I will write about the Matasano Crypto Challenges another time. What’s missing with these challenges is the communication about code. Writing code should be about communicating your thoughts and intentions in a way that the computer and other programmers understand what your meaning and intention was when you wrote that code. But there are only so many variable names you can think of and sometimes it’s just important to discuss about implementation details and their consequences. That’s why pair programming is so great. You are constantely being challenged and you have to think deeply about how and why to do things. Then you have to explain your thoughts to your pair. They say that you only really understood something if you can explain it to somebody else.
Exercism.io encourages you to do exactly that. This is how it works:

  • You register on their website (link with your Github.com profile)
  • install the ruby gem
  • download your first set of exercises

You set up a download folder and receive the first exercise in 6 different languages %(closure elixir haskell javascript python ruby). It’s totally up to you to choose your language. So this is a great way of learning or trying out a new language.

The exercise consists of a file with failing test cases. You are encouraged to run your test suite (it’s as easy as running ruby bob-test.rb). Your tests are failing and you get a first helpful hint how to change the code or what to do to get that test to pass. Then you work your way through all thests until everything passes. this way exercism.io encourages test driven development. Even if you are new to tests and TDD it shouldn’t be a problem. You don’t have to write your own tests (at least not that I am aware of).
It took me about 5 minutes for the first exercise. But that is only the first step.
The exercise is set up in a way that makes it easy to find a solution. But this is really only the beginning. Now you upload your solution and describe what made you choose this solution, what your thoughts were. You don’t have to write anything but it certainly makes you think about your solution and implementation.

When you uploaded your solution you get to see each iteration. This makes it clear that you shouldn’t see your first draft as final. You can upload a refined solution as many times as you want to. Others can then look at your iterations to see what you changed.
I actually had some UI/UX problems with the website and didn’t know how to proceed so I marked my solution as final even though it wasn’t. But I guess you won’t have the same problem.

After you uploaded your exercise you get to take a look at the implementation of other participants. And you are invited to comment on their code. Ask them questions. Learn from them. Ask yourself why they did it that way. Exercism.io calls this ‘nitpicking’ and it certainly is. But the tone is friendly and I couldn’t find any trolling while looking aaround. Unfortunately I had to take a picture from the website as you can only use it if you are logged in/connected with Github.

So go ahead and try it out. I’d love for anyone to send me links to their exercises. I’d really like to nitpick your code. :D