Wednesday, May 14, 2008

Tried KDE4 on Kubuntu

I've been testing Kubuntu with KDE4 today and have learnt two lessons.

1) There's nothing to be eager about KDE4. I mean, seriously, the guys do a good job, but this is still the same good old kde3. Those plasma and dolphin stuffs, doesn't change much, that's like a good version of the superkaramba project, it looks nice but practically doesn't change the workflow at all. And as 99% of applications still from KDE3, if don't mention internal changes, in really you've got a new nice theme for kde.

I'm little bit disappointed, the fourth version was anounced for good couple of years ago and then been delayed several times and as the result we've got something pretty raw and almost nothing new.

Yup, that's it, there's nothing in really why you should migrate to kde4 so far.

2) The quality of kubuntu is lower then the quality of ubuntu. Sorry gus, but that's true. There are several things which works out of box in ubuntu, but doesn't work in kubuntu. Several things are left behind in order to keep the kde-purity, that left a bad feeling.

Monday, May 5, 2008

Order By Aggregations With ActiveRecord

The issue is following, say you have got a classical structure in two models

class Order < ActiveRecord::Base
has_many order_items

def total_due
order_items.to_a.sum(&:total_price)
end
end

class OrderItem < ActiveRecord::Base
belongs_to :order

# and it has two principal fields
# decimal :price
# integer :quantity

def total_price
price * quantity
end
end

As you see the orders don't have own total_due fields, instead of this each order can calculate the value depend on the aggregated items. So, that's cool, we follow all the good design habits and keep the things clean.

But when you retrieve/display the orders list there might be a situation when a customer would like to order the list by the total_due value. Quite a natural desire, but there's the problem, we don't have the total_due field in really. It's virtual and depend on the aggregated objects.

Yes, you may reorder the items after retrieving, manually, but if you have quite a lot of orders and use a pagination you'll get back to the problem anyway.

The example is pretty simple, but you see, there might be lots of similar situations when you have some calculations on an aggregated data and would like to order your lists depends on the virtual fields.

So, how do we handle that?

We use the :select option for the ActiveRecord find method. Usually with the option you specify a number of fields you would like to extract, to not suck up heavy ones when you don't want them. But with the same option you may specify additional fields to extract and use all the power of SQL expressions. Those new fields will be added to the instanced object temporary, you can read them but you can't save them.

In our case this might be something like that

:select => "SUM(order_items.price * order_items.quantity) as total_due"

In the case we are using the SQL function SUM, calculate the total-due for each order, and then each selected order will obtain the total_due attribute after extraction and you may use it for your sorting options.

Then, as you see we mentioned the 'order_items' column in the select option, to make it working we should add a tables join and the items grouping options. The overall instruction might look like that.

Order.find(:all,
:select => "SUM(order_items.price * order_items.quantity) as total_due, orders.*",
:joins => "INNER JOIN order_items ON order.id = order_items.order_id",
:group => "order.id",
:order => "total_due"
)

After this you will need to fix your Order model a little, to make it use the temporary field when it appears

class Order < ActiveRecord::Base
def total_due
self[:total_due] || order_items.to_a.sub(&:total_price)
end
end

Yes, that looks a little bit sqlish dirty for a rails application, but then it works and does what you need.

And there's another issue with the solution. You actually cannot use the :include option with the :select option at the same time. That's usually not a big issue, just note, if you specify the :include option, your :select option won't work.

Friday, April 18, 2008

I think stories need chapters

This rspec's stories stuff is quite nice, I like it. But when I'm trying to write more or less complex story it turns out to a nightmare. It's quite hard to stay on the DRY way with the stories, you always need to repeat the stuffs again and again. Even if you organize your code in good and handy steps, you'll have to repeat them in the scenarios anyway.

So, I think it would be cool to have in the stories another level aka Chapter. Think even nested chapters. I could look like that.

Story "an item live-story" do
Chapter "items index" do
Given "two items"

Scenario "anonymous gets the index" do
Given "an anonymous user"
When "he GET /items"
Then "he should be redirected to the login_path"
end

Scenario "registered user gets the index" do
Given "a logged in user"
When "he GET /items"
Then "he should see the 'items/index' page"
And "both items should be on the page"
end

