Thread.new - dRuby now much more useful with Rails (2.2)

Rails 2.2 recently entered RC1 with loads of exciting features. Among built-in internationalization and bunch of other improvements, long awaited thread safety arrived. This was something that we (RoR users) were jealous when looking at Merb framework for quite a long time now.

Even if you are not using threaded server for your applications, and still use traditional mongrel/thin/whatever cluster, it’s good news for you. It’s even better if you use JRuby… but back to topic now.

Now, it’s easy to run long lasting tasks in your models for excellent description, look at Pratik Naik blog. It’s perfectly safe to write following code in your controllers now:

...

def create
  @post = Post.create(params[:post])
  Thread.new do
    @post.republish_content_on_some_slow_responding_sites
  end
end

...

However, I found thread safety even more useful for my recent project, with dRuby server running in the background. Now I can get rid of global mutex in my background process and enjoy one dRuby server shared among multiple server instances. I am running 5 instances of mongrel, each of them using heavily drb daemon which processes ActiveRecord objects - now I get 5x boost in speed with thread safe Rails :)

Posted by Hubert Łępicki Wed, 05 Nov 2008 22:48:00 GMT


BGUL Ruby in Linux example source code

This might be useful for these present at today’s BGUL meeting, but not only. Basically, I have demonstrated how to develop simple script useful for sysadmins, that checks if web pages are up and running, and stores results in MySQL database.

Additional cleanup, error handling and comments added (in Polish, sorry).

Full code is here

Posted by Hubert Łępicki Wed, 29 Oct 2008 22:53:00 GMT


War. 2.0

Russia went yesterday on war with Georgia. Despite the fact that it’s horrible barbarian behavior of Russian Federation, and violation of international law, it is different than any other conflict we saw that Russia was involved in the past. Georgia was attacked not only by bombers, troops and tanks - it was attacked by hackers too.

Most of high-traffic Georgian web pages were taken down - and not by means of destroying infrastructure by by bombers - they were hacked. All web servers of Georgian government, and prominent newspapers (like The Georgian Times) are either down, displaying error messages or their front pages were replaced by attackers.

You might want to ask why this is a big deal? Propaganda. Thing that Russians were always good in, now came to next level. By cutting off Georgian and international users from sources within Georgia, Russians wanted to spread fear among civilians. In addition to that, they were able, at least at some point, to show the world their version of events - without possibility to hear Georgian response.

What is also interesting is that this was organized attack, coordinated by Russian army. It shows that they maintain special cyber-forces that are able to attack from within Russian territory anyone. It is also interesting that such attack is not military attack in view of international law. Scale of this event shows also that attack was carefully prepared. This takes resources (money, people’s working hour, hardware) and time. Without previous preparations, such attack couldn’t succeed. This leads me to idea that Russia - in general - was preparing to military attack on Georgia for months.

Are we, members of western countries prepared for such cyber-attack? I think not. It’s probably worse in Europe than in US. We (Europeans) didn’t put enough care in security of our systems, or government IT infrastructure in general. We also do not have any significant cyber-forces that could prepare such attack. Is it time for EU countries to wake up and prepare for war 2.0?

Posted by Hubert Łępicki Sat, 09 Aug 2008 15:18:00 GMT


Extending rails form helpers: a spinbox field

Spinboxes are common control in all desktop GUI applications. They’re found in all windowing toolkits that I know, and I use it all the time to input numbers. However, when it comes to web applications they are not so common. This is because (X)HTML doesn’t define such control.

I have found this great widget that requires prototype library only. It nicely degrades to text field when user doesn’t have javascript on, and is easy to use. However, I wanted to make it play nicely with Rails forms, to easily set up initial value etc.

Nothing easier. Just paste the following code to new file called lib/formhelperextensions.rb in you rails app:


module ActionView
  module Helpers
    module FormHelper
      def spinbox_field(object_name, method, options = {})
         min_val = options.delete(:min)
         max_val = options.delete(:max)
         tag = InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_input_field_tag("text", options.merge({:class =>"spin-button"}))
         script = '<script type="text/javascript">new SpinButton($("'
         script += "#{object_name}_#{method}"
         script += '"),{'
         script += "min:#{min_val}" if min_val
         script += "," if min_val and max_val
         script += "max:#{max_val}" if max_val
         script += '});</script>'
         tag+script
      end

    end

    class FormBuilder
      def spinbox_field(method, options = {})
        @template.spinbox_field(@object_name, method, options)
      end
    end
  end
end

and include the file at the end of your config/environment.rb

....
require "form_helper_extensions"

Now, get a prototype-spin-button compressed archive, unpack it and copy spinbutton.js to your public/javascripts/ directory. Create file public/stylesheets/spinbutton.css and place following code in it:


input.spin-button {
  padding-right:20px;
  width:35px;
  background-color:white;
  background-repeat:no-repeat;
  background-position:100% 0%;
  background-image:url(/images/spinbtn_updn.gif);
}

input.spin-button.up {
  cursor:pointer;
  background-position:100% -18px;
}
input.spin-button.down {
  cursor:pointer;
  background-position:100% -36px;
}

Last bit is to copy image spinbtn_updn.gif from zip archive to your public/images directory.

And, when you include spinbutton CSS and spinbutton.js in your view, you can use spinbutton in your forms! Your layout should have:

  <%= javascript_include_tag :defaults %>
  <%= javascript_include_tag "spinbutton" %>
  <%= stylesheet_link_tag "spinbutton" %>

Use it in your forms, like you use text button:

 form_for @user....
   f.text_field :name
   f.spinbox_field :age, :min => 0, :max => 120
 end

Enjoy!

Posted by Hubert Łępicki Thu, 07 Aug 2008 07:53:00 GMT


BGUL / JTeam meetings - 02.04.2008 and 09.04.2008 ][

Posted by Hubert Łępicki Wed, 09 Apr 2008 21:33:00 GMT


Web pages creenshots using WebKit, Qt, C++ and Ruby on Rails - Part 1

There are many places where we would love to see web sites screenshots in our applications. And there are places that you can get some, check out his list.

However, with some nice Linux libraries, and a bit of C++ development skills (really a bit), you can get some for free.

In this tutorial I will use Trolltech’s Qt Library version 4.4 beta. Please make sure that you have Qt 4.4 beta or greater installed in your system before trying to compile example program.

Goals

Today, our goal is to create simple C++ app, that will work from command line and will allow us to take web site screenshots of any pages.
Later on, we will use it from within our Rails application.

Requirements

You’ll need Qt version 4.4 beta or greater, a c++ compiler and virtual X server for your Unix server on which application will be installed. I am going to use Xvfb, which is part of standard Linux X server.

Source code

Our application will consist of 3 files: main.cpp, shoter.h and shoter.cpp. main.cpp will be only used to call object Shoter that’s specified in two other files and take screenshots.

main.cpp

#include <QtGui>
#include <QtWebKit>
#include <shoter.h>


int main(int argc, char** argv) {
     if (argc != 3) {            
        qDebug("Usage: webkitshoter http://exampleurl.com file.png");
        exit(EXIT_FAILURE);                                          
     }                                                               
     QApplication app(argc, argv);                                   
     Shoter* w = new Shoter(QString(argv[1]), QString(argv[2]));     

     w->show();
     app.exec();
     return 0;  
}               

shoter.h

#ifndef SHOTER_H
#define SHOTER_H
class QWebView; 
#include <QWidget>

/**
        @author Hubert Łępicki <hubert@swarog>
*/                                            
class Shoter : public QWidget                 
{                                             
Q_OBJECT                                      
public:                                       
    Shoter(QString url, QString filename, QWidget *parent = 0);

    ~Shoter();

public slots:
    void grabScreen();


private:
    QWebView* view;
protected:         
    QString filename;
    QString url;     
    int width;       
    int height;      
};                   

#endif

shoter.cpp

#include "shoter.h"
#include <QtWebKit>
#include <QPainter>

Shoter::Shoter(QString url, QString filename, QWidget *parent)
 : QWidget(parent)                                            
{                                                             
     this->url = url;                                         
     this->filename = filename;                               
     QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptEnabled, false);                                                                      
     view = new QWebView(this);                                                 
     view->load(QUrl(url));                                                     
     width = 1024;                                                              
     height = 768;                                                              

     connect(view, SIGNAL(loadFinished()), this, SLOT(grabScreen()));
     resize(width, height);                                          
     view->resize(width, height);                                    
}                                                                    


