codedecoder

breaking into the unknown…


1 Comment

page vertical auto scroll jquery

One of my form have many inputs and user need to scroll down to reach till the end of form. I need to implement auto scrolling, for the page, so that when user, reach a input filed at the bottom of page, it automatically scroll up to expose the remaining fields. Below is the code, which use jQuery animate to implement vertical auto scroll. We have scroll_to method, which take two argument base and target . base is the element to be animated, target is used to calculate height from top , we need to scroll up . So, say as in  below example, when user click on city input box which is at the bottom, the page will move up, taking city input to top of the page, So exposing other input element below it. Similarly, I have a popup in which designation input is at bottom, so scroll_top is called on it. like $(‘html,body’) or $(‘.modal-body’) you can trigger auto_scroll on any element, provided that element have certain height set,which is less then required by whole content, triggering the scrollbar.

jQuery(function(){

   $(document).ready(function(){
     #when user click on city input scroll_to method will be called, which will
      scroll the city input to the top, showing all other input below it
     $("#city").on('focus',function(){
     scroll_to($('html,body'), $(this));
     });
     #when user click on designation input in the popup scroll_to method will be called, 
     which will scroll the city input to the top, showing all other input below it
     $("#designation").on('focus',function(){
     scroll_to($('.modal-body'), $(this));
     });
  })

  function scroll_to(base, target){
    base.animate({
    scrollTop: target.position().top
     },1000);
    }
})

I have implemented, the autoscroll basically for my popup. The problem, I faced there is that, the target(designation input) top position keep changing with each scroll. say, first time the popup get open, I clicked designation input (say it is 500px below the top), it moved up, so now it is 0 px from top, now you close the popup, again open the popup, now this time scroll not work as, it will try to move 0 px, which is equal to no scroll. So, I modified the scroll_to method as below.

function scroll_to(base, target){
   base.animate({
      scrollTop: target.position().top + parseInt(base.scrollTop())
   },1000);
}

Here, the height to scroll, will be sum of target position and height of the scroll relative to the base.

If, above auto scroll, don’t solve your problem. jQuery plugins are available with advance functionality. checkout this for vertical scroll and this for horizontal scroll

Referance:

http://stackoverflow.com/questions/4034659/is-it-possible-to-animate-scrolltop-with-jquery

http://api.jquery.com/offset/

http://api.jquery.com/position/

http://stackoverflow.com/questions/3202008/jquery-difference-between-position-and-offset

http://api.jquery.com/animate/

http://api.jquery.com/scrollTop/


2 Comments

cannot load such file — safe_yaml

Everything working fine on staging server, testing was complete. We have decided to move ahead with deploying our product in production. Heroku is decided to be our production server. We have made some changes, needed by herkou, and some other for our own foreseen benefits. Some Important changes are.

=> Added pg and unicorn gem under production group to our gem file

=> Added Procfile in root of our project to start our worker and unicorn server

=> Added some configuration file for unicorn server

=> some other changes in our environment file

code is committed and pushed to git…Herkou is up and running…yepieeee

Next day…I loged in to staging server..pull the current code on git..and restarted the staging server….BOOM…server crashed with below message.

safe_yaml load error

safe_yaml load error

Error message is self explainatory….”safe_yaml file is not getting loaded“. When you start your application server, It try to load all the gems and there dependency gems. So here, it is failing to load the safe_yaml gem. Well solution is simple then. just install the safe_yaml gem and it should work. But what the hell…safe_yaml gem is allready installed.

$ bundle show safe_yaml # below it list the path of the gem…thus it is allready installed
/root/loan_path_customer_portal/Third-Pillar/vendor/bundle/ruby/1.9.1/gems/safe_yaml-0.9.2

I struggled whole day…to trace back the error in the changes introduced last day…thinking staging server is fine before yesterday. Read  up and down of Procfile, unicorn server and pg gem for possible clue about the error…but nothing helped. O.K…so time to follow the old saying….. 🙂

“If you get LOST in your journey….go back to the place you have started”

If you read the error backtrace properly, You will always get clue….so first thing first….what is the error message…. safe_yaml file is not loading. well that, I knew from beginning. What, Iam doing wrong in my approach is linking it with pg, unicorn and Procfile added one day back, as everything fine before that. But, NO..they do not need safe_yaml. If you see the log, you will find that, actually rails_admin gem trying to load it...see line 4 of the image above.

check the path of rails_admin

$ bundle show rails_admin
/root/loan_path_customer_portal/Third-Pillar/vendor/bundle/ruby/1.9.1/bundler/gems/rails_admin-71bdd8316be0

So, you can see that, safe_yaml and rails_admin is installed at different location (see the bold part)and rails_admin trying to load safe_yaml relative to its current path.
In production mode, we generally use below command for bundle install which pull all the gem in vendor:

