Sunday, December 16, 2012

Uninitialized constant ActiveSupport::Dependencies::Mutex (NameError)

This error may occur to run older Rails application for conflicting with rubygems version. After a long googling I've come out in to following three solutions:

Using Bundler.:
Click here if you are interested to see the solution.

Changing rubygems version:
  • Downgrade the rubygems to an earlier version using gem update --system {version}
  • Add "require 'thread'" in to - Rakefile, script/server and config/environment.rb

Upgrade Rails:
Upgrade application in to Rails 3 though it's very hard to do for existing/running rails application.

For me, I was trying to run Rails 2.3.5 application where my system had rubygems 1.8.2. I've changed the rubygems version in to 1.7.2 as mentioned above and everything works fine.

Wednesday, December 12, 2012

Render HTML file in Rails using Nokogiri

You may need to render static HTML template file from a controller action without modifying anything in to file. And, may need to replace some content during render.

A template may contain relative path for css, image etc. which may raise an exception as rails may not route that automatically. At that case you have to change the contents but that's not straightforward.

I have given an example below to render a static newsletter template placed in to public directory

Say, you have a newsletter template in to public/newsletters/1.html which contains something like below and want to render from newsletters#show:
    
    

    
{title}
{description}

Write a library to process newsletter template and placed in to lib
require 'nokogiri'
require 'uri'

module NewsletterProcessor
  TEMPLATE_DIR = "newsletter-template"
  TEMPLATE_PATH = "public/#{TEMPLATE_DIR}/1.html"

  def self.included(base)
    base.send(:before_filter, :load_newsletter, :only => :show)
  end

  def show
    content = render_to_string(:file => TEMPLATE_PATH)
    @content = TemplateParser.new(request, @newsletter.attributes).parse(content)
    render :text => @content, :layout => false
  end

  private

  def load_newsletter
    @newsletter = Newsletter.find(params[:id])
  end

  class TemplateParser
    cattr_accessor :request
    cattr_accessor :params

    def initialize(request, attrs)
      self.request = request
      self.params = attrs
    end

    def parse(content)
      content = Nokogiri::HTML(content)
      return parse_content(parse_assets_url(content))
    end

    private

    def parse_assets_url(content)
      #Parse Image URL
      content.css("img").each do |img|
        update_asset_attribute(img, "src")
      end

      #Parse Stylesheet URL
      content.css("link").each do |link|
        update_asset_attribute(link, "href")
      end

      return content
    end

    def parse_content(content)
      content = content.to_s
      content.gsub!(/\{(.*)\}/) do |exp|
        replace_attribute_value(exp)
      end

      return content
    end

    def replace_attribute_value(exp, attributes = self.params)
      key = exp.delete('{}').downcase.to_sym
      attributes.has_key?(key) ? attributes[key] : exp
    end

    def update_asset_attribute(ele, key)
      path = ele.attributes[key].value
      ele.attributes[key].value = full_url(path)
    end

    def full_url(path)
      url = URI.parse(path)
      return !url.scheme ? "#{self.request.scheme}://#{self.request.host_with_port}/#{TEMPLATE_DIR}/#{url.path}" : path
    end
  end
end

Now, just include the library in to the newsletters controller and run newsletters#show from browser.
class NewslettersController < ApplicationController
  include NewsletterProcessor
end
That's all!

Wednesday, November 28, 2012

Creating authentication from scratch in Rails 3.1

There are some popular authentication libraries like devise, Authlogic, Restful Authentication, Clearance in Ruby on Rails. But, you can implement of your own as well.

Here, I'm explaining few simple steps to create your own authentication system in Rails 3.1. First, Create Run following commands from command prompt and then copy the codes in the respective files:

Create new rails application
rails new rails3-auth-from-scratch

Generate user model/controller/views
rails g scaffold user first_name:string last_name:string email:string password_digest:string

Migrate database to create users table
rake db:migrate

Generate sessions controller
rails g controller sessions new

Modify user model by following codes in app/models/user.rb
class User < ActiveRecord::Base
  attr_accessible :email, :first_name, :last_name, :password_digest
  has_secure_password

  def name
    "#{first_name} #{last_name}"
  end

  def self.authenticate(email, password)
    find_by_email(email).try(:authenticate, password)
  end
end

Add bcrypt-ruby gem in to Gemfile to encrypt password and run bundle install
gem 'bcrypt-ruby'

