Advertisement
Ruby

How to Upload Files with Ease Using DragonFly

by

File uploads are generally a tricky area in web development. In this tutorial, we will learn how to use Dragonfly, a powerful Ruby gem that makes it easy and efficient to add any kind of upload functionality to a Rails project.


What We're Going to Build

Our sample application will display a list of users, and for each one of them, we will be able to upload an avatar and have it stored. Additionally, Dragonfly will allow us to:

  • Dynamically manipulate images without saving additional copies
  • Leverage HTTP caching to optimize our application load

In this lesson, we will follow a BDD [Behavior Driven Development] approach, using Cucumber and RSpec.


Prerequisites

You'll need to have Imagemagick installed: you can refer to this page for the binaries to install. As I am based on a Mac platform, use Homebrew, I can simply type brew install imagemagick.

You will also need to clone a basic Rails application that we will use as a starting point.


Setup

We will begin by cloning the starting repository and setting up our dependencies:

git clone http://cloud8421@github.com/cloud8421/tutorial_dragonfly_template.git 
cd tutorial_dragonfly_template

This application requires at least Ruby 1.9.2 to run, however, I encourage you to use 1.9.3. The Rails version is 3.2.1. The project does not include a .rvmrc or a .rbenv file.

Next, we run:

bundle install 
bundle exec rake db:setup db:test:prepare db:seed

This will take care of the gem dependencies and database setup (we will be using sqlite, so no need to worry about database config).

To test that everything is working as expected, we can run:

bundle exec rspec 
bundle exec cucumber

You should find that all tests have passed. Let's review Cucumber's output:

 
Feature: managing user profile 
  As a user 
  In order to manage my data 
  I want to access my user profile page 
 
  Background: 
    Given a user exists with email "email@example.com" 
 
  Scenario: viewing my profile 
    Given I am on the home page 
    When I follow "Profile" for "email@example.com" 
    Then I should be on the profile page for "email@example.com" 
 
  Scenario: editing my profile 
    Given I am on the profile page for "email@example.com" 
    When I follow "Edit" 
    And I change my email with "new_email@example.com" 
    And I click "Save" 
    Then I should be on the profile page for "email@example.com" 
    And I should see "User updated" 
 
2 scenarios (2 passed) 
11 steps (11 passed) 
0m0.710s

As you can see, these features describe a typical user workflow: we open a user page from a list, press "Edit" to edit the user data, change the email, and save.

Now, try running the app:

rails s

If you open http:://localhost:3000 in the browser, you will find a list of users (we pre-populated the database with 40 random records thanks to the Faker gem).

For now, each one of the users will have a small, 16x16px avatar and a big placeholder avatar in their profile page. If you edit the user, you will be able to change its details (first name, last name and password), but if you try to upload an avatar, it will not be saved.

Feel free to browse the codebase: the application uses Simple Form to generate form views and Twitter Bootstrap for CSS and layout, as they integrate perfectly and help a lot in speeding up the prototyping process.


Features for Avatar Upload

We will start by adding a new scenario to features/managing_profile.feature:

 
... 
Scenario: adding an avatar 
  Given I am on the profile page for "email@example.com" 
  When I follow "Edit" 
  And I upload the mustache avatar 
  And I click "Save" 
  Then I should be on the profile page for "email@example.com" 
  And the profile should show "the mustache avatar"

This feature is fairly self-explanatory, but it requires a few additional steps to add to features/step_definitions/user_steps.rb:

 
... 
When /^I upload the mustache avatar$/ do 
  attach_file 'user[avatar_image]', Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
end 
 
Then /^the profile should show "([^"]*)"$/ do |image| 
  pattern = case image 
  when 'the mustache avatar' 
    /mustache_avatar/ 
  end 
  n = Nokogiri::HTML(page.body) 
  n.xpath(".//img[@class='thumbnail']").first['src'].should =~ pattern 
end

This step assumes that you have an image, called mustache_avatar.jpg inside spec/fixtures. As you might guess, this is just an example; it can be anything you want.

The first step uses Capybara to find the user[avatar_image] file field and upload the file. Note that we're assuming that we will have a an avatar_image attribute on the User model.

The second step uses Nokogiri (a powerful HTML/XML parsing library) and XPath to parse the content of the resulting profile page and search for the first img tag with a thumbnail class and test that the src attribute contains mustache_avatar.