$ bundle install – -deployment # this will store all gems in vendor/bundle/ruby/version_no folder of your project.If you use simply bundle install, it will get installed in your rvm folder

The location of the the two gems get differed, due to way the rails_admin included in the gemfile and the way bundler install them.when a gem is fetched from gem source, it is installed to gems folder , and if from some specific repository, it get installed to bundler/gems folder .

Now, since I want some fixes related to jQuery of rails_admin which is present in git master branch, but not yet published as gem, I provided the git url as source of my gem

gem ‘rails_admin’, :git => “http://github.com/sferik/rails_admin.git” # bundle install command will install rails_admin to /bundler/gems folder of rvm or the vendor folder of the project, and since safe_yaml is one of its dependency, will get installed to gems folder of RVM.

SOLUTION : My problem is solved by removing the git source from the rails_admin, letting it to be fetched from the gem repository, so that both rails_admin and its dependency get installed in the same folder.

gem ‘rails_admin’

run bundle install, committed  Gemfile and Gemfile.lock, pulled the code on staging server, restarted the server….huh…its UP again


Leave a comment

sample background job in rails

I have explained the need of background job and when to use it in this post. We need background job worker to execute our background job. I have explained installation of resque here and sidekiq here as job worker. I will explain pushing your time consuming jobs to background with respect to sidekiq. The flow will remain same for resque also.

NOTE : Though the gem used as background processor is sidekiq, the code to trigger these job and getting its status is managed by  sidekiq-status gem. sidekiq-status gem is basically written over sidekiq gem as its wrapper. You should refer sidekiq-status gem if you failed to understand something here

The feature requirement is related to loan application to a bank. You application provide, interface to user to fill up details like name, bank account number, ssn, address etc. on submit of form it go to create action, where you  make API call to bank, who then try to save the user detail in there DB and return response as success or failed with related message. I am just showing structure(in reality it have hundreds of lines of code with complicated logic of validation and other security safeguard) of my current controller code, without any background job.

Let us see our code without any background worker.

controller code

class LoansController < ApplicationController

  def new
    @loan = Loan.new
  end

  def create
    begin
      @loan = Loan.new(params[:loans])
      LoanPath::Application.new.apply_credit(params[:loan]) # this line 
      of code we will move to background later on
      flash[:notice] = "Credit Request Submitted Successfully"
      redirect_to loans_path
     rescue Exception => e
      flash.now[:error] = e.message.present? ? e.message : "System encountered error,try later"
      render :new
    end
  end

end

We have separated the code related to making API call, to another file lib/loan_path/application.rb. Its content is as below.

 
require 'rest_client'
require 'base64'

module LoanPath
  class Application
    def apply_credit(detail)
      details=detail.symbolize_keys
      uri = "http://mybank.com/esb-sunpower/outbound/SubmitForCreditService"
      payload =<<-eos
      <soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
      <soap11:Body>
        <Request>
           <Payload>
               <customer>
                  <id>#{details[:CustomerID]}</id>
                  <firstName>#{details[:first_name]}</firstName>
                  <lastName>#{details[:last_name]}</lastName>
                  <bankName>#{details[:bank_name]}</bankName>
                  <accountNumber>#{details[:account_number]}</accountNumber>
                  <routingNumber>#{details[:routing_number]}</routingNumber>
               </customer>
          </Payload>
        </Request> 
      </soap11:Body>
     </soap11:Envelope>
     eos
     rest_resource = RestClient::Resource.new(uri, {:user => "arun", :password => "secret", 
                                                   :timeout => 90 s, :open_timeout => 90s})
     rest_resource.post payload, :content_type => "application/xml"
     end
  end
end

NOTE : The background job works at class level, so the code need to be executed as background must be taken out into a separate class

Iam lucky here , that my initial design already have, the required code in a separate class Application as you see above.

So, what is happening here. in create action we are passing the details filled by the user to apply_credit method of application class, which then convert it into xml payload, and send it to Third Party through restclient call. Till the time response come, user remain on the new page itself, with a rotating image with message , your request is processing. If everything fine I redirect the user to loan index path and if the third party raise some exception, I catch the error message and render the new action. You can see that, I have set the timeout to 90 second , so you can understand how time consuming process it is. This is just an example of a method you should better run in background. You may have any other method in place of apply_credit method here.

So, now we will better our design and process, the apply_credit task in the background. The flow here will be like this.

=> user fill the detail on the Loan new form

=> Submit the data to create action. he can see rotating image with the message “Your request is Processing”

=> Create action will push the API call i,e apply_credit method to the background

=> In create action , we render create.js.erb file which will contain code, which make ajax call to worker, every 3 second, asking about the status of the task send to it