Write/Copy following codes in app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery

  def authenticate!
    if !logged_in?
      redirect_to login_url, :alert => "You must login to access that page."
    end
  end

  private

  def logged_in?
    return true if current_user.present?
  end

  def current_user
    @current_user ||= User.find_by_email(session[:email]) if session[:user_id]
  end

  helper_method :current_user, :logged_in?
end

Authentication codes in app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def new
  end

  def create
    # if the user is found and the user's password authenticates
    if user = User.authenticate(params[:email], params[:password])
      create_user_session(user)
    else
      flash.now.notice = "Invalid email or password"
      render "new"
    end
  end

  def destroy
    reset_session
    redirect_to root_url, :notice => "Logged out!"
  end

  private
  def create_user_session(user)
    session[:email] = user.email
    session[:user_id] = user.id
    redirect_to root_url, :notice => "Logged in!"
  end
end

Copy code snippet for login widget in app/views/sessions/new.html.erb
<%= form_tag sessions_path do %>
    
<%= label_tag :email %>
<%= text_field_tag :email %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag 'Login', :class => 'btn' %>
<% end %>

Update resources and path information in app/models/user.rb
resources :users
resources :sessions, :only => [:new, :create, :destroy]

get 'logout' => 'sessions#destroy', :as => 'logout'
get 'login' => 'sessions#new', :as => 'login'
get 'signup' => 'users#new', :as => 'signup'
post 'sessions' => 'sessions#create'

root :to => 'users#index'

Now, Run the application and go to "users/new" to create first user. After creating the user add following line at top of app/controllers/users-controller.rb to filter authenticated users:
before_filter :authenticate!

That's it. Now you refresh the browser and see the full functional authentication system.

Click here to checkout the full functional application with user management.

Monday, November 26, 2012

Rename rails3 application

Just published new version of rename gem with following changes:
  • Sanitize new name
  • Search/Replace module name in all files under root and config
  • Change session key
  • Change directory name

Installation
Add this line to your application's Gemfile:
gem 'rename'

Uses
rails g rename:app_to NewName
rails g rename:app_to "New-Name"

Friday, October 26, 2012

Website thumbnail using API

Just recently, I have developed a page cast module for Greenarrow.com to show users profile's thumbnail image on the fly.

Before doing that I have googling and found couple of good solutions:

webthumb.bluga.net is the best solution in between those though it's depend on windows hosting.

You can have a look at

Friday, October 19, 2012

Drag and drop from scratch using JavaScript

An example code to implement drag-ability in to an HTML element from scratch without using JavaScript library.

JavaScript functions to provide drag-ability:
function DDElement(ele, event) {
    addEvent(ele, "mousedown", downHandler, true);
    addEvent(document, "mouseup", upHandler, true);

    if (event.stopPropagation)
        event.stopPropagation();
    else
        event.cancelBubble = true;

    if (event.preventDefault)
        event.preventDefault();
    else
        event.returnValue = false;

    function upHandler(e) {
        e = e || window.event;
        removeEvent(document, "mousemove", moveHandler, true);

        if (e.stopPropagation)
            e.stopPropagation();
        else
            e.cancelBubble = true;
    }

    function downHandler(e) {
        e = e || window.event;
        addEvent(document, "mousemove", moveHandler, true);
    }

    function moveHandler(e) {
        e = e || window.event;

        var pos = getCursorPosition(e);

        ele.style.left = (pos.x - 50) + "px";
        ele.style.top = (pos.y - 5) + "px";

        if (e.stopPropagation)
            e.stopPropagation();
        else
            e.cancelBubble = true;
    }
}

function getCursorPosition(e) {
    e = e || window.event;

    var pos = {x:0, y:0};

    if (e.pageX || e.pageY) {
        pos.x = e.pageX;
        pos.y = e.pageY;
    } else {
        var de = document.documentElement;
        var b = document.body;
        pos.x = e.clientX + (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0);
        pos.y = e.clientY + (de.scrollTop || b.scrollTop) - (de.clientTop || 0);
    }

    return pos;
}
HTML element to provide drag-ability:
Handler
Drag Content
Uses: Calling drag and drop on window load:
window.onload = function () {
     DDElement(document.getElementById('dragndrop'));
};

View Demo


Friday, September 7, 2012

Friday, August 31, 2012

Google weather API not working

Recently google has shutdown their weather API silently which breaks one of my clients first page application name Greenarrow.com.

