Tigraine

Daniel Hoelbling talks about programming

Removing delete and destroy in Rails models

Today I had an interesting feature request to implement: Get rid of all deletions and replace them with a deleted flag in the DB.

It's the usual story: Nobody really does deletes but rather everything is put into the DB in case it's needed at some later point. Unfortunately I didn't know about this particular feature until after I had finished most of the coding for the Rails application so going through the code and removing all destroy code from controllers was pretty much out of the question.

Instead I remembered reading about Modules in Ruby and how they can bolt on functionality to Classes.

Turns out it's totally trivial to remove deletion from Rails Models with 10 odd lines of code in a completely transparent an unobtrusive way:

module NotDeleteable
  def destroy
    unless self.respond_to? :deleted
      raise MissingMigrationException
    end

self.update_attribute :deleted, true end

def delete self.destroy end

def self.included(base) base.class_eval do default_scope where( :deleted => false ) end end end

class MissingMigrationException < Exception def message "Model is lacking the deleted boolean field for NotDeleteable to work" end end

This will override the default destroy/delete method provided by ActiveRecord::Base and also install a default_scope into the Model class so Rails will by default append WHERE deleted = false to all SQL queries made through the ActiveRecord Query Interface

You use this by simply including this module inside your Model class:

class User < ActiveRecord::Base
  include NotDeleteable
end
Did I mention that I really like Ruby?

Word of warning: I have no clue if I am breaking :dependant => :destroy on ActiveRecord relations in any way, but I suspect it should still be alright.

Update: The original code had an issue where you could not mark a record that is invalid as deleted. This was due to the fact that I was using save instead of update_attribute.

Filed under programmierung, rails, ruby

A word of advice on Bundler and Gems from git

At times (especially after Rails version upgrades) some Gems don't work out of the box so I usually spend some time on GitHub looking through the network graph for a fork that fixes the issue.

This works great and you usually end up with a well working plugin to continue working. Bundler supports this by loading the gem from the git source:

gem 'rails', :git => 'https://github.com/rails/rails.git'

Only problem with this approach: Forks are usually a moving target in regards to their longevity. People tend to delete them once the pull request gets merged, or simply forget about them.

Neither is desirable and today it bit me for the first time, I had referenced a fork that got deleted but contained a important fix for my project on a gem that was not yet 3.1 ready. Fortunately the project has moved along and the master already included the fix (and didn't introduce new issues). But it sure taught that I should always keep my own fork of code I decide to depend upon.

Filed under uncategorized

Make GNU screen xterm-256color work on OSX

I just ran into this and spend like 2 hours with Linux genius Jam trying to figure out why in the heck I could run Vim in 256 colors mode on my server while once I started screen it didn't work any more.

The issue was two fold. a) My local Terminal.app was reporting itself as xterm-color instead of xterm-256color. You have to update this setting in your Terminal app here:

 

Once done you only need to edit your .screenrc to include the following 3 lines:

 

# terminfo and termcap for nice 256 color terminal
# allow bold colors - necessary for some reason
attrcolor b ".I"
# tell screen how to set colors. AB = background, AF=foreground
termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
# erase background with current bg color
defbce "on" 
# set TERM
term screen-256color-bce

Problem is: Even if you set your .screenrc correctly, it won't matter if your terminal is not reporting the correct version string in the first place..

Filed under tools

New team member on dotless: Luke Page

You may have noticed that my blog is filling itself slowly with stuff about Ruby and Unix in general. This has to do with the fact that for now 3 months I am working on Rails full time with very little to no .NET work in between.

While this is awesome for me and I am really enjoying it - it also means that I don't have a .NET dev environment available at work and quickly merging in a pull request and testing it has become quite a hassle. So dotless has had quite some open tickets that where already fixed but where not yet merged into the mainline due to me lagging behind on responding to pull requests.

Fortunately, most/all pull requests have come from our very active Luke Page who has been busily fixing bugs and contributing features - so adding him to the dotless core team is a logical choice to cut down on the lag I or James where inducing into the process.

Since James felt the same we are happy to announce that Luke Page is now part of the dotless team with commit access and everything. So, welcome onboard Luke! Thanks for being part of dotless :)

plupload and IE8

Just a quick reminder for future Daniel who will surely run into this issue again in the near future:

If you don't specify the container property during plupload's setup it will use the body tag.

Problem with this is that on IE8 this may cause the flash fallback for file-uploads to span the whole body element and make the page unaccessible to clicks from the user.

So always include some dummy element nobody will click on and specify it as container.

Oh: And can we please get off IE8 at last?

Filed under uncategorized

How to use a PuttyGen private key to connect to a OpenSSH server

A quick reminder in case I ever forget: If you need to generate a new public/private key on a Windows box your best bet is PuttyGen. The Problem is that PuttyGen will create a SSH2 key that you can't use in your authorized_keys file as OpenSSH is using a different key format.

Thankfully ssh-keygen supports converting keys from one format into another:

ssh-keygen -i -f my_putty_key > ssh2_compatible_key.pub

Then just upload the file to your server and append it to your authorized_keys:

cat key.pub >> ~/.ssh/authorized_keys

Filed under uncategorized

Rails .to_json nested includes and methods

Defining assocations to be included in the rendered Json in Rails is pretty easy. You just use the options hash to define an include in to_json and by voodoo magic to_json will also traverse the ActiveRecord assocation and render the associated entity as a nested element in the Json. The code in question is quite simple:

@object.to_json({:include => :assocation_a})

By default Rails will only include attributes in to_json so if you want to also serialize the return value from a method (for example if you want to concatenate some attributes or compute something) you can do so through the options hash:

@object.to_json({:methods => :my_method})

You can also combine them easily if needed:

@object.to_json({:include => :assocation_a, :methods => :my_method})

But this calls the my_method on @object. How do you tell to_json to invoke my_method on @object.assocation_a?

Not trivial, but it works:

@object.to_json({:include => { :assocation_a => { :methods => :my_method }})

It gets spicy when you already had multiple includes in an array like this:

@object.to_json {:include => [ :assocation_a, :assocation_b ]} 

And now you only want to include my_method in assocation_a and not assocation b. simply replacing :assocation_a by a hash like before isn't going to work. It took me some time but this is what I came up with:

@object.to_json {:include => { :assocation_a => { :methods => :my_method }, :assocation_b => {} }} 

Did I mention that I am amazed by how flexible the syntax is here?

Filed under programmierung, rails, ruby

Invoking rails i18n.translate with pluralization

One very nice thing about the internationalization library in Rails is it's support for pluralization by default. Instead of having to figure out how to display a plural or a singular when selecting what message translation you display you can just call translate and it will figure out if the plural or the singular form should be used.

Defining the two forms is done inside your config/locale/.yml like this:

found:
  one: "Found one result"
  other: "Found %{count} results"

This works out of the box for things like validation errors or ActiveRecord models. But it refused to work on me for my own little custom array I was outputting.

Turns out I was just not calling it correctly. I18n.translate simply takes a hash of options - expecting one of these options to be count so it can perform the pluralization check (by default this is entry[count == 1 ? 0 : 1]).

So in order to use this with a custom array you need to write something like this:

I18n.translate :found, :count => myarray.length

Since this allows you to pass any value you want through the arguments hash you can easily construct translations like this:

found:
  one: We could not find anything matching your query %{query}
  other: We found %{count} items

I18n.translate :found, :count => myarray.length, :query => "your query"

Filed under programmierung, rails, ruby

Execute callback once multiple ajax requests finish with jQuery

I just stumbled upon the problem of having to load multiple resources during page initialization. During the initial load I wanted a way to prevent any animations and other fancy stuff from happening but rather only create the page as soon as possible.

Since I couldn't find any way in jQuery (there are no combined callbacks) I decided to implement this using the deferred promise concept jQuery 1.5 introduced.

Deferred basically means "I represent a ajax call that has happened or is happening - ask me about it and I'll tell you when it's done or was done already". So implementing my little wait functions was rather trivial:

I used CoffeeScript for this, but the resulting JavaScript is also quite readable and you can use that too.

What this does is provide you with the awkwardly named function waitForAjaxRequestsToComplete that takes one callback parameter and an array of jQuery promises. Once all promises succeed or fail the callback will be called and the first parameter will contain information about failures.

Sample usage:

waitForAjaxRequestsToComplete(function (info) {
  console.log("requests failed " + info.failures)
  console.log("requests succeeded " + info.successes)
  console.log(info.failed) //contains all failed promises
}, [ $.ajax(...), $.ajax(...), $.ajax(...) ]);

Securely managing database.yml when deploying with Capistrano

The more I venture into Ruby land the more magic Unicorns I find on the way. The wonders of SSH still seem totally outlandish to someone used to do deployments by RDPing into a server and xcopying a directory structure into your IIS folder.

But here I am and learning the ways of Capistrano and how deployments to multiple servers really should work.

Naturally I ran into issues I'll detail a bit later, but one of my major problems with my Rails deployment was the different database.yml between my production and my dev environment. Since the repository is in a shared location I could not put the production server mysql password into the config as it would be available to anyone with read access to the repository. This may be something you can get away with in a corporate environment, but if you plan on ever open-sourcing your project you should make sure you don't put production passwords into your repository :).

My solution to that problem is quite simple: I ssh'd into my server and put a "production" database.yml into the home directory of my deployment user and added the following task to my Capfile:

namespace :db do
  task :db_config, :except => { :no_release => true }, :role => :app do
    run "cp -f ~/database.yml #{release_path}/config/database.yml"
  end
end

after "deploy:finalize_update", "db:db_config"

The after statement tells Capistrano to run the db_config task right before finishing the code update, but before running any migrations in case you run cap deploy:migrations (capistrano process). And during every deployment I overwrite the database.yml from the repo with the one on the server.

I also added a assets:precompile task since Capistrano won't run the precompilation of Rails assets out of the box (you need RVM integration for this though):

  task :precompile, :role => :app do
    run "cd #{release_path}/ && rake assets:precompile"
  end
after "deploy:finalize_update", "deploy:precompile"

Et voilá: I can now run cap deploy:migrations from my dev machine and it will automatically connect to my release server, pull the code out of the git repository, compile the assets and migrate the database to a new version. And it will even roll-back to the old version if something goes wrong along the way.

Ps: I also struggled at one point with the SSH keys for the git repository. Since the deployment user on the server has no own private key I was inclined to generate one and add it to my git server's allowed keys list. But that's apparently the wrong way to go about things. The right thing to do here is to simply enable agent forwarding so the server will forward any questions about keys to your dev machine that should have the appropriate set of keys available.

ssh_options[:forward_agent] = true

Filed under rails, ruby, tools