=> If status is success, we redirect it to loan index path as usual, but if failed, we need to capture the error message. The problem here I faced is that, sidekiq do not return any error message but only the status. The message need to be set by you only. So you need to capture the exception in apply_credit method, instead of controller as we are doing it above. Now, since you have captured the exception yourself, It will never fail in background ..so always return the status to be complete. The workaround here is to, use store method of sidekiq, which allow you to define variable, set and retrive value from it. Things get clear when you will see the code below.

Application.rb file content

 
require 'rest_client'
require 'base64'

module LoanPath
 class Application

    include Sidekiq::Worker
    include Sidekiq::Status::Worker
    sidekiq_options :retry => false # it will not retry the 
                  failed action, default is true

    #what ever code you write within perform action will be executed in
     background, see the use of at and store within perform. at will give
     back message at given % of job completd, I have used 100,100 as I want
     message at completion of process. If you have written 5,100 the message
     will be set at completion of 5% and 100%. store allow you to define new
     variable and retrive it later on, I have define lp_status variable to
     which I stored message return by apply_credit method
    def perform(*args)
      status_message = apply_credit(args.first)# we will return status 
      and message from the apply_credit method
      at 100,100, status_message.last if status_message.last.present?
      lp_status = status_message.first.present? ? status_message.first : ""
      store lpstatus: lp_status
    end

  #see that now we are capturing, exception in apply_crdit method itself 
   and make it tot return a array whose first element is status of the process
   and second element is a success or error message. See the use of these
   returned value in credit_submit_status action of the controller
  def apply_credit(detail)
    begin
      details=detail.symbolize_keys
      uri = "http://mybank.com/esb-sunpower/outbound/SubmitForCreditService"
      payload =<<-eos
      <soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
      <soap11:Body>
        <Request>
           <Payload>
               <customer>
                  <id>#{details[:CustomerID]}</id>
                  <firstName>#{details[:first_name]}</firstName>
                  <lastName>#{details[:last_name]}</lastName>
                  <bankName>#{details[:bank_name]}</bankName>
                  <accountNumber>#{details[:account_number]}</accountNumber>
                  <routingNumber>#{details[:routing_number]}</routingNumber>
               </customer>
          </Payload>
        </Request> 
      </soap11:Body>
     </soap11:Envelope>
     eos
    rest_resource = RestClient::Resource.new(uri, {:user => "arun", 
                  :password => "secret", :timeout => 90 s, :open_timeout => 90s})
    rest_resource.post payload, :content_type => "application/xml"
    ["LpValid", "Credit Request Submitted Successfully"]
  rescue Exception => e
    error_message = e.message.present? ? e.message :  
                                  "System encountered error, please try later"
    ["LpError", error_message]
  end
 end
 end
end

Below is the code, with API task pushed to the background

controller code

class LoansController < ApplicationController

 def new
  @loan = session[:loan] || Loan.new # from js file you can't render, 
                       but only redirect, so have stored the user filled 
                       data in session in create action to be used here. If
                       session[:loan] is not present, It will create a new 
                       instance of the Loan
  session[:loan] = nil # we have stored its value in variable, so clear it
end

def create
  @job_id = LoanPath::Application.perform_async(params[:loan]) # this is the 
            line which push the job to background and return you the job Id. 
            we have stored it in @job_id variable.You will need this Id to 
            retrive information about its status
  session[:loan] = params[:loan] # create session of @loan data to render on error
  render "create.js" # if you are submitting form from new with :remote => true 
                     i,e ajax form submit, you will not need this line as rails
                    will load it automatically
end

 def credit_submit_status
    status = Sidekiq::Status::status(params[:job_id])#get the status of the job
    lp_status = Sidekiq::Status::get(params[:job_id], :lpstatus) #get the value 
                                     set in the :lpstatus variable you set in
                                      perform method in application class

    status = status.present? ? status : "NotReturned"
    lp_status = lp_status.present? ? lp_status : "NotSet"
    if status.to_s == "failed"
      flash[:error] = Sidekiq::Status::message(params[:job_id])
    elsif status.to_s == "complete"
      if lp_status == "LpError"
        flash[:error] = Sidekiq::Status::message(params[:job_id])
      else
        flash[:notice] = Sidekiq::Status::message(params[:job_id])
      end
  end
    # return back the json data to ajax call
    render :json => {:status => status.to_s, :lpstatus => lp_status.to_s }
  end

end

create.js.erb file with below content

  var jobId = <%= @job_id %>;
  var path = '/loans/new';

  # In case of failure we will redirect to the new action with
    "server_error=true" set in url, the failedActionUrl generate
    it as below
  var failedActionUrl = function(){
     var error = "server_error=true";
      if(path.indexOf('?') == -1) {
          path = path + "?" + error;
      } else {
          path = path + "&" + error;
      }

      return path;
   }

  # seInterval is jquery function which repeat the code within it.
    We will use it to make ajax call to credit_submit_status every
    3 second and redirect according to the status
      setInterval(function() {
        $.ajax({
          url: '/loans/credit_submit_status',
          data: 'job_id=' + jobId,
          success: function(data){
            if(data.lpstatus == "LpError") {
              var currentPath = failedActionUrl();
              window.location = currentPath;
              return false;
            }
            if(data.status == "complete") {
              window.location = path;
              return false;
            }
            if(data.status == "failed") {
              var currentPath = failedActionUrl();
              window.location = currentPath;
              return false;
            }
          }
        })
      }, 3000);