Shoter::~Shoter()
{                
}                


/*!
    \fn Shoter::grabScreen()
 */                         
void Shoter::grabScreen()   
{                           
            qDebug("taking shot");
            QPixmap shot = QPixmap::grabWidget(this->view);

            shot.save(filename, "JPG");
            qDebug("shot taken");      
            this->close();             
}                                      

Well, more or less that’s it for very basic screenshoter! You can dowlnoad this code as a KDevelop project from here.

Compiling the project

It’s a fairly straightforward for Qt program, let’s comile it with: “qmake && make”.

Creating screenshots

You can find “webkitshoter” executable in “bin” folder. You use it like this:

./webkitshoter http://google.com googleshot.png

That’s it! You get 1024x768 screenshot.

Notes on how to use it from within Rails application in my next post!

Alternatives (the most important part of this post ;))

The code I have shown you here is pretty basic one. I know that there might bebetter alternatives you want to use. Good one is khtml2png, however it’s using KHTML engine which is not as good as WebKit (these two are much related!). I have used this one and even modified it so I can take screenshots of full web pages, not only part of them. Pretty neat stuff, I think it might be topic of next post…

If you are using WebKit on MacOS X, try WebKit2PNG. It does basically what my program does, but is using standard MacOS X WebKit engine and libraries (python).

And finally there are scripts that embed Gecko rendering engine into GTK+ windows. I found my installation of Gecko working unreliable in comparison with WebKit/KHTML, but you might try it! Good description is found on hackdiary.

Posted by Hubert Łępicki Mon, 07 Apr 2008 08:18:00 GMT


JTeam/Bgul Example rails 2.0 application

Posted by Hubert Łępicki Thu, 03 Apr 2008 21:36:00 GMT


BGUL / JTeam meetings - 02.04.2008 and 09.04.2008

This is announcement for our local Linux/Java community at Bialystok Technical University but… I’m a speaker at next two meetings of BGUL, together with JTeam. Subject - JRuby on Rails - I’ll try to prepare some cool examples of code that you might expect to appear on this blog this weekend / next week even before the first meeting.

Exactly when and where? This will appear on JTeam and/or BGUL web sites.

Everyone is invited!

Posted by Hubert Łępicki Fri, 28 Mar 2008 22:34:00 GMT


Announcing SimplierStats rails plugin

I am happy to announce my first Ruby on Rails plugin! SimplierStats is meant to be smarter and better plugin for collecting your web site statistics. It’s in alpha state right now, but I’m using it on this blog already! No real documentation yet, but check page on this blog aboutit.

Update

