act_as_newbie

Keeping a newbie mindset, at all times.

Nginx + Upload Module and Carrierwave

| Comments

Last night was a really long one. Why? Because I couldn’t find enough information on how to make nginx handle uploads (using upload module and upload progress) and include carrierwave on the equation to handle files after they have been sent to the server.

Maybe I didn’t search enough, maybe I found only the old deprecated stuff, but after compiling these sources I think I came up with a decent solution.

First off, let’s compile nginx with some upload sugar.

1
2
3
4
5
6
7
8
9
10
11
12
cd /tmp

wget http://nginx.org/download/nginx-1.1.14.tar.gz
tar -zxvf nginx-1.0.14.tar.gz

wget http://www.grid.net.ru/nginx/download/nginx_upload_module-2.2.0.tar.gz
tar -zxvf nginx_upload_module-2.2.0.tar.gz

cd nginx-1.0.14
./configure --prefix=/usr/local/nginx-1.1.14 --with-http_ssl_module --with-http_gzip_static_module --conf-path=/etc/nginx/nginx.conf --add-module=../nginx_upload_module-2.2.0/
make
sudo make install

So the module is there, we need to make it come to life in nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
http {
  # ... A lot of stuff
  server {

    # This will be our route on our rails app
    location /videos/upload {
      # app_server is the unicorn upstream
      proxy_pass http://app_server;

      # @app is the unicorn upstream proxy location
      upload_pass @app;

      upload_store /web_apps/mysite/shared/uploads/tmp 1;

       # set permissions on the uploaded files
      upload_store_access user:rw group:rw all:r;

      # Set specified fields in request body
      upload_set_form_field $upload_field_name[original_filename] "$upload_file_name";
      upload_set_form_field $upload_field_name[content_type] "$upload_content_type";
      upload_set_form_field $upload_field_name[path] "$upload_tmp_path";

      upload_pass_form_field "^X-Progress-ID$|^authenticity_token$";
      upload_cleanup 400 404 499 500-505;
    }
}

This is from a server using unicorn to serve the rails app, if you need some help getting started with nginx and unicorn this is a good place to start. And I really recommend that you read upload module’s docs carefully.

The important bits are the ones starting with “upload”. The way it works is upload_pass routes the request to the @app location after the upload has finished it’ll pass the form fields you set with upload_pass_form_field along with the ones we’ll be using to show the file to carrierwave.

Now restart nginx and you’re good to go. #NOT

As soon as you try to upload anything nginx will complain about permissions or directories it could not found so lets fix that.

I’m using 1 level deep directory hashing (set on upload store) so I’ll have to manually create the directory structure and chown it to the user that runs nginx workers (in my case is rafa:rafa).

1
2
3
cd /web_apps/mysite/shared/uploads/tmp
mkdir 0 1 2 3 4 5 6 7 8 9
sudo chown -R rafa:rafa /web_apps/mysite/shared/uploads/tmp

Now to your rails app. I’m using mongoid, but this applies to any orm.

video.rb
1
2
3
4
5
6
7
8
9
10
11
class Video
  include Mongoid::Document

  # ...

  field :raw_file, :type => String
  mount_uploader :raw_file, VideoUploader

  # ...

end

Lets create the route to recieve the request after the upload is handled by nginx.

routes.rb
1
  match "/videos/upload/", as: "upload_videos", controller: "videos", action: "upload", via: :post

And the action to save it.

videos_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def upload
  @video = Video.build(params[:video])

  # Production/staging only, development will go the carrierwave way.
  if Rails.env != "development"
    @video.raw_file = ActionDispatch::Http::UploadedFile.new(
      filename: params['video']['raw_file']['original_filename'],
      tempfile: File.open(params['video']['raw_file']['path'])
    )
    @video.name = params['video']['raw_file']['original_filename'].chomp(".raw")
  else
    @video.name = params['video']['raw_file'].original_filename.chomp(".raw")
  end

  @video.save!
  render :json => @video
end

The trick here is to simulate a ActionDispatch::Http::UploadedFile being passed to carrierwave.

This will send the file to the right place, but I still have some quirks to solve. Like the temporary dir cleanup task and the content_type validation. Once I get the hang of those I’ll update this post.

Client_side_validations and Dynamic Nested Forms

| Comments

Last week I found a little caveat when using the client_side_validations gem with ajax-loaded forms. It didn’t work out of the box.

Digging through the sourcecode I found this comment

rails.validations.js
1
2
3
4
  // Main hook
  // If new forms are dynamically introduced into the DOM the .validate() method
  // must be invoked on that form
  $(function () { $('form[data-validate]').validate(); });

Ok, so I called $("#my-form").validate() on ajax:success and everything was fine! Except it wasn’t =/

The behavior I understood, after banging my head against the wall several times was: if the form was entirely rendered in my ajax call it would validate ok, but if I added some fields inside it dynamically then I’d start getting those nasty validators is not defined errors and everything would go boom!

So how do I add some fields to the form and keep them “validatable”? this issue gave me some insight. And after rummaging the code a little more I found that this gem registers the validators in the window object. This process is done inside the form renderer, and that’s why the full rendered forms worked and adding just some of the fields did not. To accomplish that I created this helper

1
2
3
4
5
6
7
8
9
  def add_dynamic_validators(builders)
    result = ""
    builders.each do |builder|
      builder.object.client_side_validation_hash.each do |validator|
        result += "window[form_id].validators['#{builder.object_name}[#{validator[0]}]'] = #{validator[1].to_json};\n"
      end
    end
    result.html_safe
  end

It recieves an array of form builders and inspect it for the validators added by the gem. Then it prints the resulting instruction within the form partial, inside a function, to which I pass the id of the form that I want to validate.

1
2
3
4
  function update_dynamic_fields(form_id)
  {
    <%= add_dynamic_validators builders %>
  }

Then after the fields (with the script block) were added the to form you can call

1
2
  var $form = $("#my-form");
  update_dynamic_fields($form.attr("id"));

I know this is hacky as hell, but with this I was able to keep using this gem even inside pages with lots of moving parts.

ICanHaz Templates - Dealing With the Lack of Dot Notation

| Comments

[UPDATE: 30/10/2011] According to this issue we now have dot notation in moustache.js! Yay!

The ICanHaz javascript templating system is just awesome. It is really simple, and powerful, BUT as all good things in life it’s not perfect! ICanHaz is built on top of moustache.js that, on his part, is a javascript implementation of the moustache templates. Originally the moustache implementation didn’t support dot notation for accessing nested objects. Like for instance

1
2
3
4
5
6
7
8
    var post = {
      title : "Post title",
      body : "post body",
      author : {
        name : "Rafael Barbosa",
        age : 26
      }
    };

Normally you can access the author’s name in my js files via dot notation like post.author.name, but until this commit this wasn’t possible within moustache’s templates and it still isn’t supported by the javascript implementation. So how can I access nested objects? The same way you iterate over arrays!

For the post object above, inside an ICanHaz template

And that’ll do it. There’s an open issue on the moustache.js github for the inclusion of the dot notation.

Show Hierarchical Data Using Recursive Partials

| Comments

Yesterday I needed to show a deep nested tree in a view. The first solution that crossed my mind was something along the lines of a recursive helper like this one.

1
2
3
4
5
6
7
8
9
10
11
12
def display_tree_recursive(tree, parent_id)
  ret = "<ul>"
  tree.each do |node|
    if node.parent_id == parent_id
      ret += "<li>"
      ret += link_to node.title
      ret += display_tree_recursive(tree, node.id)
      ret += "</li>"
    end
  end
  ret += "</ul>"
end

That’s ok for simple ul-li pairs but I needed much more markup since my task was to show this information as nested accordions. Wouldn’t it be better if I could define a partial and call it from inside itself passing the children as its locals variables? Guess what? It works just like that! =)

In the index view

1
2
3
4
5
6
7
8
9
10
11
12
<ul class="accordion">
    <% @sections.each do |section| %>
      <li>
        <h3><%= section.name %></h3>
        <div class="accordion-content">
          <ul class="accordion">
            <%= render "section/section_children", :section => section %>
          </ul>
        </div>
      </li>
    <% end %>
  </ul>

That section/section_children partial is the trick. Inside it we have

1
2
3
4
5
6
7
8
9
10
<% section.children.each do |child| %>
  <li>
    <h3 ><a href="#" class="header"><%= child.name %></a></h3>
      <div class="accordion-content">
        <ul class="accordion">
          <%= render "section/section_children", :section => child %>
        </ul>
      </div>
  </li>
<% end %>

and that’s it!

Starting Things Up

| Comments

Time to start sharing whatever knowledge comes my way! This will be the first post on this blog and I hope many will follow. I’ll mainly talk about Rails and its fellas, so if that’s your thing stick around!