Then "something in common happens"
end
end

The idea is that the chapters were working like scopes for the inside subchapters and scenarios. You may specify there common givens and thens which will be applied to the internal parts. May be it could be useful to be able to attach additional steps for particular chapters.

Wednesday, April 16, 2008

Ajaxload - The Spinners Generator

Found today the resource ajaxload.info, you can generate your custom ajaxload spinners there.

The guys did pretty well I should say. There are lots of patterns, you can choose a transparent background and custom colors.

Nice stuff.

Tuesday, April 15, 2008

Displaying GIT Branch Name In Your Console

So, if you had been taken the gateway drug of GIT recently, then you probably feel the sake of branches and there's a little trick for you dear fellow.

Put (or change) the following stings in your ~/.bashrc file and you'll get a nice enhancement on your console prompt which will show your current git-branch when you're in a directory which is under git.

function git_branch {
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /'
}

PS1='\[\033[0;37m\][\[\033[01;36m\]\W\[\033[0;37m\]] \[\033[0;32m\]$(git_branch)\[\033[00m\]\$ '

This is quite handy when you use the branches feature actively.

Sunday, April 13, 2008

Rescue data from a reiserfs partition

Couple of days ago, I met a situation, when my /home partition, which was on reiserfs filesystem, all the sudden, got dead. It was not able to restore the partition with reiserfs utils, it didn't want to mount anymore, info said there only 563 Kb of 60 Gb data left. Not good.

I've spent a day rescuing the data, and managed to get back 99% of it (i belive), so now I share the experience.

The rule number one in such a situation is to calm down. Sit down, take a blank sheet of paper, a pencil and then in a nice friendly characters write the phrase "DON'T PANIC".

I'm serious, it's pretty easy to get jumpy and overreactive when "all of yours" suddenly getting disappeared. And surrely it's easy to broke something down completely. So, don't touch anything until you get back to the cool consciousness.

The second thing you need, is a complete copy of your damaged partition. For that you'll need another free partition with exact same size. If you have such space on another hard drive, create it there, or think about baying another one.

Once you have your new partition for the backup. You need to boot up on some kind of live-cd with a linux environment. I've used the ubuntu 7.10 live-cd, it's quite handy, understand most of the modern hardware, contains the gparted util, have a web-browser etc. So it's stuffed pretty good for our purpose.

When you have your live cd booted up, you may copy the partitions. There's a builtin prgramm called 'dd', which allows you to copy block devices byte by byte, one to another. So you run it like that.

$ sudo dd conv=noerror if=/dev/old of=/dev/new

Where the '/dev/old' and '/dev/new' are your damaged and backup partitions. The optional attribute 'conv=noerror' tells the commad to skip reading errors.

Optionally you may unlock the 'universe' repository and install the 'dd_rescue' prgramm, which I belive, a wrapper for the 'dd' command and provides some more resuce oriended functionality.

The main point is to create an exact copy of the aviable data from the damaged partition.

And note, depends on the conditions, this may take quite a long time. My 60G partition was copied in about 7 hours.

That's it. Once you have a copy block. You run the 'reiserfsck' on the _copy_ partition like that.

$ sudo reiserfsck --rebuild-tree -S /dev/new

Note the '-S' option. This tells the reiserfsck programm to scan the whole partition for the aviable data. It's important, don't miss it up.

This operation usually is quite fast. Depends on the size of your data, and its condition this will take some minutes.

After the reiserfsck pargamm have finished, mount your new partition and take a look how is it going. If your partition was not damaged too hard, most of the data and directories structure will be on the right places. And there will be the 'lost+found' directory, take a look in it too, there will be lots of directories and subdirectories named with numbers. The util put there the files which were recovered but which former place was not found. And you may find there some files which you have deleted recently. So browse throw the directories, you may find some valuable data there too.

This is pretty much it. In really it's qute a simple stuff. Just don't get scary, some bad blocks on your hard drive is not a big problem, most of your data usually safe untill the harddrive any-working.

Sunday, April 6, 2008

Wish that thing in Ruby


class Array
def ||<<(i)
<< i unless include? i
end
end

Think, that would be logically appropriate, in similar to the ||= operation