1 Comment

sidekiq installation and authentication with devise

I have explained the need of background and when to use it in this post. here I will explain installation , starting and stoping of sidekiq and then its authentication with devise.sidekiq gem is available here . A sample example code of background job using sidekiq is available here .

STEP 1 : Install the gem

Assuming you are working with Rails 3 add below to your Gemfile.

gem 'sidekiq'
gem 'sinatra', require: false
gem 'slim'
gem 'sidekiq-status'

Now, Install the gem by running budle install on the terminal

$ bundle install

STEP 2: Write routes for sidekiq

mount Sidekiq::Web => ‘/sidekiq’ # sidekiq is a separate app and can be mounted over your app

STEP 3: Add initialization code for sidekiq

create a sidekiq.rb file in config/initializer folder and add below code to it

require 'sidekiq'
require 'sidekiq-status'

Sidekiq.configure_client do |config|
       config.client_middleware do |chain|
       chain.add Sidekiq::Status::ClientMiddleware
    end
end

Sidekiq.configure_server do |config|
        config.server_middleware do |chain|
        chain.add Sidekiq::Status::ServerMiddleware,
                           expiration: 30.minutes 
       end
end

STEP 4: Starting and stopping sidekiq

If you are working locally you can start it with below command.

$ bundle exec sidekiq

To stop it just press cntr + c . Even if you close the terminal it get stop. This will cause problem on server as there you want it to keep running all the time. So we need to run it in background. It can be done with the below command.

$bundle exec sidekiq -d -L log/sidekiq.log #start worker in background

NOTE:

As per this commit of sidekiq, it iinherit development environment by default. So If you are starting sidekiq on any other environment say staging or production you must pass the environment also otherwise sidekiq not inherit the environment. So use below command, which start sidekiq say in production environment.

$bundle exec sidekiq -e staging -d -L log/sidekiq.log

since, now the job is running in background, It will always keep running, even if you close the terminal.

To kill a background, you need to first find its process id, then kill it

$ ps -ef | grep sidekiq #to see worker running at which pid
say, the above command return the pid 56778 an8 3421

kill those process with kill command as below.

$ kill -9 56778

NOTE: you should stop and restart the worker, whenever you make changes to the code executed by the worker , otherwise it will execute the old code only. So, to be on safer side when ever you deploy the code to server, restart the worker.

STEP 5: see the sidekiq worker dasboard is up and running

Go to browser and go to http:://your_site_url/sidekiq you will see the sidekiq dashboard. but the problem here is that everyone can access this page. It is the page which have detail of sensitive data and running process, so we need to make it accessible only to admin.

STEP 6: Authenticating and authorization sidekiq with devise

The logic to authenticate and authorize a user to access sidekiq dashboard is to make the mounting of sidekiq engine conditional one as below, by modifying the routes we have written in step 2

constraint = lambda { |request| request.env["warden"].authenticate? and 
                      (request.env['warden'].user.admin? or request.env['warden'].user.monitor?)}

constraints constraint do
mount Sidekiq::Web => '/sidekiq'
end

Thus I have first checked that the user should be loged in and when loged in they should be either admin or a monitor. you must have admin? and monitor? method defined in your user model, which contain logic to check whether a user is admin or not. For example, Iam using rolify gem and so I have implemented my method as below.

class User < ActiveRecord::Base

 def admin?

    self.has_role?  :admin #has_role? is method provided by rollify gem

  end

  def monitor?

    self.has_role?  :monitor #has_role? is method provided by rollify gem

   end

end

So, now if a user is not logged in or do not have admin or monitor role, when try to access /sidekiq he will get page not found error


Leave a comment

resque installation and authentication with devise

I have explained the need of background job and when to use it in this post. here I will explain installation , starting and stopping of resque and then its authentication with devise. resque gem is available here . You will also need resque-status to know the status of running job. resque status gem is available here.

STEP 1 : Install the gem

Assuming you are working with Rails 3 add below to your Gemfile.


gem 'resque'
gem "resque-scheduler"
gem "resque-status"

Now, Install the gem by running budle install on the terminal

$ bundle install

STEP 2: Write routes for rersque

Say, if my application is created with the name MyFinance, my routes will look like this.

require 'resque/server'

MyFinance::Application.routes.draw do

--------other routes or mount-----
  mount Resque::Server, :at => "/resque"

--------other routes or mount-----
end

STEP 3: Add initialization code for resque

create a resque.rb file in config/initializer folder and add below code to it


