View posts for Category "Development"

rating_for – A context-based rating plugin for Rails

Today I’ve released my rating_for plugin for Rails. It allows to add multiple rating categories to one ActiveRecord model. For example if you’re building a hotel review website, the rating_for plugin can save you some work:

class Hotel < ActiveRecord::Base
  rating_for :room_service
  rating_for :quality
end

four_seasons = Hotel.find_by_name("Four Seasons")
four_seasons.rating_for_quality.add(10)
four_seasons.rating_for_room_service.add(9)

rating = Rating.new(:value => 7)
marriott = Hotel.find_by_name('Marriott')
marriott.rating_for_room_service << rating

hotels = Hotel.find_where_quality_has_average_rating_of(10)

For more info and installation instructions, you should take a look at the plugin’s GitHub page: http://github.com/frane/rating_for

By the way: Since we’re currently on the edge between Rails 2.3 and 3.0, I’m happy to announce that the rating_for plugin is compatible with both versions.

Any kind of feedback is welcome and if you’ve got questions, just ask!

Leave a Comment

Rails I18n and emails

Since version 2.2, Ruby on Rails comes with an integrated support for internationalization (I18n) which makes developing multi-language websites very easy. Here’s how it works. Recently I worked on a project where I used the I18n API to provide multi-language support. The website had a user system and the user was able to change the web-site’s language in his/her profile. Basically, there was a model “User” with an attribute “language”, which was stored in the database. Every time when a user would log in on the website, the web-site’s language would change to the user’s preset language with:

I18n.locale = current_user.language

However, there was a problem with the emails, which a user automatically received from the web-site. I used a cron-job with Rails’ “script/runner” to periodically send mails from a model like this:

class Task
  def self.send_mails
    User.all( :conditions => "want_mail = 1" ).each do |user|
        UserMailer.deliver_daily_mail(user)
    end
  end
end

The mail template was translated with the Rails I18n API like this:

<%= I18n.t 'daily_mail.hello' + @user.name %>
...

The problem was only that the mails were sent out in English because the web-sites default language (I18n.default_locale) was English and there was no “I18n.locale” set in “script/runner”. The easiest solution to that problem is to set the locale somewhere in your email setup:

class UserMailer < ActionMailer::Base
  def daily_mail(user)
    I18n.locale = user.language
    @recipients  = user.email
    @from        = "The Daily Mailer <daily_mail@example.com>"
    @subject     = I18n.t 'daily_mail.subject'
    @sent_on     = Time.now
    @body[:user] = user
  end
end

Alternatively, it’s possible to set the language in the email template:

<%= I18n.t('daily_mail.hello', :locale => @user.locale) + @user.name %>
...

It’s more a logical then a technical problem, but it shows how (logically) complicated multi-language web-sites can be.

Leave a Comment

Introducing Eject Volume

I’ve written my first MacOS X Dashboard widget today. It’s called Eject Volume and provides a handy way to eject volumes which are mounted on your system. More information about the widget and a download option is provided here.

Eject Volume Screenshot

2 Comments

Basic Authentication problems with Phusion Passanger (mod_rails)

Phusion Passenger aka. “mod_rails” is great! It makes Rails deployment pretty easy and time-saving. Unfortunately it has a bug in it’s current 2.0.6 version which breaks Basic Authentication. Though this bug is fixed in the unreleased 2.1 version (see here) you need to care about the problem by yourself for now. The only working solution for me was to user Rails’ Basic Authentication functionality by hacking the following into my application controller:

class ApplicationController < ActionController::Base

  before_filter :http_auth  
 
  ...

  private
 
  def http_auth
    authenticate_or_request_with_http_basic do |user_name, password|
      user_name == "JohnDoe" && password == "secret123"
    end
  end

end

At this point you can be as creative as you want with reading the user name and password form a file or database and checking hashed passwords instead of plain text. For my purposes this was just enough, so I didn’t waste any more time on it. At the end of this post be warned: Basic Authentication through Rails does only protect your application, but it does not protect the static content in your public directory.

1 Comment

How to download videos from YouTube

YouTube is the world’s #1 source for more or less funny or interesting videos. Unfortunately YouTube does not offer any options to download the videos from their site. YouTube even hides the direct links to their video resources. Even though it’s quite easy to find a download link for the real .flv videos:

  • Just go to the site where your desired video is i.e. http://de.youtube.com/watch?v=-xEzGIuY7kw .
  • View the source code of the site and search for a section that starts with “swfArgs”.
  • From this section you need the values for “video_id” and “t” (i.e. “video_id”: “dsfaAfdaAfs” and “t”: “sdfkljasldfjlkasflshdfjaiosjjsknfjkhJhjdf”)
  • With these values you should be able to call “http://www.youtube.com/get_video.php?video_id=<your video_id value>&t=<your t vlaue>” and to download your desired video.

I’ve made a little shell script for Linux and Mac that does all the searching stuff for me and that returns the url to the video source.

#!/bin/sh