If you run cucumber now, this scenario will trigger an error, as there is no file field with the name we specified. It's now time to focus on the User model.


Adding Dragonfly Support to the User Model

Before integrating Dragonfly with the User model, let's add a couple of specs to user_spec.rb.

We can append a new block right after the attributes context:

 
context "avatar attributes" do 
 
  it { should respond_to(:avatar_image) } 
 
  it { should allow_mass_assignment_of(:avatar_image) } 
 
end

We test that the User has a avatar_image attribute and, as we will be updating this attribute through a form, it needs to be accessible (second spec).

Now we can install Dragonfly: by doing that, we will get these specs to go green.

Let's add the following lines to the Gemfile:

 
gem 'rack-cache', require: 'rack/cache' 
gem 'dragonfly', '~>0.9.10'

Next, we can run bundle install. Rack-cache is needed in development, as it's the simplest option to have HTTP caching. It can be used in production as well, even if more robust solutions (like Varnish or Squid) would be better.

We also need to add the Dragonfly initializer. Let's create the config/initializers/dragonfly.rb file and add the following:

 
require 'dragonfly' 
 
app = Dragonfly[:images] 
app.configure_with(:imagemagick) 
app.configure_with(:rails) 
 
app.define_macro(ActiveRecord::Base, :image_accessor)

This is the vanilla Dragonfly configuration: it sets up a Dragonfly application and configures it with the needed module. It also adds a new macro to ActiveRecord that we will be able to use to extend our User model.

We need to update config/application.rb, and add a new directive to the configuration (right before the config.generators block):

 
config.middleware.insert 0, 'Rack::Cache', { 
  verbose: true, 
  metastore: URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), 
  entitystore: URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body") 
} unless Rails.env.production? 
 
config.middleware.insert_after 'Rack::Cache', 'Dragonfly::Middleware', :images