require 'resque/job_with_status'
Resque.redis = "localhost:6379" # this is the default value, 
                              change if redis running on some other
Resque::Plugins::Status::Hash.expire_in = (24 * 60 * 60) # 24hrs in seconds

STEP 4: Adding resque rake task to your environment

resque comes with a number of rake task to perform different resque task from the commandline, like starting stopping the worker etc. To load these task, you need to add below line to Rakefile.

require 'resque/tasks' # this will load all the resque task

task "resque:preload" => :environment. 
# it will load resque environment i,e all the files needed by it

Once , you have added above two line to the RakeFile, You can see all the available resque rake task with below command.

$ rake -vT | grep resque # will list all the available resque task as below
rake resque:work      # Start a Resque worker
rake resque:workers   # Start multiple Resque workers.

NOTE :
1-> If you do not add require ‘resque/tasks’ to rake file , you will get the below error , when try to run any resque rake command
Don’t know how to build task ‘resque:work’
2 -> If you do not add task “resque:preload” => :environment, you will get below error, when you try to start the resque worker
No such file to load — bootstrap_flash_helper

STEP 5: Starting and stopping sidekiq

If you are working locally you can start it with below command.

$ QUEUE=* rake resque:work

To stop it just press cntr + c . Even if you close the terminal it get stop. This will cause problem on server as there you want it to keep running all the time. So we need to run it in background. I do not get much time to explore running the resque worker in the background. Some good information is available here on the stackoverflow. I will update it here some other time, when I implement it myself

STEP 6: see the resque worker dasboard is up and running

Go to browser and go to http:://your_site_url/resque you will see the resque dashboard. but the problem here is that everyone can access this page. It is the page which have detail of sensitive data and running process, so we need to make it accessible only to admin.

STEP 7: Authenticating and authorization sidekiq with devise

You can introduce simple http authentication by creating a file with any name(by convention use name which reflect content and purpose of file so call it  resque_admin.rb) in config/initializer and add the below lines to it.

Resque::Server.use(Rack::Auth::Basic) do |user, password|
user = "resque_admin"  
password == "secret"
end

The logic to authenticate and authorize a user to access resque dashboard with devise is to make the mounting of sidekiq engine conditional one as below, by modifying the line we have written for mounting resque in  step 2 as below

constraint = lambda { |request| request.env["warden"].authenticate? and (request.env['warden'].user.admin? or request.env['warden'].user.monitor?)}

constraints constraint do
 mount Resque::Server, :at => "/resque"
 end

Thus I have first checked that the user should be loged in and when loged in they should be either admin or a monitor. you must have admin? and monitor? method defined in your user model, which contain logic to check whether a user is admin or not. For example, Iam using rolify gem and so I have implemented my method as below.

class User < ActiveRecord::Base

 def admin?

    self.has_role?  :admin #has_role? is method provided by rollify gem

  end

  def monitor?

    self.has_role?  :monitor #has_role? is method provided by rollify gem

   end

end

So, now if a user is not logged in or do not have admin or monitor role, when try to access /sidekiq he will get page not found error


Leave a comment

background jobs in rails

Recently, I have to restructured my code design due to request timeout error on Heroku. We have decided to use Heroku as our production server. Our staging and other instance are running on nginx+apache in our own server. We do have long running process which make third party API calls. The API is slow and take longer time to return the response. We have handled it by setting request timeout to 90 s. So our server wait for 90 second before throwing the request time out error.

Note: a sample code explaining background job is available here

But this piece of code crashed on heroku. Heroku has maximum limit of 30 second for response to return the first byte and it is not configurable, so you can’t increase it further. It is explained here . Heroku is right in its own way. Why they should pay for your poor design. Any request taking more then 10-15 second is crime in itself, in today’s fast pace world.

So the idea, is to process time consuming request in background.

There can we two kind of background job as below:

Detached background jobs:

These are the job which do not need you application to process its output i,e you are just concerned with the result: failed or success.

Some examples are :

1 : sending newsletter or email to users

2: watermarking photos uploaded by users

3: rendering images or pdf

In this case, You push the task to the background. configure retry, to try the failed job set number of time. If you want, you can ignore the failed job or write code to start it again.

Attached Background job:

You application have dependency on output of these job.

Some Examples are:

1: posting some detail outside your application to third party through API

2: Uploading photo or document by the user

Here, You need to keep user on the same page with showing progress bar or rotator and through ajax call keep checking the background worker after, say every 3 seconds about the status of the job, If it is success, you redirect to some other page and if failed, you render the error message to the user.

Choosing between available background job processor gem.

Below is few gems available which handle background job and are very easy to use. The complete list is available here on the rubytoolbox.

=> delayed job

=> sidekiq

=> resque

I have listed the gems in order of there popularity. I have used both sidekiq(explianed here) and rescue(explianed here) in my project and found both of them are very easy to use. A comparative analysis of resque and sidekiq is available here , choose whatever suits you.