2 small updates by now - added geo IP (thanks to http://hostip.info) and simple authentication with HTTP basic and config YAML file.

Posted by Hubert Łępicki Fri, 14 Mar 2008 15:22:00 GMT


TinyMCE and AJAX

TinyMCE is a visual XHTML editor that you can put on your web app, to convert textareas into Word-like editors. This way you can make it possible for your clients edit pages more easily, saving you lots of trouble explaining them basics ofHTML or even easier formatting languages. TinyMCE doesn’t play well with AJAX calls, however it’s easy to fix it. I will use TinyMCE with Ruby on Rails, version 2.0.2

Let’s start with creating new application:

                                                                     
     [hubert@swarog ~]$ rails tiny_mce_ajax                                     
       create                                                                   
       create  app/controllers                                                  
       create  app/helpers                                                      
       ...........................                                              
       create  log/development.log                                              
      create  log/test.log                                                      
     [hubert@swarog ~]$ cd tiny_mce_ajax/                                       
     [hubert@swarog tiny_mce_ajax]$ ls                                          
     README    app     db   lib  public  test  vendor                           
     Rakefile  config  doc  log  script  tmp                                    

Now, let’s install tiny_mce plugin:

                        
     [hubert@swarog tiny_mce_ajax]$ ruby script/plugin install http://secure.near-time.com/svn/plugins/trunk/tiny_mce                                           
     [hubert@swarog tiny_mce_ajax]$ rake tiny_mce:scripts:install               

TinyMCE plugin used to work right after you do it, however something has changed either in Rails or the editor plugin that requires us to make a little hack here:

First, open this file with your favorite editor:

                                     
     vendor/plugins/tiny_mce/lib/tiny_mce.rb    

and put these two lines at top of the file:

                    
     require 'tiny_mce_helper'             
     include TinyMCEHelper                 

We’re ready to go. First, let’s create a RESTful controller:

                                                 
     [hubert@swarog tiny_mce_ajax]$  ./script/generate scaffold note body:text
     [hubert@swarog tiny_mce_ajax]$  rake db:migrate                          

An add TinyMCE and Prototype script links to HEAD section of our layout file:

                                                                  
     <script src="/javascripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>                                                                           
     <%= tiny_mce %>                                                            
     <%= javascript_include_tag :defaults %>                                    

At this point, we have TinyMCE installed in our application, that will be used on all textareas. However, this will not work if we add another textarea using JavaScript and/or AJAX calls.

To make it work, let’s add partial to our application:

file: app/views/notes/_new.html.erb

                        
     <% form_remote_for :note, @note, :update => { :success => "notes" }, :position => :bottom,     :url => { :controller => "notes", :action => "create" }, :after => "$('new_note').innerHTML = ''; "      do |f| %>                          
             <%= f.text_area 'body', :colls => 100, :rows => 10 %><br/>         
        <%= submit_tag "Save", :onclick=>"javascript: tinyMCE.triggerSave(); tinyMCE.execCommand('mceRemoveControl', false, 'note_body'); " %>                  
     <% end %>                                                                  

     <script type="text/javascript">
        tinyMCE.execCommand('mceAddControl', false, 'note_body');
     </scrip>                                                    

And modify our “index” view:

 Listing notes
       
     <table id="notes">
             <%= render :partial => "note", :collection => @notes %>
     </table>                                                       

     <br />

     <%= link_to_remote "New note", :url => { :action => "new" }, :update => { :success => "new_note" } %>                                                      

     <div id="new_note">

     </div>

Add partial for single note: _note.html.erb

                 
     <tr>                   
         <td><%=h note.body %></td>
         <td><%= link_to 'Show', note %></td>
         <td><%= link_to 'Edit', edit_note_path(note) %></td>
         <td><%= link_to 'Destroy', note, :confirm => 'Are you sure?', :method => :delete %></td>                                                               
     </tr>                                                                      

And modify “new” and “create” actions in our controller:
notes_controller.rb

                                                         
      def new                                                                   
        @note = Note.new                                                        

        if request.xhr?
               render :partial => "new"
        else
        respond_to do |format|
          format.html # new.html.erb
          format.xml  { render :xml => @note }
        end
        end
      end

      def create
        @note = Note.new(params[:note])

       respond_to do |format|
          if @note.save
            if request.xhr?
                    render :partial => @note
                    return
            end
            flash[:notice] = 'Note was successfully created.'
            format.html { redirect_to(@note) }
            format.xml  { render :xml => @note, :status => :created, :location => @note }
          else
            format.html { render :action => "new" }
            format.xml  { render :xml => @note.errors, :status => :unprocessable_entity }
          end
        end
      end

Download full source code example

Posted by Hubert Łępicki Sun, 02 Mar 2008 12:12:00 GMT