Without going into much detail, we are setting up Rack::Cache (except for production, where it's enabled by default), and setting up Dragonfly to use it.

We will store our images on disk, however, we need a way to track the association with a user. The simplest option is to add two columns to the user table with a migration:

rails g migration add_avatar_to_users avatar_image_uid:string avatar_image_name:string 
bundle exec rake db:migrate db:test:prepare

Once again, this is straight from Dragonfly's documentation: we need to have a avatar_image_uid column to uniquely identify the avatar file and a avatar_image_name to store its original filename (the latter column is not strictly needed, but it enables the generation of image urls that end with the original filename).

Finally, we can update the User model:

 
class User < ActiveRecord::Base 
 
  image_accessor :avatar_image 
 
  attr_accessible :email, :first_name, :last_name, :avatar_image 
  ...

The image_accessor method is made available by the Dragonfly initializer, and it requires just an attribute name. We also make the same attribute accessible in the line below.

Running rspec now should show all specs green.


Uploading and Displaying the Avatar


To test the upload function, we can add a context to users_controller_spec.rb in the PUT update block:

 
context "avatar image" do 
 
  let!(:image_file) { fixture_file_upload('/mustache_avatar.jpg', 'image/jpg') } 
 
  context "uploading an avatar" do 
 
    before do 
      put :update, id: user.id, user: { avatar_image: image_file } 
    end 
 
    it "should effectively save the image record on the user" do 
      user.reload 
      user.avatar_image_name.should =~ /mustache_avatar/ 
    end 
 
  end 
 
end

We will reuse the same fixture and create a mock for the upload with fixture_file_upload.

As this functionality leverages on Dragonfly, we don't need to write code to get it passing.

We now have to update our views to show the avatar. Let's start from the user show page and open app/views/users/show.html.erb and update it with the following content:

 
<div class="row"> 
<div class="span4"> 
    <% if @user.avatar_image.present? %> 
      <%= image_tag @user.avatar_image.url, class: 'thumbnail' %> 
    <% else %> 
      <img src="http://placehold.it/400x400&amp;text=Super+cool+avatar" alt="Super cool avatar" class="thumbnail"> 
    <% end %> 
  </div> 
  <div class="span8"> 
    <hr /> <h2><%= @user.name  %></h2> 
    <h4><%= @user.email %></h4> 
    <hr /> 
    <%= link_to 'Edit', edit_user_path(@user), class: "btn" %> 
  </div> 
</div>

Next, we can update app/views/users/edit.html.erb:

 
<%= simple_form_for @user, multipart: true do |f| %>  
<div class="row"> 
  <div class="span4"> 
    <div class="thumbnail-wrapper"> 
      <% if @user.avatar_image.present? %> 
        <%= image_tag @user.avatar_image.url, class: 'thumbnail' %> 
      <% else %> 
        <img src="http://placehold.it/400x400&amp;text=Super+cool+avatar" alt="Super cool avatar" class="thumbnail"> 
      <% end %> 
      <div class="caption form-inline"> 
        <%= f.input :avatar_image, as: :file %> 
      </div> 
    </div> 
  </div> 
  <div class="span8"> 
    <div class="well"> 
      <%= f.input :first_name %> 
      <%= f.input :last_name %> 
      <%= f.input :email %> 
    </div> 
    <div class="form-actions"> 
      <%= f.submit 'Save', class: "btn btn-primary" %> 
    </div> 
  </div> 
</div> 
<% end %>

We can show the user avatar with a simple call to @user.avatar_image.url. This will return a url to a non-modified version of the avatar uploaded by the user.

If you run cucumber now, you'll see the green feature. Feel free to try it out in the browser too!

We're implicitly relying on CSS to resize the image if it's too big for its container. It's a shaky approach: our user could upload non-square avatars, or a very small image. In addition, we're always serving the same image, without too much concern for page size or bandwidth.

We need to work on two different areas: adding some validation rules to the avatar upload and specifying image size and ratio with Dragonfly.


Upload Validations

We will start by opening the user_spec.rb file and adding a new spec block:

 
context "avatar attributes" do 
 
  %w(avatar_image retained_avatar_image remove_avatar_image).each do |attr| 
    it { should respond_to(attr.to_sym) } 
  end 
 
  %w(avatar_image retained_avatar_image remove_avatar_image).each do |attr| 
    it { should allow_mass_assignment_of(attr.to_sym) } 
  end 
 
  it "should validate the file size of the avatar" do 
    user.avatar_image = Rails.root + 'spec/fixtures/huge_size_avatar.jpg' 
    user.should_not be_valid # size is > 100 KB 
  end 
 
  it "should validate the format of the avatar" do 
    user.avatar_image = Rails.root + 'spec/fixtures/dummy.txt' 
    user.should_not be_valid 
  end 
 
end

We are testing for presence and are allowing "mass assignment" for additional attributes that we will use to enhance the user form (:retained_avatar_image and :remove_avatar_image).

In addition, we are also testing that our user model will not accept big uploads (more than 200 KB) and files that are not images. For both cases, we need to add two fixture files (an image with the specified name and whose size is more than 200 KB and a text file with any content).

As usual, running these specs will not get us to green. Let's update the user model to add those validation rules:

 
... 
 
attr_accessible :email, :first_name, :last_name, :avatar_image, :retained_avatar_image, :remove_avatar_image 
 
... 
 
validates_size_of :avatar_image, maximum: 100.kilobytes 
 
validates_property :format, of: :avatar_image, in: [:jpeg, :png, :gif, :jpg] 
 
validates_property :mime_type, of: :avatar_image, 
                               in: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'], 
                               case_sensitive: false

These rules are fairly effective: note that, in addition to checking the format, we also check the mime type for better safety. Being an image, we allow jpg, png and gif files.

Our specs should be passing now, so it's time to update the views to optimize the image load.


Dynamic Image Processing

By default, Dragonfly uses ImageMagick to dynamically process images when requested. Assuming we have a user instance in one of our views, we could then:

 
user.avatar_image.thumb('100x100').url 
user.avatar_image.process(:greyscale).url

These methods will create a processed version of this image with a unique hash and thanks to our caching layer, ImageMagick will be called just once per image. After that, the image will be served directly from cache.

You can use many built-in methods or simply build your own, Dragonfly's documentation has got plenty of examples.

Let's revisit our user edit page and update the view code:

 
... 
<% if @user.avatar_image.present? %> 
  <%= image_tag @user.avatar_image.thumb('400x400#').url, class: 'thumbnail' %> 
<% else %> 
...

We'll do the same for the user show page:

 
... 
<% if @user.avatar_image.present? %> 
  <%= image_tag @user.avatar_image.thumb('400x400#').url, class: 'thumbnail' %> 
<% else %> 
...

We're forcing the image size to 400 x 400 pixels. The # parameter also instructs ImageMagick to crop the image keeping a central gravity. You can see that we have the same code in two places, so let's refactor this into a partial called views/users/_avatar_image.html.erb

 
<% if @user.avatar_image.present? %> 
  <%= image_tag @user.avatar_image.thumb('400x400#').url, class: 'thumbnail' %> 
<% else %> 
  <img src="http://placehold.it/400x400&amp;text=Super+cool+avatar" alt="Super cool avatar" class="thumbnail"> 
<% end %>

Then we can replace the content of the .thumbnail container with a simple call to:

 
<div class="thumbnail"> 
  <%= render 'avatar_image' %> 
</div>

We can do even better by moving the argument of thumb out of the partial. Let's update _avatar_image.html.erb:

 
<% if user.avatar_image.present? %> 
  <%= image_tag user.avatar_image.thumb(args).url %> 
<% else %> 
  <img src="http://placehold.it/<%= args.gsub(/\W/, '') %>&amp;text=Super+cool+avatar" alt="Super cool avatar"> 
<% end %>

We can now call our partial with two arguments: one for the desired aspect and one for the user:

 
<%= render 'avatar_image', args: '400x400#', user: @user %>

We can use the snippet above in edit and show views, while we can call it in the following way inside views/users/_user_table.html.erb, where we are showing the small thumbnails.

 
... 
<td><%= link_to 'Profile', user_path(user) %></td> 
<td> 
  <%= render 'avatar_image', args: '16x16#', user: user %> 
</td> 
<td><%= user.first_name %></td> 
...

In both cases, we also perform a Regex on the aspect to extract a string compatible with the placehold.it service (i.e. removing non alphanumerical characters).


Removing the Avatar


Dragonfly creates two additional attributes that we can use in a form:

  • retained_avatar_image: this stores the uploaded image between reloads. If validations for another form field (say email) fail and the page is reloaded, the uploaded image is still available without need to reupload it. We will use it directly in the form.
  • remove_avatar_image: when it's true, the current avatar image will be deleted both from the user record and disk.

We can test the avatar removal by adding an additional spec to users_controller_spec.rb, in the avatar image block:

 
... 
context "removing an avatar" do 
 
  before do 
    user.avatar_image = Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
    user.save 
  end 
 
  it "should remove the avatar from the user" do 
    put :update, id: user.id, user: { remove_avatar_image: "1" } 
    user.reload 
    user.avatar_image_name.should be_nil 
  end 
 
end 
...

Once again, Dragonfly will get this spec to pass automatically as we already have the remove_avatar_image attribute available for the user instance.

Let's then add another feature to managing_profile.feature:

 
Scenario: removing an avatar 
  Given the user with email "email@example.com" has the mustache avatar 
  And I am on the profile page for "email@example.com" 
  When I follow "Edit" 
  And I check "Remove avatar image" 
  And I click "Save" 
  Then I should be on the profile page for "email@example.com" 
  And the profile should show "the placeholder avatar"

As usual, we need to add some steps to user_steps.rb and update one to add a Regex for the placeholder avatar:

 
Given /^the user with email "([^"]*)" has the mustache avatar$/ do |email| 
  u = User.find_by_email(email) 
  u.avatar_image = Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
  u.save 