Reference:

https://devcenter.heroku.com/articles/request-timeout


1 Comment

jQuery datpicker with date of Birth validation

We often have date element in our forms, like for entering date of birth, joining date, delivery date etc. We provide, the user with a calender to enter the date. A number of plugin available out there for entering date to form input. But, We will use datepicker plugin of jQuery here. We will then validate the date enter by the user on the form submit. Note, that a date selected from datepicker is always a valid date fromat, but user can change it manually in the text box if he want and enter some wrong date… testing person always do it 🙂

Lets below is our simple form with one input field with id = dob and a submit button.

<form>
   <label>Your Date of Birth</label>
   <input type="text" value="" id="dob" />
   <input type="submit" value="Submit" id="form-submit" />
</form>

We will going to validate date for its correct format (assuming dd-mon-yyyy format) and other things like, it should not be less than the current date.

jQuery(function(){
  //attach the datepicker to input with id dob after page load
  $(document).ready(function(){
  //yearRange will determine no of years to show in year select box. currently it will list 100 year 
  from now .  setting changeMonth and changeYear to true will show month and year box in calender, 
  otherwise user will able to select day only.The format given here means date should be like 
  13-May-2013. all possible format is available here

  $("#dob").datepicker({
          yearRange: "-100:+0",
          changeMonth: true,
          changeYear: true,
          dateFormat : "d-M-yy",
          # onchangeMonthYear code below will refelct the date change as soon as user
           change year or month.If you do not use it date will cahnge only after
           select a day
          onChangeMonthYear: function(year, month, day){
            $(this).datepicker('setDate', new Date(year, month-1, "1"))
            var selectedDate = '1';
            if($(this).datepicker('getDate')!=null){
                selectedDate = $(this).datepicker('getDate').getDate();
            }
            $(this).datepicker('setDate', new Date(year, month-1, selectedDate));
          }
       });

    })

  // defining the function doing the date validation .our date format should be like 13-May-2013
  var validated_dob = function(dob){
             var dob_split = dob.split("-") #split the dob string into array
             var validated = "Yes"
             var msg = "Date of Birth is valid"
             var month_array = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                                'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]

             // make sure that day year and month entered or return
             if(dob_split.length != 3){
                            validated = "NO"
                            msg = "Date of Birth must be entered in this format: DD-MON-YYYY"
                            return [validated, msg]
                }

             // make sure that day month and year in DD-MON-YYYY format
            if ((dob_split[2].length != 4) || (dob_split[1].length != 3) || 
                                 !(dob_split[0].length == 2 || dob_split[0].length == 1)){
                            validated = "NO"
                            msg = "Date of Birth must be entered in this format: DD-MON-YYYY"
                            return [validated, msg]
                        }

             // make sure that day month have only integer
             if((!(/^[0-9]+$/).test(dob_split[0])) || (!(/^[0-9]+$/).test(dob_split[2]))){
                           validated = "NO"
                           msg = "Date of Birth day and year can have only numeric value"
                           return [validated, msg]
              }

             // make sure that day is in range 1-31
             if(dob_split[0] > 31 || dob_split[0] <= 0){
                            validated = "NO"
                            msg = "Date of Birth day should have value in 1-31"
                            return [validated, msg]
               }

            // make sure that month entered as Jan Feb etc
            if($.inArray(dob_split[1],month_array ) < 0){
                           validated = "NO"
                           msg = "Date of Birth month should be in ['Jan', 'Feb', 'Mar', 'Apr', 'May', 
                                                    'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]"
                           return [validated, msg]
             }

           // these variable are defined here instead of top because datepicker
           // can parse only a valid date, so if date is wrong it will throw error
           var user_dob =$.datepicker.parseDate("d-M-yy", dob)
           var today_date = new Date()
           if(user_dob > today_date){
                           validated = "NO"
                           msg = "Your Date of Birth can't be less than Today's Date"
                           return [validated, msg]
            }

           // if all condition pass, return original value at top
           return [validated, msg]
        }

       // validate the date on form submit
    $("#form-submit").click(function(e){
              // collect value return by validated_dob in a variable
              var check_dob = validated_dob(dob)
              // if validation return No, alert the error message and return
              //false i,e prevent the form from submit
              if (check_dob[0] == "NO"){
                            alert(check_dob[1])
                            return false
               }
     })
})

Referance:

http://api.jquery.com/Types/ # will tell you all type of data in jquery

http://api.jquery.com/Types/#Array # detail on jQuery array
http://api.jquery.com/jQuery.inArray/ # matching a element in array, will return -1 if no element matched or index of element if matched
http://api.jquery.com/category/miscellaneous/dom-element-methods/ # list method for traversing dom
http://api.jqueryui.com/datepicker/ # detail documentation of datepicker