if [ $1 == "" ]; then echo -e "$0: No URL specified\nUsage: $0 <url>\n"; exit 1; fi

which curl > /dev/null
if [ "$?" == 0 ]; then GET_COMMAND=curl
else
  which wget > /dev/null
  if [ "$?" == 0 ]; then echo "Didn't find curl nor wget. Exiting."; exit 1;
  else
    GET_COMMAND=wget -O ytf| cat ytf; rm ytf;
  fi
fi

# Use GNU version of sed on Darwin/OS X
if [ `uname -s` == "Darwin" ]; then SED=gsed;
else SED=sed; fi

RELEVANT_DATA=`$GET_COMMAND $1 | grep 'swfArgs' | $SED 's/,/\n/g'`
VIDEO_ID=`echo "$RELEVANT_DATA" | grep 'video_id' | $SED 's/"//g' | $SED 's/ //g' | $SED 's/:/=/g'`
T=`echo "$RELEVANT_DATA" | grep 't"' | $SED 's/"//g' | $SED 's/ //g' | $SED 's/:/=/g'`

LINK="http://www.youtube.com/get_video.php?$VIDEO_ID&$T"

if [ "$VIDEO_ID" != "" ] && [ "$T" != "" ]; then echo $LINK; exit 0;
else echo "Couldn't retrieve the needed data from the specified URL."; exit 1;
fi

To run the script correctly the GNU version of “sed” is needed.

Leave a Comment

Qt4.4 for beginners

Quite some time ago I have worked with Qt3 and C++ to do some Linux projects. I had taken a look on GTK and wxWidgets too, but I felt most comfortable with Qt.

Now I had to build small program that was able to play a list of audio files and to give the user an option to rate these files. It’s a quite simple little program which for some reasons is needed to be written in C++.

So I installed Qt4.4 and started Qt’s Designer. I spent half an hour searching the source code editor in Designer. After five minutes with Google I found out that one “feature” of Qt4 was the complete separation of GUI code and logic code, so I had to work a slightly different way from what I was familiar with. Though I never used Qt’s Designer that way (usually I coded the whole GUI stuff by hand or used Designer’s built-in source code editor), I started “designing” my GUI. After I was finished I saved the file as “MainWindow.ui” (I know it’s not a smart name but I don’t care). So, what now? There were no other files and the Designer wasn’t able to produce any other files. The answer: qmake! qmake is some kind of Qt’s own make, which is not intended to replace make, but to give you a smart ability to handle *.ui and other Qt related files. One just needs to create a file named somefile.pro and add something like the following code to it:

HEADERS += MainWindow.h #as my ui file is MainWindow.ui
FORMS += MainWindow.ui # my ui file created by Qt Designer
SOURCES  += main.cpp MainWindow.cpp

This should be enough for a valid and working .pro file. Now there are three new file mentioned in the .pro file which are not existing yet. So where do we get these files from? We just create them ourselves. Let’s start with the main.cpp. It’s intended to be – guess what… So, what does it look like:

#include "MainWindow.h" // to integrate my MainWindow class from created by the Designer.
int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  MainWindow *window = new MainWindow;  //create an instance of our window
  window->show();                       // show our window
  return app.exec();
}

Curious about what the MainWindow.h file is needed and used for?

#ifnedf MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_MainWindow.h"
class MainWindow : public QMainWindow, private Ui::MainWindow
{
  Q_OBJECT
  public:
  MainWindow(QWidget *parent = 0);
};
#endif

First of all one has to understand where the “ui_mainWindow.h” comes from. It’s automatically generated by qmake when you call it. qmake simply generates C++ code out of the XML-ui file. Your can call qmake right now it should generate an “ui_MainWindow.h” file and a Makefile which will be called later. Another alternative to generating “ui_MainWindow.h” is to call the command

uic -o ui_MainWindow.h MainWindow.ui

qmake itself calls uic to get the “ui_MainWindow.h”. Now if you take a look at the “ui_MainWindow.h” you’ll see that it contains pure C++ code calling the different Qt classes to draw the GUI. With “class MainWindow : public QMainWindow, private Ui::MainWindow” in MainWindow.h we inherit the Ui::MainWindow class produced by uic and are able to define our methods, attributes an so on… Now it’s time to create our MainWindow.cpp. This file is also pretty simple but important.

#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent) {
  setupUi(this);
}

By calling setupUi in the constructor, the GUI elements, which were added to the interface with the Designer, are painted the first time. You can comment the setupUi line out and see what’s happening. After all of these steps we’re finally finished… or let’s say nearly finished. If you have followed all these steps carefully you should call

make

to process the Makefile previously created by qmake. Note: If you use Qt/Aqua on MacOS X, the qmake will produce a something.xcodeproj file/directory instead of a Makefile. To build your foo.app you’ll need to call xcodebuild instead of make.

If you get some errors while building your app, you’re on your own. I’m done for now ;-) . If you need more information on Qt then take a look at http://doc.trolltech.com/4.4/index.html . But you’re also free to comment or ask to me ;-) .

1 Comment