Creating PDFs under Wine.

This morning I needed to create a PDF file under wine on my Ubuntu machine. Nothing easier than that: You will need to install cups-pdf.

sudo apt-get install cups-pdf

This will automatically install a “virtual” printer which is selectable in the print dialog of all windows applications installed under wine. After printing, the PDF may be found in a folder PDF directly under your home directory.

Old Agfa Snapscan on Ubuntu 9.10.

This morning I tried to use may very old and almost antique scanner Agfa Snapscan e20 with my brand new Ubuntu 9.10 and xsane.

Surprise, surprise, it did not work. So, I started searching for a solution on Google, read myself through many boards and finally constructed this solution from all I read (and thought myself, of course *g*):

1. First of all you need the proprietary Windows driver of your Snapscan device. This can be found here.

2. The downloaded ZIP archive will contain a file called 2.0.0.9-e20.exe. You will need to extract all files from that exe to get a file called snap20.bin. But how do you do that? The file is not a self extracting ZIP archive. So, unzip does not work. In this case wine is your friend:

sudo apt-get install wine

Open the exe file with wine. Leave the initial screen open but do not follow the installation routine further on. Instead, copy the needed file from the temp directory of wine:

sudo cp ~/.wine/drive_c/windows/temp/Drivers/snap20.bin /etc/sane.d/

Now, close the installer.

3. Now edit the configuration file /etc/sane.d/snapscan.conf and add (or modify if present) that line:

firmware /etc/sane.d/snape20.bin

4. Start xsane and start scanning

Ubuntu 9.10 64bit vs. Broadcom

Well, I actually didn’t think about my WIFI-chipset when I bought my Dell Studio notebook: If Dell offers Ubuntu as an operating system along their products anyway, there should not be a driver problem when manually installing Ubuntu. After installing 8.04 and later 8.10 and 9.04 (32bit by accident), it worked out of the box: The Broadcom driver for the BCM4312 chipset was proprietary and I didn’t have a single problem.

Yesterday I decided to get rid of the 32 bit 9.04 version and install the Ubuntu 9.10 beta version. Installation worked fine, but after rebooting the system I saw that there was no wireless network connection at all. Running lsmod told me that the b43 module is running. However, it didn’t work: no network connection was shown, not even that it recognized my WIFI card.

After reading through several blogs and forums I finally got it running. This installation guideline might help you, too. Maybe the driver will be included / fixed in the final 9.10 version, but just in case it’s not, this might be a solution for you:

1. Compile Broadcom driver

Download the driver from the official Broadcom website and follow the installation instructions in the README.txt.

After compiling the module and adding it via “modprobe” as described in the README.txt file, it already worked fine for me: The system connected to my local WIFI access point.

2. Load driver on startup

What didn’t work was the automatic disabling of the ssb module by adding it to the blacklist. The command lsmod still showed that the module was loaded even though it was added to the /etc/modprobe.d/blacklist.conf. Therefore, after a reboot of the system I still had no connection at all and had to manually modprobe wl again. Adding “wl” to the list in /etc/modules showed no effect.

Here is the solution I found on another forum (don’t find the URL anymore):

Add these 3 lines to /etc/rc.local:

rmmod ssb
modprobe -r ssb
modprobe wl

After a reboot, the network service now automatically took the newly installed driver.

Ruby Hash: Convert String keys to Symbols

Ever had a hash which contained strings as keys and needed symbols instead? I do: From a REXML::Document I created a hash. Unfortunately, the keys were all strings and I needed them to be symbols at some other point in the app. Thank god, Ruby is capable of extending any object “on the fly”. So, I wrote a simple extension to Hash, which you might find useful as well:

class Hash
  #take keys of hash and transform those to a symbols
  def self.transform_keys_to_symbols(value)
    return value if not value.is_a?(Hash)
    hash = value.inject({}){|memo,(k,v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo}
    return hash
  end
end

Usage is:

a = { "key" => 123, "inner_hash" => { "another_key" => "blabla" }}
Hash.transform_keys_to_symbols(a)
#returns
a = { :key => 123, :inner_hash => { :another_key => "blabla" }}

Passenger and OpenID

I recently updated Passenger 2.0.6 to 2.2.4 and experienced that openID logins were not working anymore. Seems like it tries to log output to some strange log location.

However: If anyone comes across the same problem: Simply add

OpenID::Util.logger = RAILS_DEFAULT_LOGGER

to your environment.rb file and everything will work like a treat again.

Rails’ to_xml w/ multiple associations.

This is a pain and took me about an hour to figure out today.

Rails ActiveRecord instances offer a nice function to render xml:

my_model.to_xml()

This method can be fed with a parameter

:include => []

to have all associations being integrated in the XML tree, just like when calling

my_model = MyModel.find( :include => [association])

But when I tried to use it, it always failed when dealing with nested associations. Until I found out the trick.
This is how it works: Basically you need to build a list of nested hashes.

class Book < ActiveRecord::Base
  has_many :pages
  has_one :owner
end
class Owner < ActiveRecord::Base
  has_many :books
end
class Page < ActiveRecord::Base
  has_many :spots_of_coffees
  belongs_to :book
end
class SpotOfCoffee < ActiveRecord::Base
  belongs_to :page
end

Now, you want to create a nice XML output containing a book, with its owner, pages and all spots of coffee?
Pretty easy:

  @book = Book.first
  includes = {} # let's build a hash; it's easier to read. At least for me...
  includes[:owner] = {} # owner has no association. So, let's take an empty hash as target
  includes[:pages] = { :include => :spots_of_coffee } #load pages and include its spots of coffee
    
  respond_to do |format|
    format.xml  { render :text => @book.to_xml(:include => includes) }
  end

Rails: Custom image sizes using has_attachment

Ever wanted to offer users the possibility to define their very own image sizes for uploaded pictures?

Here’s how you can quickly do that.

You will have a class acting as a an attachment such as:

class AssetImage < ActiveRecord::Base

has_attachment :content_type => :image,
:storage => :file_system,
:max_size => 1.megabytes,
:path_prefix => "public/system/images/#{ActiveRecord::Base.configurations[RAILS_ENV]['domain_name']}/assets/images",
:thumbnails => { :large => '450>', :normal => '300', :medium => '200', :thumbnail => [100,75] },
:processor => :rmagick

validates_as_attachment

...

First add a cattr_accessor to store your custom size in the class:

cattr_accessor :custom_size

Now, add a before_save callback which takes the assigned value and adds it to the list of requested image sizes. It is using the value as a minimum size while keeping aspect ratio.

#store custom size
def before_save
  return if AssetImage.custom_size.nil?
  attachment_options[:thumbnails][:custom] = AssetImage.custom_size.to_s + ">"
end

In your controller do something like this: Take a value from your parameters and store it in your model to have your image customized.

def add_image
  AssetImage.custom_size = params[:custom_size].to_i.to_s rescue "100"
  a = AssetImage.new(params[:asset_image])
  a.save
  redirect_to :action => :index
end

Nerd stuff.

Die Agentur Seibert Media hat einen kleinen Programmierer-Wettbewerb laufen:

Wer den schlankesten Code schreibt, der einen Weihnachtsbaum auf dem Bildschirm erzeugt, bekommt einen netten iPod-Schuffle.

Hier mein Beitrag, geschrieben in Ruby:

puts (0..30).map{|x|" "*(30-x)+"XX"*x+"\n"}.join+(" "*29+"||\n")*2

Und die Ausgabe auf der Konsole mit IRB:

                             XX
                            XXXX
                           XXXXXX
                          XXXXXXXX
                         XXXXXXXXXX
                        XXXXXXXXXXXX
                       XXXXXXXXXXXXXX
                      XXXXXXXXXXXXXXXX
                     XXXXXXXXXXXXXXXXXX
                    XXXXXXXXXXXXXXXXXXXX
                   XXXXXXXXXXXXXXXXXXXXXX
                  XXXXXXXXXXXXXXXXXXXXXXXX
                 XXXXXXXXXXXXXXXXXXXXXXXXXX
                XXXXXXXXXXXXXXXXXXXXXXXXXXXX
               XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
              XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
            XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
           XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                             ||
                             ||

Use ar_mailer for future mail delivery

This little howto describes, how to use ar_mailer to schedule emails for future delivery.

Sorry for the bad formatting. Might change it someday…
1) Migrate emails table and add needed fields

  add_column :emails, :various, :string #holds classname and id of any object you want to
  add_column :emails, :type, :string #type of email
  add_column :emails, :date_to_send, :date #date to send that mail

2) Override “def find” in email.rb

  def self.find(*args)
    with_scope(:find=>{ :conditions=>["(date_to_send IS NULL OR date_to_send <= ?)", Date.today] }) do
      super(*args)
    end
  end

3) Create DelayedEmail class, inherting Email

  class DelayedEmail < Email
    before_save :set_due_date
    before_save :set_various_field
    @@days_before_sending = 21 #default is 3 weeks after creation of various object
    @@various_class = nil

    def set_due_date
      self.date_to_send = Date.today + @@days_before_sending
    end

    def set_various_field
      name = @@various_class.class.to_s + "_" rescue "NOCLASS_"
      id = @@various_class.id.to_s rescue "0"
      self.various = name + id
    end

    #tell email to which object it belongs. might be important for future deletion of unsent mails
    def self.set_various_class(c)
      @@various_class = c
    end

    #tell email how many days shall pass by before sending email
    def self.set_days(days)
      @@days_before_sending = days
    end
  end

4) Modify ar_mailer standard emailer class in controller before delivery and set it back afterwards

  DelayedEmail.set_days(10)
  DelayedEmail.set_various_class(SOMEOBJECT)
  ActionMailer::ARMailer.email_class=DelayedEmail
  #Let any mailer send an email through this class
  #eg. Mailer.deliver_mymail(...)
  ActionMailer::ARMailer.email_class=Email