Leave a comment

prevent right click on page : jquery contextmenu

contextmenu, tell a user of available options with a data element like links , input etc. You have observed a list of options shown to you when you right click on a webpage like : “reload”, “view page source” etc, similarly when you right click a link, it show you options like : “open in new window”, “open in new tab”  etc. These are the examples of contextmenu implemented by browser i,e they are default features of each browser. You can create your own context menu when needed in your application. Say you application is for managing image gallery, then you want, the right click to provide “copy”, “cut”, “save”, “downlaod” etc options on right click of a folder or image. A no of plugin are available there, to write custom contextmenu . some of them are listed below

http://medialize.github.io/jQuery-contextMenu/

http://plugins.jquery.com/contextMenu/

for people working on Rubu on Rails, gems also available for developing contextmenu

https://github.com/medialize/jQuery-contextMenu

https://github.com/joewalnes/jquery-simple-context-menu

Well, I have not tried any of the above plugin or gems, as my current requirement was not to set contextmenu, but to prevent it. I’ am working on financial domain website, and for security reason they do not want the user to access any contextmenu provided by the browser. So basically they want to disable right click on the page . It can be, achieved by the few lines of code. just put the below lines of code on page , you want to prevent the right click.

<script type=”text/javascript”>
  $(document).ready(function(){
    $(document).bind(“contextmenu”,function(e){
      alert(“For Security Reason Right Click Disabled on This Page”)
      e.preventDefault();
    });
  });
</script>

Note that contextmenu is a event like click, mouseover , keydown etc. So, to prevent it we have just prevented its default behaviour. complete list of events is available here at the bottom of the page . contextmenu event is explained in detail here .


2 Comments

custom rake task in rails

rake command is explained in this post. rails provide a number of inbuilt tasks, but you can create your own task also as explained here.

=> Understanding the basics :

When you create any new rails project(example: rails new my_finance), you will find a file called Rakefile in your project root directory. It has below content in it

#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)

MyFinance::Application.load_tasks # load_tasks method will make all your task available to rake

You can see that, it has self explanatory message at top. So to create, any custom task, we will create a file with .rake extension in lib/tasks folder of our application.

=> Examples of rake tasks.

I will create here different rake task, demonstrating how to write a simple rake task, rake task with arguments and rake task with dependency. let us create a demoexamples.rake file in lib/tasks folder. We will add our custom tasks to this file. Below is the code examples.

namespace :demotask do

  desc "display the current environment of rake"
  task :current_environment do
    puts "You are running rake task in #{Rails.env} environment"
  end

  desc "You are going to meet a person"
  task :meet_a_person do
    puts "I meet a person on the way to my house"
  end

  desc "I will say hello to the person"
  task :say_hello => :meet_a_person do # It means meet_a_person is dependency of say_hello task
    puts "I said HELLO to the person"
  end

  desc "I will say hello to the person after meeting and check environment"
  task :hello_env => [:current_environment, :meet_a_person] do # multiple dependency can be 
                                                               #passed as array
    puts "I said HELLO to the person"
  end

  desc "going to call two of my friend"
  task :call_friend, [:friend1, :friend2] do |t, args| # task with two arguments
    args.with_defaults(:friend1 => "John", :friend2 => "Dough")
    puts t # print t to see what it contain
    puts args # print args to see what it contain and in which format
    puts "Hello #{args.friend1}"
    puts "Hello  #{args.friend2}"
  end

  desc "see what happen when you call a modal method without loading environment"
  task :without_environment do
    puts User.first.full_name
  end

  desc "load environment before operating on any model object"
  task :with_environment => :environment do
    puts User.first.full_name
  end

  desc "count number of records in given model table"
  task :count_records, [:model] => :environment do |t, args| # task with both arguments and dependency
    args.with_defaults(:model => "User" )
    model_calss_name = Object.const_get(args.model) # this is very important as when you#pass argument it come as a string, so you must convert it to model class
    puts "No of records is #{model_calss_name.count}"
  end

end

The point to note above is the use of below concept:

namespace : It will group your task in a namespace, thus avoiding any conflict if task with same name already exists. You can skip it if you want, but use it as good convention

desc : It describe the function your task is going to perform. You can skip it if you want, but use it as good convention

task: it contain the code which perform your desire action. I have just printed simple messages but you can do anything in the do end block

name of the task : task is followed by name of the task as symbol like :meet_a_person,  :say_hello etc

arguments : arguments are passed as array, following the name

dependency : the dependent task to be performed before performing a task is passed as array after =>

=> Listing the custom task

As usual, now when you run rake -vT. It will list the task name with description of what you can do with that task

$ rake -vT