end 
 
When /^I check "([^"]*)"$/ do |checkbox| 
  check checkbox  
end 
 
Then /^the profile should show "([^"]*)"$/ do |image| 
  pattern = case image 
  when 'the placeholder avatar' 
    /placehold.it/ 
  when 'the mustache avatar' 
    /mustache_avatar/ 
  end 
  n = Nokogiri::HTML(page.body) 
  n.xpath(".//img[@class='thumbnail']").first['src'].should =~ pattern 
end

We need also to add two additional fields to the edit form:

 
... 
<div class="caption form-inline"> 
  <%= f.input :retained_avatar_image, as: :hidden %> 
  <%= f.input :avatar_image, as: :file, label: false %> 
  <%= f.input :remove_avatar_image, as: :boolean %> 
</div> 
...

This will get our feature to pass.


Refactoring Features

To avoid having a large and too detailed feature, we can test the same functionality in a request spec.

Let's create a new file called spec/requests/user_flow_spec.rb and add this content to it:

 
require 'spec_helper' 
 
describe "User flow"  do 
 
  let!(:user) { Factory(:user, email: "email@example.com") } 
 
  describe "viewing the profile" do 
 
    it "should show the profile for the user" do 
      visit '/' 
      page.find('tr', text: user.email).click_link("Profile") 
      current_path = URI.parse(current_url).path 
      current_path.should == user_path(user) 
    end 
 
  end 
 
  describe "updating profile data" do 
 
    it "should save the changes" do 
      visit '/' 
      page.find('tr', text: user.email).click_link("Profile") 
      click_link 'Edit' 
      fill_in :email, with: "new_email@example.com" 
      click_button 'Save' 
      current_path.should == user_path(user) 
      page.should have_content "User updated"  
    end 
 
  end 
 
  describe "managing the avatar" do 
 
    it "should save the uploaded avatar" do 
      user.avatar_image = Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
      user.save 
      visit user_path(user) 
      click_link 'Edit' 
      attach_file 'user[avatar_image]', Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
      click_button 'Save' 
      current_path.should == user_path(user) 
      page.should have_content "User updated" 
      n = Nokogiri::HTML(page.body) 
      n.xpath(".//img[@class='thumbnail']").first['src'].should =~ /mustache_avatar/ 
    end 
 
    it "should remove the avatar if requested" do 
      user.avatar_image = Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
      user.save 
      visit user_path(user) 
      click_link 'Edit' 
      check "Remove avatar image" 
      click_button 'Save' 
      current_path.should == user_path(user) 
      page.should have_content "User updated" 
      n = Nokogiri::HTML(page.body) 
      n.xpath(".//img[@class='thumbnail']").first['src'].should =~ /placehold.it/ 
    end 
 
  end 
 