I think many developers and users were (and still are) outraged, but at least they have some time to breathe as because iGoogle isn’t going away until November 1, 2013. So, there are still one year and three months left to change your favorite weather module. So, there's no point trying to spend time with it.

There has been no official announcement or communication that indicate the API has been closed or going to be closed. But, it is very interesting that iGoogle using wunderground.com API till the service is completely retired in 2013.

If your are experiencing same problem with your favorite application or weather module change the API without spending time to fix that. I think better option to move in to wunderground.com.

Click here to see the demo

Monday, July 2, 2012

Javascript not working - NetworkError: 404 Not Found

Yesterday, I have deployed an application on Ubuntu server but the javascript was no longer working after configuring the virtual host.

I have taken following steps to find the problem:
  • Viewed the HTML source code using firebug and found page not found error
  • Checked the .htaccess file, but there were no problem
  • Tried a test javascript file from a different directory and it worked
  • At last, I have checked the Apache error log and found that it was attempting to load file from /usr/share/javascript/{file name}

It was very surprising because none of my site contents on that directory - /usr/share/ and didn't do anything which may take this type of effect.

After a lot checking in the Apache configuration I found a symbolic link in the /etc/apache2/conf.d/javascript-common.conf which was causing the problem.

Alias /javascript /usr/share/javascript/

<directory "/usr/share/javascript/">
        Options FollowSymLinks MultiViews
</directory>

To fix - Commented out the Alias line(1) and then restarted Apache. Everything started working fine for me.

Friday, May 25, 2012

Undefined local variable or method `version_requirements' for ...

I was getting the error while installing an older rails application. After googling I've got the solution from a discussion thread to add following block in right before the initialization in to config/environment.rb and worked for me.
if Gem::VERSION >= "1.3.6"
  module Rails
    class GemDependency
      def requirement
        r = super
        (r == Gem::Requirement.default) ? nil : r
      end
    end
  end
end

Wednesday, April 4, 2012

How to rename Rails3 application

A Rails3 application name are using as a Ruby name space for entire application and throughout the project tree as well. So, If anyone later decide to change the project name, then have to replace the name in the following files:
Rakefile
config.ru
config/routes.rb
config/application.rb
config/environment.rb
config/environments/development.rb
config/environments/test.rb
config/environments/production.rb
initializers/secret_token.rb
initializers/session_store.rb

You can run following command in your project root, to find out the list of files containing project name(assume you are using linux):
grep -Ri 'AppName' * | cut -f1 -d':' | sort | uniq

You can use following gem to rename rails3 application without any hassle:

Monday, March 12, 2012

Date Time difference and a new time adding intervals in days, week, month etc.

I've written a DateTime helper class to get:
  • DateTime difference as an object and string
  • DateTime details as an array and object
  • Repeat DateTime by minute, hour, day, week, month, year using interval etc.

You can checkout the repository from github.com.

Uses: View Demo

Friday, February 3, 2012

Cross browser event listener

Sometimes, we need to attach or detach an action with an element for specific event where listener function depends on browser. By using following code snippet anyone can do that in all browsers:
function addEvent(obj, evType, fn, useCapture) {
    useCapture = (useCapture === undefined ? false : useCapture);

    if (obj.addEventListener) {
        obj.addEventListener(evType, fn, useCapture);
    } else if (obj.attachEvent) {
        obj.attachEvent("on" + evType, fn);
    } else {
        obj['on' + evType] = fn;
    }
}
// Use: addEvent(element, 'mousemove', function_name);

function removeEvent(obj, evType, fn, useCapture) {
    useCapture = (useCapture === undefined ? true : useCapture);

    if (obj.removeEventListener) {
        obj.removeEventListener(evType, fn, useCapture);
    } else if (obj.detachEvent) {
        obj.detachEvent("on" + evType, fn);
    } else {
        obj['on' + evType] = fn;
    }
}
// Use: removeEvent(element, 'mousemove', function_name);


Tuesday, January 10, 2012

Multiple login in google talk

Most of us have multiple google talk IDs and used third party software to login at a time. But, anyone can do multiple login to gtalk by using a simple trick below:

  • Right click gtalk icon and select properties
  • Add /nomutex at the end of target property like following way
    "C:\Users\Morshed\AppData\Roaming\Google\Google Talk\googletalk.exe" /startmenu /nomutex
  • Click to Apply and Ok

Done! Now click on gtalk icon and open as many as gtalk windows you want. Cheers!!