rake demotask:call_friend[friend1,friend2]              # going to call two of my friend
rake demotask:count_records[model]                      # count number of records in given model table
rake demotask:current_environment                       # display the current environment of rake
rake demotask:hello_env                                 # I will say hello to the person after meeting and check environment
rake demotask:meet_a_person                             # You are going to meet a person
rake demotask:say_hello                                 # I will say hello to the person
rake demotask:with_environment                          # load environment before operating on any model object
rake demotask:without_environment                       # see what happen when you call a modal method without loading

=> Running the rake task from terminal

I will show you how to run these task from terminal, with small description where ever needed.

$ rake demotask:current_environment # below is the output , as no environment is passed default development is taken
You are running rake task in development environment

$ rake demotask:current_environment RAILS_ENV=staging # here see how we are passing the environment in which task need to be run
You are running rake task in staging environment

$ rake demotask:current_environment RAILS_ENV=production # this time passing production environment
You are running rake task in production environment

$ rake demotask:meet_a_person # this will just print the message
I meet a person on the way to my house

$ rake demotask:say_hello # see that since meet_a_person is dependency of say_hello, its code is executed first
I meet a person on the way to my house # this message coming from  meet_a_person task, executed first as being a dependency
I said HELLO to the person # hello is printed now, if dependency fail, this task will also fail

$ rake demotask:hello_env #this task have multiple dependency, each called in order they are specified in the task
You are running rake task in development environment
I meet a person on the way to my house
I said HELLO to the person

$ rake demotask:call_friend # you have not passed any argument so default will be printed, also see the value stored in t and args variable
demotask:call_friend # coming from t variable, thus it contain the task name
{:friend1=>”John”, :friend2=>”Dough”} # see that args is generated as a hash
Hello John
Hello  Dough

passing arguments to rake command in rails 3 . when you define any task with argument, while passing it from console, do not use space between different argument otherwise will throw error as below.
$ rake demotask:call_friend[“arun”, “sanjay”]
rake aborted!
Don’t know how to build task ‘demotask:call_friend[arun,’ # see that task name is choped when space encountered , so do not use space between argument
/home/arun/.rvm/gems/ruby-1.9.3-p194@threepiller/gems/rake-10.0.4/lib/rake/task_manager.rb:49:in `[]’
/home/arun/.rvm/gems/ruby-1.9.3-p194@threepiller/gems/rake-10.0.4/lib/rake/application.rb:142:in `invoke_task’
/home/arun/.rvm/gems/ruby-1.9.3-p194@threepiller/gems/rake-10.0.4/lib/rake/application.rb:70:in `run’
(See full trace by running task with –trace)

$ rake demotask:call_friend[“arun”,”sanjay”] # passing argument to rake task
demotask:call_friend
{:friend1=>”arun”, :friend2=>”sanjay”}
Hello arun
Hello  sanjay

$ rake demotask:without_environment # task fail as environment is not loaded so, model, gems, library function etc is not available to rake
rake aborted!
uninitialized constant User

$ rake demotask:with_environment # this will work as this task load environment as its dependency
Jeff Smith

NOTE : for a rake task to use all the methods in your gems, you library, your models i,e available anywhere in your application, you must load environment as its dependency. see with_environment task written above

$ rake demotask:count_records # will count the number of records from User model table
No of records is 13 #my user table have 13 records

$ rake demotask:count_records[Role] # will count the number of records from Role model table, passed here as argument
No of records is 7 #my role table have 7 records


Leave a comment

bootstrap popover

Bootstrap provide a number of js plugin listed here. Here I will create a popover to display message about the input to be filled,when a user try to enter something in it. Let us first define a input field on which we implement popover.

In ruby on rails it has below syntax.

<%=text_field_tag "routing_number", @loan[:RoutingNumber] , 
'data-content'=>"Routing Number is a 9 digit number starting with 0, 1, 2 or 3.",
'data-placement'=>"top"
%>

The important point above to note is the use of data attribute to add any value to a html element in unobtrusive way. Any property provided by bootstrap can be added in this way (i,e ‘data-property’ => ‘value’). I have set the property content and placement in the above code. the value set to data-content will give the text to be shown in the popover and data-placement will decide whether it appears right left top or bottom.Other available property for popover listed here is animation , html, selector, trigger, title, delay and container .

The above code in pure html can be written as below

<input type="text"  name="routing_number" id="routing_number" 
data-content="Routing Number is a 9 digit number starting with 0, 1, 2 or 3." data-original-title=""
data-placement="top"
/>

Now we will write our jQuery code to add popover on the input. When a user type a character, popover will appear with the message. It will be removed when he click anywhere out side i,e if input get blur

var showpopup = function(){
$(this).popover('show')
};

var hidepopup = function(){
$(this).popover('hide');
};

$("#routing_number").keypress(showpopup); # will show the popover on enter of a charecter
$("#routing_number").blur(hidepopup); # will hide the popover

The other event available for popover besides show and hide is destroy and toggle . Also note the use of jQuery events keypress and blur . other event listed here is change(), focusin(), select(), submit() .