end

The spec encapsulates all of the steps we used to define our main feature. It thoroughly tests the markup and the flow, so we can make sure that everything works properly at a granular level.

Now we can shorten the managing_profile.feature:

 
Feature: managing user profile 
  As a user 
  In order to manage my data 
  I want to access my user profile page 
 
  Background: 
    Given a user exists with email "email@example.com" 
 
  Scenario: editing my profile 
    Given I change the email with "new_mail@example.com" for "email@example.com" 
    Then I should see "User updated" 
 
  Scenario: adding an avatar 
    Given I upload the mustache avatar for "email@example.com" 
    Then the profile should show "the mustache avatar" 
 
  Scenario: removing an avatar 
    Given the user "email@example.com" has the mustache avatar and I remove it 
    Then the user "email@example.com" should have "the placeholder avatar"

Updated user_steps.rb:

 
Given /^a user exists with email "([^"]*)"$/ do |email| 
  Factory(:user, email: email) 
end 
 
Given /^the user with email "([^"]*)" has the mustache avatar$/ do |email| 
  u = User.find_by_email(email) 
  u.avatar_image = Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
  u.save 
end 
 
Then /^I should see "([^"]*)"$/ do |content| 
  page.should have_content(content) 
end 
 
Then /^the profile should show "([^"]*)"$/ do |image| 
  n = Nokogiri::HTML(page.body) 
  n.xpath(".//img[@class='thumbnail']").first['src'].should =~ pattern_for(image) 
end 
 
Given /^I change the email with "([^"]*)" for "([^"]*)"$/ do |new_email, old_email| 
  u = User.find_by_email(old_email) 
  visit edit_user_path(u) 
  fill_in :email, with: new_email 
  click_button 'Save' 
end 
 
Given /^I upload the mustache avatar for "([^"]*)"$/ do |email| 
  u = User.find_by_email(email) 
  visit edit_user_path(u) 
  attach_file 'user[avatar_image]', Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
  click_button 'Save' 
end 
 
Given /^the user "([^"]*)" has the mustache avatar and I remove it$/ do |email| 
  u = User.find_by_email(email) 
  u.avatar_image = Rails.root + 'spec/fixtures/mustache_avatar.jpg' 
  u.save 
  visit edit_user_path(u) 
  check "Remove avatar image" 
  click_button 'Save' 
end 
 
Then /^the user "([^"]*)" should have "([^"]*)"$/ do |email, image| 
  u = User.find_by_email(email) 
  visit user_path(u) 
  n = Nokogiri::HTML(page.body) 
  n.xpath(".//img[@class='thumbnail']").first['src'].should =~ pattern_for(image) 
end 
 
def pattern_for(image_name) 
  case image_name 
  when 'the placeholder avatar' 
    /placehold.it/ 
  when 'the mustache avatar' 
    /mustache_avatar/ 
  end 
end

Adding S3 Support

As a last step, we can easily add S3 support to store the avatar files. Let's reopen config/initializers/dragonfly.rb and update the configuration block:

 
Dragonfly::App[:images].configure do |c| 
 
  c.datastore = Dragonfly::DataStorage::S3DataStore.new 
 
  c.datastore.configure do |d| 
    d.bucket_name = 'dragonfly_tutorial' 
    d.access_key_id = 'some_access_key_id' 
    d.secret_access_key = 'some_secret_access_key' 
  end 
 
end unless %(development test cucumber).include? Rails.env

This will work out of the box, and will only affect production (or any other environment that is not specified in the file). Dragonfly will default to file system storage for all other cases.


Conclusion

I hope you found this tutorial interesting, and managed to pick up a few interesting tidbits of information.

I encourage you to refer to the Dragonfly GitHub page for extensive documentation and other examples of use cases - even outside of a Rails application.

Related Posts
  • Web Design
    UX
    Walk Users Through Your Website With Bootstrap TourTour retina
    When you have a web application which requires some getting used to from your users, a walkthrough of the interface is in order. Creating a walkthrough directly on top of the interface makes things very clear, so that's what we're going to build, using Bootstrap Tour.Read More…
  • Code
    JavaScript & AJAX
    Ember Components: A Deep DiveEmber components retina preview
    Ember.js is a JavaScript MVC framework that allows developers to create ambitious web applications. Although pure MVC allows a developer to separate concerns, it does not provide you with all the tools and your application will need other constructs. Today, I'm going to talk about one of those constructs. Ember components are essentially sandboxed re-usable chunks of UI. If you are not familiar with Ember, please check out Getting Started With Ember.js or the Let's Learn Ember Course. In this tutorial, we will cover the Web Components specification, learn how to write a component in Ember, talk about composition, explain the difference between an Ember view and an Ember component, and practice integrating plugins with Ember components.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Preparing the MarkupCreating wordpress theme from html 400
    Last year I did a small (and admittedly very un-scientific) survey among other WordPress developers. What I wanted to know was this: When they built their first WordPress theme, how did they do it? Did they hack an existing theme or did they start with their own static HTML and turn it into a theme? The majority of people I spoke to used the second approach - they were all experienced frontend developers who had built sites using HTML and CSS, and found it easiest to take their existing HTML files and convert them to a theme. Two of the people I spoke to were lecturers or teachers, and told me that this is the approach they use with students. So in this series I'm going to show you how to do just that.Read More…
  • Code
    Scala
    Building Ribbit in ScalaRibbit scala retina preview
    In this tutorial we will implement the Ribbit application in Scala. We'll be covering how to install the Play web framework, a NetBeans plugin for it, and finally the code in Scala. If you are new to Scala, check out this previous tutorial which will help you set up your environment and provides you with a general platform that you can build upon. Even though the essence of Ribbit is to create/send/read Ribbits (our version of tweets), we will spend a large part of this tutorial explaining how Play works, authentication, and persistence. After these are in place, the rest becomes much easier. We will also implement ribbit creation, submission and listing out all ribbits. Following someone, advanced user settings, and direct messages will be an extra assignment for you to complete on your own. I am sure if you manage to follow along with this tutorial and create Ribbit as explained below, these three functionalities will be easily accomplished as homework.Read More…
  • Code
    JavaScript & AJAX
    Building Ribbit in MeteorRibbit meteor preview retina
    This is a continuation of the Twitter clone series with building Ribbit from scratch, this time using Meteor.Read More…
  • Code
    Plugins
    How to Create a WordPress Avatar Management Plugin from Scratch: Finishing TouchesPreview
    Avatar Manager for WordPress is a sweet and simple plugin for storing avatars locally and more. Easily. Enhance your WordPress website by letting your users choose between using Gravatar or a self-hosted avatar image right from their profile screen. Improved workflow, on-demand image generation and custom user permissions under a native interface. Say hello to the Avatar Manager plugin.Read More…