Archive
words and words and words
Uncategorized agile coderetreat tdd
coderetreat with Corey Haines

After RubyAndRails 2010 there was a coderetreat, and i had read two blog posts about it, and got really interested. So when i learned that coderetreat was coming to Belgium, i subscribed. Coderetreat as a concept was conceived by Corey Haines and a few friends, as a single full-day retreat doing nothing but practicing code writing. Actually, practicing performing TDD. The reasoning behind it is quite simple: if musicians need to practice to get perfect, why don't we? Musicians practice small parts over and over again, to get it right. I played volleyball, and we also practiced each single movement, so that during a game you wouldn't have to think twice how to bend your knees, hold your hands, place your feet, approach the net ... But as programmers we are almost always producing. And of course, there is experience that makes up for that. But while i am an experienced programmer, i am not an experienced TDD'er. So i could use some practice :) A coderetreat starts at about 8, and is filled with 5-6 sessions of about 45 minutes during which you try to solve a well-known problem together with another programmer, as a pair. The pairing is essential. After 45 minutes you delete the code, discuss the chosen paths, options, viewpoints, switch pairs, and off you go again. The problem we try to solve is Conway's game of life. A relatively simple problem, but just too big to solve in 45 minutes. My main reason to go was that i still struggle doing full-on TDD, and i really want to do that. At work I have paired intensively for a few weeks and done TDD and that was really instructive. Yet, on my own, i too easily slip back to designing, thinking of the solution, coding and then writing tests. What I expected was to get some kind of magic insight, to completely 'get' it :) Let me explain that in more detail. The game of life, while it's rules are quite simple, has to be translated to tests, and then to code. This process is still somewhat gray to me. What the day did teach me is that the way you write the tests, can definitely drive the design. And actually, when starting with a new problem, i can also imagine you really need a few iterations starting to get the correct tests to correctly identify the problem. A teacher once told me that once you find a certain solution to a problem, you definitely have to find a second solution, then select the best of both. That would make sure you don't have the worst solution ;) I always take this approach in my designs, but almost never in my code. But actually, if the tests drive the design, i can imagine it is indeed really helpful to really try some different approaches. And doing lots of these exercises will learn you to make the right decisions quicker. The first two sessions were just getting accustomed to the problem. The problem is so different from what we solve everyday, that it is pretty hard to get your head round it. In between every session Corey asks what we tried, and then highlights some key-points to consider, mainly the SOLID principles and the 4 rules of simple design. That really helps you focus, change perspective and allows you to explore different paths. While in the second and third session, we were really close to actually solving it, or so it felt, the more we knew, the harder it got ;) Corey did an amazing job, guiding us through the day. He mostly let us do our work, and like a good therapist he sometimes just asked questions so we could find the answers ourselves. Corey also pointed us to a very good explanation on his blog on the difference between Test First and Test Driven development by JB Rainsberger. I found it very enlightening, and also very supportive. What i do now ressembles closest to Test First, and i want to get at the Test Driven approach. And i will :) The complete day was just an awesome experience. So many people in one room, all willing to learn and share and get better at what we do. It was sometimes very humbling. I believed i was good at what i did, but i was wrong. There is so much room for improvement. But it makes me want to learn and improve. What also was humbling is the time and energy and knowledge Corey shared. I really enjoyed all the conversations in between the sessions, meeting the people. I really enjoyed the pairing, while at times i could also find it very hard as well. I did not work equally well with everybody. That also is something i need to work on. There was a nice mix of languages: most c#, some java, some ruby. I saw that much of the principles we use in ruby, are now also easily used in c#. But i did not need to do c# a lot, because most people wanted to give ruby a try. And a lot of people were impressed. That was very nice ;) So i am really buzzed now. I want to do more. I want to learn more. I want to practice. I want to teach. Spread the word. I want to do this at work more. I want my code to be better. To conclude i want to repeat something Corey said: we have the best job in the world. Every time we type, we create something where there first was nothing. That is amazing. That is a gift. For a moment, do not think about the requirements, the documents, your team-members and your boss and your clients, but remember why we got here in the first place: because we really liked coding. Because when we were young we just coded for fun. And it was fun. It can be fun. So make it fun again. That is something i want to keep with me. Since i switched to ruby it comes more easily to me, but still ... Have a look at the pictures and try to spot me ;) (hint: i am wearing the yellow t-shirt). Here is another impression from the same day. I hope to see you next time ;)

More ...
Uncategorized ruby arrrrcamp ruby on rails
Arrrrcamp 29/10/2010

The fourth and most international of all arrrrcamp editions. Also the first paying edition. As i said in mypost about the previous edition, i have been to all editions, and it is awesome to see how it has grown. The schedule was amazing, with an amazing array of international speakers, of which for me especially Yehuda Katz i looked forward to. The biggest problem i had was that two of my collegues gave a talk at the same time, both of which i wanted to see. Choices choices choices :) Let me give a quick impression of the talks i did see:

Keynote by Carl Lerche:

To be frank, i had totally no idea who Carl was. But his talk was very nice, talking about the speed improvements Rails does, under the covers, unknown at least to me, to get your site visible as soon as possible. Also the speed improvements they will take in the next version 3.1 and 3.2 to improve this even further. In short, they look for ways to serve the HTML so that a browser can download the page and all the assets quicker. Very new to me, touched some very interesting subjects as automatic spriting, the cache manifest ... But in the end, there is one thing that Rails can't solve: latency. That is the core time it takes to reach a server and get back to the client. A mere ping. If you want to reduce latency, you either make sure your servers are really close to all clients, ... or ... you work in a different way, and let your client handle more stuff. In short: using a minimal HTML which is only downloaded once, using the cache manifest and lots of javascript: back to client side code? Hold that thought, we'll come back to that later.

Escaping the Sludgy Swamp of Slow Tests by Joseph Wilk

This is a problem we are getting into at work. We try to solve that by running our tests in parallel. Joseph explains the routes they had taken in their team.

  • First off: use a lot of EC2 instances to reduce time. They went from 4hours build time to 11minutes, cheering developers, but very angry boss :) EC2 is not cheap!
  • So then they introduced some kind of low-level caching, which will cache sequences of SQL commands and returned a cached result. This sounds very interesting as that is what you see most in tests: a lot of similar db-setup to actually test something small.
  • Thirdly a great idea was to divide your tests into different sets, and only run those that are most likely to fail. Those that always succeed you only run nightly, and the ones that sometimes fail you also seperate so you can more easily test those, check loggings, and hopefully fix them. I also remembered the suggestions to use capybara together with env.jsto be able to test your javascript pages quicker. Good tips, and i especially like the graphics (and humour) on the slides :D

Refactoring++ : Refactor Everything A.T.F.T by Alain Ravet

A talk by a collegue of mine (had to miss Elise's talk, bummmmer, but her talk is recorded so i hope to see that later). I know most of his refactoring tips, because we have paired extensively and i have learned a lot by doing that. Alain took a small piece of code from the internet, an example to solve the Towers of Hanoi: the code was small and compact and seemed to be ok. But then Alain was able to find and show a lot of improvements. That was great. Aside from the standard refactorings (from the book) Alain also stressed the scanability of the code. This is also a pet-pieve of mine. Code has to be formatted nicely and correctly. In teams it is preferred that classes follow a bit the same structure, e.g. inside rails it is easy to make agreements where to expect the filters, constructors, public methods, ... Also Alain stressed the point to know your tools and your language. Ruby is a very expressive and compact language: use that to your benefit! Know the tool you are using, whether it is Rubymine, Textmate or VIM. And practice. Do code kata's, download some code and refactor-refactor-refactor.

Making it an Anti-Pattern is Not Enough by Timothy Payton and Sebastian Roebke :

I saw these guys last time, and i was very impressed by them at that time. Probably because what they said struck a chord, and matched my own experiences. This time, i found them less persuasive. I think maybe because my expectations were too high, they re-iterated a lot they said last time (or so it felt), the title was not explained anywhere (or i missed that), and i guess they were also having troubles with the single microphone (being two speakers) that made them more uncomfortable. Still a very nice talk, and Xing seems to be a very nice place to work.

Lightning Talks

  • Friendly attributes: apparently, in mysql, adding a columns is a very expensive operation. So this guy looked for alternatives, and came up with friendly attributes. This could be a very nice tool for someone if you are forced to use MySql (e.g. by your hosting provider). Otherwise i would suggest to use Postgresql.
  • A postgres textsearch without any extra server: this seemed very interesting and promising, but also very non-existant at the moment. He was in the process of turning it into a gem. Wait and see.
  • Yehuda's 10 minutes about concurrency in MRI: inspired by Elise's talk about concurrency, Yehuda dug a bit deeper into MRI threads and possible advantages. Unfortunately none of the big servers (passenger or unicorn) make any use of that. Only thin --threaded would profit from that. This really was a lightning talk! A lot of information in a short span, very interesting!
  • @Defv's recipe for a good rails rumble: after his third Rails Rumble Jan gave us the recipe: 1) a knock-out idea but simple enough so any visitor/judge would get it, simple enough to implement in 48 hours, and 2) good design. With the next emphasis being: simple! simple! simple! Reminds me a bit of what 37signals always says.
  • Wicegrid: i have used this grid in a few big projects i did, and really liked it. Nice that Yuri showed it, hope some more people start using it.
  • Restart of BRUG: this was nice news too. I have seen that amsterdam.rb and rotterdam.rb exist, and was wondering why we don't have such a "working" thing in Belgium. But the guys from Openminds offered to revive it, they will support the first three sessions, and then other sponsors would need take over (volunteers from the public immediately jumped in). Meetings would take place in different cities, so i am very curious how this would work out. That would be very nice ;)

Closing Keynote by Yehuda Katz:

Yehuda recently switched jobs, and together with Carl Lerche they are now both actively working on a framework called Sproutcore. In short, Sproutcore (or SC) is a javascript MVC framework. So, MVC on the client. In the talk from Carl we learned that the big problem is latency, so one way to improve or remove that, is instead of developing your web-application in the Rails way, is to use a more client-centric way. Yehuda then showed us a few moving parts of Sproutcore, which he intends to extract in seperate libraries so you could use them more easily. They also stressed that Carl and Yehuda are aiming for a very tight integration with Rails in the future. Altough it is not entirely sure what or how that will be be. You would be using Rails to just serve json-data. Rails still has its very strong points to be used in the backend for something like that. His talk left me a bit baffled, to be honest. The big advantage for me of the Rails framework is that there is one language, one platform to develop in, to cover both server and client side. That is a big advantage. It is also a big advantage compared to using AIR or Silverlight on the client, because you remove the duplication of all the models on both sides (in Rails you only need them on server side). That said, i do believe the future lies in heavier clients, like gmail and twitter shows us. The bindings that Yehuda showed, reminded my very much of the bindings offered in WPF and Silverlight. Possible advantages of Silverlight: with Ironruby you have the option to run ruby in the client as well. But, as the video-section of arrrrcamp themselves show: Silverlight it is not ready for all platforms. It does not work on my ubuntu 10.10. I am thinking now would be a good time to revive the idea of a ruby vm on javascript. In no specific order:

  • Hotruby was very promising but seems dead. With the speed improvements in current javascript vm's it would seem awesome to get some ruby on javascript too.
  • rubyjs: compiles ruby to javascript to be run in the browser
  • Js.class could be an alternative approach: use the classes and paradigms of ruby in javascript.
  • red: writes like ruby and runs like javascript
  • coffeescript: not quite ruby, that compiles into javascript I will dig into these alternatives in a later post :) The biggest advantage of sproutcore over extjs, AIR or Silverlight is that sproutcore is truly open source. Exciting times ahead :)

To conclude

As usual I really enjoyed arrrrcamp, the organisation was great, i enjoyed seeing and talking to a lot like-minded people, and the talks were really though-provoking this year. Setting sail to the next edition!

More ...
Uncategorized ruby gemsets rvm rails3 ruby on rails
rails 2 and 3 simultaneously: gemsets to the rescue

I am developing several rails projects. Some are still rails 2.3.9, and some are rails3. But using those at the same time, on the same machine can cause some trouble. I use bundles for all my projects, so the gem dependencies are managed. But still, somehow, when running my tests, i get into trouble. If i run spec, it complains that it is deprecated. Rubymine doesn't support running tests in my rails 2 project. The solution? Use gemsets! Gemsets are a feature from rvm, the Ruby Version Manager. But with gemsets rvm does more than just manage your ruby version! A gemset is a set of gems, which you can switch at will. So i am using a gemset per project. Creating a gemset is easy: [ruby] rvm gemset create some_name [/ruby] Using a gemset is equally simple: [ruby] rvm gemset use some_name [/ruby] Showing which gemset is in use: [ruby] rvm gemset name [/ruby] Showing the list of possible gemsets [ruby] rvm gemset list [/ruby] By default, you are using an unnamed gemset, which contains all the gems for your ruby-version. Per project you can create a new gemset. Per gemset you have to re-install your gems, but luckily, using bundler, that is as simple as doing bundle install. Now comes the good part:

  • Rubymine supports using gemsets, so you can select your gemset to work with, and each time your project is opened, it uses the correct gemset and the correct corresponding scripts (e.g. spec)
  • If you place a .rvmrc file in your project-folder containing rvm default@projecta, every time you cd into that folder it will select the default ruby and the projecta gemset. Awesome!
More ...
Uncategorized
in-place-editing in rails3

On-the-spot is a Rails3 compliant unobtrusive javascript in-place-editing plugin, using jEditable. As this jEditable depends on jQuery, you have to install that first. How to setup a fresh rails3 site with jquery is explained in this post. In short it is easy: [ruby] gem "jquery-rails" [/ruby] Run the installation task: [ruby] rails g jquery:install [/ruby]

Installation

Inside your Gemfile add the following: [ruby] gem "on_the_spot" [/ruby] Run the installation task: [ruby] rails g on_the_spot:install [/ruby] Inside your routes.rb you need to provide the following route: [ruby] resources :posts do collection do put :update_attribute_on_the_spot end end [/ruby] You need to do this for each controller that uses the on-the-spot editing (in this example for the PostsController). For the moment i do not know of any better solution, but i am always open for suggestions! Inside your application.html.haml you will need to add below the default javascripts: [ruby] = javascript_include_tag :on_the_spot [/ruby] or using erb, you write [ruby] < %= javascript_include_tag :on_the_spot %> [/ruby] That is all you need to do to start using it!

Usage

Inside your controller you write: [ruby] class YourController < ApplicationController can_edit_on_the_spot ... leave the rest of your controller alone ... end [/ruby] And inside your view you will have to specify the fields you want to be "editable" : [ruby] Username: <%= on_the_spot_edit @user, :name %> [/ruby] It should be as simple as that :)

Detailed options

The on_the_spot_edit also accepts options:

  • :type : :textarea or select (none means default edit)
  • :ok_text : the text for the ok-button
  • :cancel_text : the text for the cancel-button
  • :tooltip : the tooltip-text
  • :rows : for textarea, the number of rows, defaults to 5
  • :columns : for textarea, the number of columns, defaults to 40
  • :data : for select, the lookup-data, should be in an array of id-value pairs. E.g. [[1, 'ok'], [2, 'not ok'], [3, 'not decided']]. For the texts: if a text is not specified, the default is taken from the on_the_spot.en.yml (or your current language).

Examples

Edit field

[ruby] < %= on_the_spot_edit @user, :name %> [/ruby]

Textarea

[ruby] < %= on_the_spot_edit @user, :description, :type => :textarea, :rows => 10, :columns => 55 %> [/ruby]

Select-box

[ruby] < %= on_the_spot_edit @user, :rating, :type => :select, :data => [[1, 'good'], [2, 'mediocre'], [3, 'bad']] %> [/ruby]

Example project

There is an example rails3-project called on_the_spot_tester, where this is demonstrated in action. Let me know what you think.On-the-spot is a Rails3 compliant unobtrusive javascript in-place-editing plugin, using jEditable.

Installation

Inside your Gemfile add the following: [ruby] gem "on_the_spot" [/ruby] Run the installation task: [ruby] rails g on_the_spot:install [/ruby] Inside your routes.rb you need to provide the following route: [ruby] resources :posts do collection do post :update_attribute_on_the_spot end end [/ruby] You need to do this for each controller that uses the on-the-spot editing (in this example for the PostsController). For the moment i do not know of any better solution, but i am always open for suggestions! Inside your application.html.haml you will need to add below the default javascripts: [ruby] = javascript_include_tag :on_the_spot [/ruby] or using erb, you write [ruby] < %= javascript_include_tag :on_the_spot %> [/ruby] That is all you need to do to start using it!

Usage

Inside your controller you write: [ruby] class YourController < ApplicationController can_edit_on_the_spot ... leave the rest of your controller alone ... end [/ruby] And inside your view you will have to specify the fields you want to be "editable" : [ruby] Username: <%= on_the_spot_edit @user, :name %> [/ruby] It should be as simple as that :)

Detailed options

The on_the_spot_edit also accepts options:

  • :type : :textarea or select (none means default edit)
  • :ok_text : the text for the ok-button
  • :cancel_text : the text for the cancel-button
  • :tooltip : the tooltip-text
  • :rows : for textarea, the number of rows, defaults to 5
  • :columns : for textarea, the number of columns, defaults to 40
  • :data : for select, the lookup-data, should be in an array of id-value pairs. E.g. [[1, 'ok'], [2, 'not ok'], [3, 'not decided']]. For the texts: if a text is not specified, the default is taken from the on_the_spot.en.yml (or your current language).

Examples

Edit field

[ruby] < %= on_the_spot_edit @user, :name %> [/ruby]

Textarea

[ruby] < %= on_the_spot_edit @user, :description, :type => :textarea, :rows => 10, :columns => 55 %> [/ruby]

Select-box

[ruby] < %= on_the_spot_edit @user, :rating, :type => :select, :data => [[1, 'good'], [2, 'mediocre'], [3, 'bad']] %> [/ruby]

Example project

There is an example rails3-project called on_the_spot_tester, where this is demonstrated in action. Let me know what you think.

More ...
Uncategorized rspec2 rcov rails3 ruby on rails
getting rcov working with rspec 2.0.0.rc

I had troubles to get rcov working with the latest rspec2 release (since beta23 and now 2.0.0.rc). I got the same error every time: [bash] require': no such file to load -- spec\_helper (LoadError) [/bash] But luckily, somebody [found the problem](http://github.com/rspec/rspec-core/issues/issue/172) and it is extremely easy to fix. Just add -Ispecto your rcov task. Therake spec:rcovdoes not work for me (as it needs to be fixed). So i added my own task (add this code to the end ofRakefileor add in a seperate filercov.rakeinsidelib/tasks`) : [ruby] desc "Run all specs with rcov" RSpec::Core::RakeTask.new("test_cov") do |t| t.rcov = true t.rcov_opts = %w{--rails --include views -Ispec --exclude gems/,spec/,features/,seeds/} end [/ruby] and then you can run the task by typing [bash] > rake test_cov [/bash] in your rails root folder.

More ...
Uncategorized cross-browser css ie8
ie8 css can't find my id

I was having this weird problem in IE8. My page was rendered correctly in Chrome and Firefox, but not in IE8. This was a bit weird, as it was pretty standard stuff, i had some form-styling, something like this: [css] form#some_long_id4test .example { font-style: italic; } form#some_long_id4test>div { clear:left; padding:5px; } form#some_long_id4test label { width:160px; display:block; float:left; } form#some_long_id4test .field-el { float:left; display:block; } form#some_long_id4test input[type='submit'] { margin-right:160px; margin-top: 20px; height:25px; padding-left:15px; padding-right:15px; } form#some_long_id4test .field-el .field-with-errors { color:red; } form#some_long_id4test #feedback_container { clear:both; margin-top: 20px; display:block; } form#some_long_id4test #fix_button { margin-top:-10px; padding-left:165px; } [/css] Seems pretty obvious. Why didn't it work? After a long search, trying stuff out, trying to rewrite my css to get it working, i saw my error. Once found it was very obvious: in my ruby-view i had the following: [ruby] <% form_for @form, :html => {:multipart => true, :id => "some_long_id4test "} do |f| [/ruby] Wow! So my id is actually some_long_id4test with an added newline! Apparently IE8 thinks that some_long_id4test and some_long_id4test\n are not equal (which is not unlogical). It is sometimes so hard, confusing, difficult that all these browsers behave different.

More ...
Uncategorized jquery json jsonp rails3
rails3 doing cross-browser json

I have two rails applications that communicate together. In the first application i have the following method in my controller: [ruby] def delivery_status envelope = Envelope.find(params[: id]) render : json => envelope.to_json end [/ruby] which, if go to the url in my browser, nicely shows my the JSON. Seems ok. However, if i call this through jQuery, from my second application, using the following: [javascript] $(document).ready(function(){ $('.get_sms_details').live('click', function(event) { var el = $(this), data_url = el.attr('data-url'); $.ajax({ url: data_url, dataType: 'text', success: function(data, status, req) { alert('received with status' + status) alert('received json ' + data); } }); }); }); [/javascript] then the right url is hit with the correct parameters but data is always empty. I first tried using $.getJSON, then $.get to end at $.ajax. I am not sure but it seemed i was doing something wrong at server-side. The request looked fine inside firebug, but the response was always empty. Yet, i did not understand, if let the browser hit the same url, i got my json object. So how do you solve this? Well, i was reading the documentation of $.ajax, and there i found:

When data is retrieved from remote servers (which is only possible using the script or jsonp data types), the operation is performed using a script tag rather than an XMLHttpRequest object.

So, jsonp was the way, but how? First, i changed my jQuery code: [sourcecode language="javascript"] $(document).ready(function(){ $('.get_sms_details').live('click', function(event) { var el = $(this), data_url = el.attr('data-url'); data_url = data_url $.ajax({ url: data_url, dataType: 'jsonp', success: function(data) { envelope = data.envelope; alert('received envelope ' + data.envelope.id); } }); }); }); [/sourcecode] but then my server-side needed to be able to handle the jsonp. I handled that using the following code: [ruby] def delivery_status envelope = Envelope.find(params[:id]) render_json envelope.to_json(:include => [: deliveries, : log_lines]) end private # render json, but also allow JSONP and handle that correctly def render_json(json, options={}) callback, variable = params[:callback], params[:variable] logger.debug("render json or jsonp? Callback = #{callback}, Variable=#{variable}") response = begin if callback &amp;&amp; variable "var #{variable} = #{json};\n#{callback}(#{variable});" elsif variable "var #{variable} = #{json}" elsif callback "#{callback}(#{json});" else json end end render({:content_type => :js, :text => response}.merge(options)) end [/ruby] Where the render_json does all the dirty work for me :) I was somewhat expecting this to be standard inside rails3, and as Kevin Chiu pointed out in the comments, it is and much simpler at that: [ruby] def delivery_status envelope = Envelope.find(params[:id]) render :json => envelope.to_json(:include => [: deliveries, : log_lines]), :callback => params[:callback] end [/ruby] Awesome :)I have two rails applications that communicate together. In the first application i have the following method in my controller: [ruby] def delivery_status envelope = Envelope.find(params[: id]) render : json => envelope.to_json end [/ruby] which, if go to the url in my browser, nicely shows my the JSON. Seems ok. However, if i call this through jQuery, from my second application, using the following: [javascript] $(document).ready(function(){ $('.get_sms_details').live('click', function(event) { var el = $(this), data_url = el.attr('data-url'); $.ajax({ url: data_url, dataType: 'text', success: function(data, status, req) { alert('received with status' + status) alert('received json ' + data); } }); }); }); [/javascript] then the right url is hit with the correct parameters but data is always empty. I first tried using $.getJSON, then $.get to end at $.ajax. I am not sure but it seemed i was doing something wrong at server-side. The request looked fine inside firebug, but the response was always empty. Yet, i did not understand, if let the browser hit the same url, i got my json object. So how do you solve this? Well, i was reading the documentation of $.ajax, and there i found:

When data is retrieved from remote servers (which is only possible using the script or jsonp data types), the operation is performed using a script tag rather than an XMLHttpRequest object.

So, jsonp was the way, but how? First, i changed my jQuery code: [sourcecode language="javascript"] $(document).ready(function(){ $('.get_sms_details').live('click', function(event) { var el = $(this), data_url = el.attr('data-url'); data_url = data_url $.ajax({ url: data_url, dataType: 'jsonp', success: function(data) { envelope = data.envelope; alert('received envelope ' + data.envelope.id); } }); }); }); [/sourcecode] but then my server-side needed to be able to handle the jsonp. I handled that using the following code: [ruby] def delivery_status envelope = Envelope.find(params[:id]) render_json envelope.to_json(:include => [: deliveries, : log_lines]) end private # render json, but also allow JSONP and handle that correctly def render_json(json, options={}) callback, variable = params[:callback], params[:variable] logger.debug("render json or jsonp? Callback = #{callback}, Variable=#{variable}") response = begin if callback && variable "var #{variable} = #{json};\n#{callback}(#{variable});" elsif variable "var #{variable} = #{json};" elsif callback "#{callback}(#{json});" else json end end render({:content_type => :js, :text => response}.merge(options)) end [/ruby] Where the render_json does all the dirty work for me :) I was somewhat expecting this to be standard inside rails3, but apparently it isn't. Are there any better ways to handle this?

More ...
Uncategorized rspec2 watchr rails3
rspec2 using watchr instead of autotest

I was having troubles with autotest, and not really finding a good solution. But i noticed that inside rspec2 they were using watchr. Watchr is a very generic gem that will allow you to watch a set of files and take action when something changes. That sounds great, but maybe a bit too general :) So, it appears you need a script to run your rspec2 continuously using watchr. Luckily i did find some examples, which allowed my to brew my own (save in your rails-root as specs.watchr): [ruby wraplines="false"] # adapted from http://github.com/rspec/rspec-rails/blob/master/specs.watchr # Run me with: # # $ watchr specs.watchr # -------------------------------------------------- # Convenience Methods # -------------------------------------------------- def all_spec_files Dir['spec/**/*_spec.rb'] end def run_spec_matching(thing_to_match) matches = all_spec_files.grep(/#{thing_to_match}/i) if matches.empty? puts "Sorry, thanks for playing, but there were no matches for #{thing_to_match}" else run matches.join(' ') end end def run(files_to_run) puts("Running: #{files_to_run}") system("rspec -c #{files_to_run}") no_int_for_you end def run_all_specs run(all_spec_files.join(' ')) end # -------------------------------------------------- # Watchr Rules # -------------------------------------------------- watch('^spec/(.*)_spec.rb') { |m| run_spec_matching(m[1]) } watch('^app/(.*).rb') { |m| run_spec_matching(m[1]) } watch('^app/(.*).haml') { |m| run_spec_matching(m[1]) } watch('^lib/(.*).rb') { |m| run_spec_matching(m[1]) } watch('^spec/spec_helper.rb') { run_all_specs } watch('^spec/support/.*.rb') { run_all_specs } # -------------------------------------------------- # Signal Handling # -------------------------------------------------- def no_int_for_you @sent_an_int = nil end Signal.trap 'INT' do if @sent_an_int then puts " A second INT? Ok, I get the message. Shutting down now." exit else puts " Did you just send me an INT? Ugh. I'll quit for real if you do it again." @sent_an_int = true Kernel.sleep 1.5 run_all_specs end end [/ruby] It even seems to be quicker than autotest, but not sure if that is just wishful thinking.

More ...
Uncategorized authlogic rails3
authlogic on rails3

If you want to get authlogic working in a fresh rails 3 project, it will take a bit more steps than devise. This has everything to do with vision: authlogic only claims to deliver you the backend, allowing itself to remain more stable and to easily replace other authentication libraries (even your home-brewn). That seems a great philosophy, but starting from scratch involves more steps. First you need to setup a clean rails3 project, as i described before.

Install the gem

As simple as adding the following line to your Gemfile : [ruby] gem "authlogic" gem "rails3-generators" [/ruby] (note: you need the rails3-generators to include the needed generators). Then run bundle install or bundle update.

Create the UserSession

[ruby] rails g authlogic:session UserSession [/ruby] This would be all, but in my installation it was not enough. Something inside rails3 broke the authlogic session. But the fix, luckily, is pretty easy: you have to add the to_key function. So your complete UserSession model will look as follows: [ruby] class UserSession < Authlogic::Session::Base def to_key new_record? ? nil : [self.send(self.class.primary_key)] end end [/ruby]

Create the User

If you do not yet have a User model, and i am assuming you don't, you need to [ruby] rails g model User [/ruby] For now, this is an empty model. You will need to fill in your migration to create the model correctly. [ruby wraplines="false"] class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.string :login, :null => false t.string :email, :null => false t.string :crypted_password, :null => false t.string :password_salt, :null => false t.string :persistence_token, :null => false #t.string :single_access_token, :null => false # optional, see Authlogic::Session::Params #t.string :perishable_token, :null => false # optional, see Authlogic::Session::Perishability # magic fields (all optional, see Authlogic::Session::MagicColumns) t.integer :login_count, :null => false, :default => 0 t.integer :failed_login_count, :null => false, :default => 0 t.datetime :last_request_at t.datetime :current_login_at t.datetime :last_login_at t.string :current_login_ip t.string :last_login_ip t.timestamps end add_index :users, ["login"], :name => "index_users_on_login", :unique => true add_index :users, ["email"], :name => "index_users_on_email", :unique => true add_index :users, ["persistence_token"], :name => "index_users_on_persistence_token", :unique => true end def self.down drop_table :users end end [/ruby] Now we still have to add some code to the User model : [ruby] class User < ActiveRecord::Base acts_as_authentic end [/ruby]

ApplicationController

We need to add some generic code to our applicationcontroller to persist the sessions, to check whether a user is required and do the correct redirects when needed. [ruby] class ApplicationController < ActionController::Base protect_from_forgery helper_method :current_user_session, :current_user private def current_user_session logger.debug "ApplicationController::current_user_session" return @current_user_session if defined?(@current_user_session) @current_user_session = UserSession.find end def current_user logger.debug "ApplicationController::current_user" return @current_user if defined?(@current_user) @current_user = current_user_session && current_user_session.user end def require_user logger.debug "ApplicationController::require_user" unless current_user store_location flash[:notice] = "You must be logged in to access this page" redirect_to new_user_session_url return false end end def require_no_user logger.debug "ApplicationController::require_no_user" if current_user store_location flash[:notice] = "You must be logged out to access this page" redirect_to account_url return false end end def store_location session[:return_to] = request.request_uri end def redirect_back_or_default(default) redirect_to(session[:return_to] || default) session[:return_to] = nil end end [/ruby]

UserSessionsController

[ruby] rails g controller UserSessions new [/ruby] and fill the controller with the correct code: [ruby] class UserSessionsController < ApplicationController before_filter :require_no_user, :only => [:new, :create] before_filter :require_user, :only => :destroy def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.save flash[:notice] = "Login successful!" redirect_back_or_default users_url else render :action => :new end end def destroy current_user_session.destroy flash[:notice] = "Logout successful!" redirect_back_or_default new_user_session_url end end [/ruby] and of course that also needs a view, in new.html.haml[ruby] %h1 Login = form_for @user_session, :url => {:action => "create"} do |f| = f.error_messages %div = f.label :login = f.text_field :login %div = f.label :password = f.password_field :password %div = f.check_box :remember_me = f.label :remember_me %div = f.submit "Login" [/ruby] We want to use the f.error_message, but that is now removed from Rails3 and we need to install a plugin instead: [ruby] rails plugin install git://github.com/rails/dynamic_form.git [/ruby] We also need to define, inside config/routes.rb. You will see that the generator will have added the route get 'user_sessions/new', but that is not enough. You will have to add: [ruby] resources :user_sessions match 'login' => "user_sessions#new", :as => :login match 'logout' => "user_sessions#destroy", :as => :logout [/ruby]

Restrict access

Suppose you now have some other controller, e.g. HomeController, then restricting acces is straightforward: [ruby] rails g controller home index [/ruby] [ruby] class HomeController < ApplicationController before_filter :require_user def index end end [/ruby] The method require_user, defined in ApplicationController, will check if there is a user logged on, and if not redirect to the login-page. If we now delete the index.html inside your public folder, and we add the following at the bottom of config/routes.rb[ruby] root :to => 'home#index' [/ruby] Now we can start our application, and it should redirect to our login-page. But of course, since we have no users for now, we can't login just yet. To allow testing, you fire up your console: [bash] $ rails c Loading development environment (Rails 3.0.0.rc) ruby-1.9.2-p0 > User.create(:login => 'test', :email => 'test@tester.com', :password => 'test123', :password_confirmation => 'test123') => #<User id: 1, login: "test", email: "test@tester.com", crypted_password: "0129d9733b7912017e37a50263901488da90e127e6fd1ae6081...", password_salt: "ygufdflWkJQZGhbsGyia", persistence_token: "957788609b2067092dd3852b01613d53f96d0692ce5131174ca...", login_count: 0, failed_login_count: 0, last_request_at: nil, current_login_at: nil, last_login_at: nil, current_login_ip: nil, last_login_ip: nil, created_at: "2010-08-29 14:11:04", updated_at: "2010-08-29 14:11:04"> ruby-1.9.2-p0 > [/bash] Now you should be able to login using this user. For completeness, you should add some links to your application-view to allow logging in and out: [ruby] #user_nav - if current_user = "Signed in as #{current_user.email}. Not you?" = link_to "Sign out", logout_path - else = link_to "Sign in", new_user_session_path [/ruby] This would get your rails3 project started. The next steps would be to add some user management, or allowing users to sign up themselves, and maybe add some roles to limit certain users access if needed. Now, to contrast this with devise: i now have a bunch of code in my application that actually is not specific to my code, but is also completely not tested. I will provide example rspec tests for this later. Actually, the problem with this scenario as outlined, is it is one big bang. You should start little, declaring things you need to be able to do, and work in little steps to get there. But this scenario is intended as a draft to see how you could get there. Now, in your real application, you should start with the tests, and then from this example you now how you can implement it.If you want to get authlogic working in a fresh rails 3 project, it will take a bit more steps than devise. This has everything to do with vision: authlogic only claims to deliver you the backend, allowing itself to remain more stable and to easily replace other authentication libraries (even your home-brewn). That seems a great philosophy, but starting from scratch involves more steps. First you need to setup a clean rails3 project, as i described before.

Install the gem

As simple as adding the following line to your Gemfile : [ruby] gem "authlogic" [/ruby] and then run bundle install or bundle update.

Create the UserSession

[ruby] rails g authlogic:session UserSession [/ruby] This would be all, but in my installation it was not enough. Something inside rails3 broke the authlogic session. But the fix, luckily, is pretty easy: you have to add the to_key function. So your complete UserSession model will look as follows: [ruby] class UserSession < Authlogic::Session::Base def to_key new_record? ? nil : [self.send(self.class.primary_key)] end end [/ruby]

Create the User

If you do not yet have a User model, and i am assuming you don't, you need to [ruby] rails g model User [/ruby] For now, this is an empty model. You will need to fill in your migration to create the model correctly. [ruby wraplines="false"] class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.string :login, :null => false t.string :email, :null => false t.string :crypted_password, :null => false t.string :password_salt, :null => false t.string :persistence_token, :null => false #t.string :single_access_token, :null => false # optional, see Authlogic::Session::Params #t.string :perishable_token, :null => false # optional, see Authlogic::Session::Perishability # magic fields (all optional, see Authlogic::Session::MagicColumns) t.integer :login_count, :null => false, :default => 0 t.integer :failed_login_count, :null => false, :default => 0 t.datetime :last_request_at t.datetime :current_login_at t.datetime :last_login_at t.string :current_login_ip t.string :last_login_ip t.timestamps end add_index :users, ["login"], :name => "index_users_on_login", :unique => true add_index :users, ["email"], :name => "index_users_on_email", :unique => true add_index :users, ["persistence_token"], :name => "index_users_on_persistence_token", :unique => true end def self.down drop_table :users end end [/ruby] Now we still have to add some code to the User model : [ruby] class User < ActiveRecord::Base acts_as_authentic end [/ruby]

ApplicationController

We need to add some generic code to our applicationcontroller to persist the sessions, to check whether a user is required and do the correct redirects when needed. [ruby] class ApplicationController < ActionController::Base protect_from_forgery helper_method :current_user_session, :current_user private def current_user_session logger.debug "ApplicationController::current_user_session" return @current_user_session if defined?(@current_user_session) @current_user_session = UserSession.find end def current_user logger.debug "ApplicationController::current_user" return @current_user if defined?(@current_user) @current_user = current_user_session && current_user_session.user end def require_user logger.debug "ApplicationController::require_user" unless current_user store_location flash[:notice] = "You must be logged in to access this page" redirect_to new_user_session_url return false end end def require_no_user logger.debug "ApplicationController::require_no_user" if current_user store_location flash[:notice] = "You must be logged out to access this page" redirect_to account_url return false end end def store_location session[:return_to] = request.request_uri end def redirect_back_or_default(default) redirect_to(session[:return_to] || default) session[:return_to] = nil end end [/ruby]

UserSessionsController

[ruby] rails g controller UserSessions new [/ruby] and fill the controller with the correct code: [ruby] class UserSessionsController < ApplicationController before_filter :require_no_user, :only => [:new, :create] before_filter :require_user, :only => :destroy def new @user_session = UserSession.new end def create @user_session = UserSession.new(params[:user_session]) if @user_session.save flash[:notice] = "Login successful!" redirect_back_or_default users_url else render :action => :new end end def destroy current_user_session.destroy flash[:notice] = "Logout successful!" redirect_back_or_default new_user_session_url end end [/ruby] and of course that also needs a view, in new.html.haml[ruby] %h1 Login = form_for @user_session, :url => {:action => "create"} do |f| = f.error_messages %div = f.label :login = f.text_field :login %div = f.label :password = f.password_field :password %div = f.check_box :remember_me = f.label :remember_me %div = f.submit "Login" [/ruby] We want to use the f.error_message, but that is now removed from Rails3 and we need to install a plugin instead: [ruby] rails plugin install git://github.com/rails/dynamic_form.git [/ruby] We also need to define, inside config/routes.rb. You will see that the generator will have added the route get 'user_sessions/new', but that is not enough. You will have to add: [ruby] resources :user_sessions match 'login' => "user_sessions#new", :as => :login match 'logout' => "user_sessions#destroy", :as => :logout [/ruby]

Restrict access

Suppose you now have some other controller, e.g. HomeController, then restricting acces is straightforward: [ruby] rails g controller home index [/ruby] [ruby] class HomeController < ApplicationController before_filter :require_user def index end end [/ruby] The method require_user, defined in ApplicationController, will check if there is a user logged on, and if not redirect to the login-page. If we now delete the index.html inside your public folder, and we add the following at the bottom of config/routes.rb[ruby] root :to => 'home#index' [/ruby] Now we can start our application, and it should redirect to our login-page. But of course, since we have no users for now, we can't login just yet. To allow testing, you fire up your console: [bash] $ rails c Loading development environment (Rails 3.0.0.rc) ruby-1.9.2-p0 > User.create(:login => 'test', :email => 'test@tester.com', :password => 'test123', :password_confirmation => 'test123') => #<User id: 1, login: "test", email: "test@tester.com", crypted_password: "0129d9733b7912017e37a50263901488da90e127e6fd1ae6081...", password_salt: "ygufdflWkJQZGhbsGyia", persistence_token: "957788609b2067092dd3852b01613d53f96d0692ce5131174ca...", login_count: 0, failed_login_count: 0, last_request_at: nil, current_login_at: nil, last_login_at: nil, current_login_ip: nil, last_login_ip: nil, created_at: "2010-08-29 14:11:04", updated_at: "2010-08-29 14:11:04"> ruby-1.9.2-p0 > [/bash] Now you should be able to login using this user. For completeness, you should add some links to your application-view to allow logging in and out: [ruby] #user_nav - if current_user = "Signed in as #{current_user.email}. Not you?" = link_to "Sign out", logout_path - else = link_to "Sign in", new_user_session_path [/ruby] This would get your rails3 project started. The next steps would be to add some user management, or allowing users to sign up themselves, and maybe add some roles to limit certain users access if needed. Now, to contrast this with devise: i now have a bunch of code in my application that actually is not specific to my code, but is also completely not tested. I will provide example rspec tests for this later. Actually, the problem with this scenario as outlined, is it is one big bang. You should start little, declaring things you need to be able to do, and work in little steps to get there. But this scenario is intended as a draft to see how you could get there. Now, in your real application, you should start with the tests, and then from this example you now how you can implement it.

More ...
Uncategorized etsyhacks fast_tagger
etsy fast_tagger v2

There used to be a greasemonkey script fast_tagger which allowed an etsy seller to add all tags at once when creating or editing an item. Since april of this year this script was broken. My girlfriend has had a shop for a couple of years and missed the functionality from etsyhacks dearly. Apparently Ian, the person behind etsyhacks, is now working for etsy himself and isn't maintaining the scripts anymore. So, without further ado: you can download the fast_tagger_2 script to install. It should operate in the same way as before.

Installation instructions:

  • install firefox and greasemonkey if you haven't done so already.
  • once Greasemonkey is installed and running, follow this link.
  • The "fast tagger 2" script will be downloaded, and Greasemonkey will ask if you want to install it. Assuming you trust me, click "Install".

Operation

When you create a new listing and go to the tags page, or when you edit the tags of an existing listing, you will see that a new box is now visible. Inside this box, you can enter tags, comma separated and ...

  • click "add tags" to add the tags to the listing
  • click "replace tags" to remove any existing tags and replace them with your current ones.
  • or you can click "delete tags" to remove any existing tags. [UPDATE] I have been in touch with Ian, and he assured me he is going to continue supporting etsyhacks, only that he currently was swamped in work. I leave this script for whoever it could help in the meantime.
More ...
Uncategorized pgadmin postgresql ubuntu
fixing pgadmin3

When i try to run pgadmin3 on my ubuntu 10.04 box i now get the following error: [bash] $ pgadmin3 pgadmin3: relocation error: pgadmin3: symbol _ZN21wxMemoryFSHandlerBase19AddFileWithMimeTypeERK8wxStringPKvjS2_, version WXU_2.8 not defined in file libwx_baseu-2.8.so.0 with link time reference [/bash] I assume it has something to do with one of the latest updates. I run all the updates always when they are proposed, but i am not really sure this always is a good idea. When googling the error i found a lot of links, and ultimately, also the fix: [bash] apt-get source pgadmin3 sudo apt-get install debhelper libpq-dev libwxgtk2.8-dev libxml2-dev libxslt1-dev autotools-dev devscripts cd pgadmin3-1.10.2 dpkg-buildpackage sudo dpkg -i ../pgadmin3_1.10.2-1_i386.deb [/bash]

More ...
Uncategorized delayed_job rails3
setting up delayed_job in rails3

If you want to run longrunning jobs in the background, one very easy solution is using delayed_job. One other very interesting alternative is resque, but it seemed harder to setup (it uses redis), and delayed_job seemed to be just right for my needs. In short (from the redis documentation) : Choose Resque if:

  • You need multiple queues
  • You don't care / dislike numeric priorities
  • You don't need to persist every Ruby object ever
  • You have potentially huge queues
  • You want to see what's going on
  • You expect a lot of failure / chaos
  • You can setup Redis
  • You're not running short on RAM Choose DelayedJob if:
  • You like numeric priorities
  • You're not doing a gigantic amount of jobs each day
  • Your queue stays small and nimble
  • There is not a lot failure / chaos
  • You want to easily throw anything on the queue
  • You don't want to setup Redis And in my case: a short list of outstanding jobs, i am using a database already, not sure about redis, performance is not that important, i do not expect a lot of failure, i do not want to setup redis (yet :). So to use the delayed_job gem in a rails3 you will need to use the code from github (as the gem version 2.0.3 is not yet rails3 compatible). Add the following line to your Gemfile : [ruby] gem "delayed_job", :git => 'git://github.com/collectiveidea/delayed_job.git' [/ruby] and then run [bash] bundle install [/bash] Because i am using ActiveRecord, i can just use the generator, that will create the table and add the script to run a worker: [ruby] rails generate delayed_job rake db:migrate [/ruby] Include the rake tasks from delayed-jobs into your Rakefile: [ruby] begin require 'delayed/tasks' rescue LoadError STDERR.puts "Run bundle:install to install delayed_job" end [/ruby] Create an initializer file delayed_jobs_config.rb and write [ruby] # config/initializers/delayed_job_config.rb Delayed::Worker.destroy_failed_jobs = false #Delayed::Worker.sleep_delay = 60 #Delayed::Worker.max_attempts = 3 Delayed::Worker.max_run_time = 5.minutes [/ruby] If you are happy with the defaults, you can leave it. For me it was important to keep a record of the jobs that failed. Then you can just delay any function-call like this: [ruby] envelope.delay.query_status(delivery) [/ruby] Just adding the .delay does all the magic for you! And starting a worker is as simple as [ruby] rake jobs:work [/ruby]
More ...
Uncategorized
rspec2 and rails3: controller testing with devise

Devise seems to become the new authentication standard in rails land. Also the last version of the gem is for rails3, so it is very easy to start using it. If you are using rspec2 for your tests, it is also really easy to test your controllers that are authenticated by devise. Suppose you have a DoStuffController like this: [ruby] class DoStuffController < ApplicationController before_filter :authenticate_user! def index end end [/ruby] You need to test it as follows in do_stuff_controller_spec.rb: [ruby] require 'spec_helper' describe DoStuffController do include Devise::TestHelpers before (:each) do @user = Factory.create(:user) sign_in @user end describe "GET 'index'" do it "should be successful" do get 'index' response.should be_success end end end [/ruby] And in your factory, users.rb: [ruby] Factory.define :user do |f| f.email "bla@blabla.com" f.password "blax123" end [/ruby] I am not testing the fact that the redirect will work, under the assumption that that is specific devise functionality which i assume to be tested and working.

More ...
Uncategorized ajax unobtrusive-javascript jquery rails3
handling ajax callbacks in rails3 using jquery

Previously, in rails 2.3.8 i used the prototype-helpers link_to_remote and form_remote_for (amongst others). These had the option to add callbacks as follows: [ruby] link_to_remote "Add to cart", :url => { :action => "add", :id => product.id }, :update => { :success => "cart", :failure => "error" } [/ruby] (an example from the documentation). This example would, upon success update the html-element with class "cart", and upon failure the class "error". The possible callbacks were:

  • :loading: Called when the remote document is being loaded with data by the browser.
  • :loaded: Called when the browser has finished loading the remote document.
  • :interactive: Called when the user can interact with the remote document, even though it has not finished loading.
  • :success: Called when the XMLHttpRequest is completed, and the HTTP status code is in the 2XX range.
  • :failure: Called when the XMLHttpRequest is completed, and the HTTP status code is not in the 2XX range.
  • :complete : Called when the XMLHttpRequest is complete (fires after success/failure if they are present). Now the modus operandi has changed, instead we write: [ruby] link_to "Add to cart", :url => {:action => "add", :id => product.id}, :remote => true [/ruby] and it seems there is no option to set the callbacks anymore. Instead of a normal html, we now render javascript, like this (in jquery) : [ruby] $('.cart').replaceWith(<%= escape_javascript(render :partial => 'cart') %>) [/ruby] But how do you handle an error situation? Do i handle it in my controller, and use seperate views? It would seem useful to me to somehow be able to mimic the behaviour we had before. Luckily in this article I was able to find the solution. I had already found that in rails.js the following callbacks were checked:
  • ajax:beforeSend : triggered before executing the AJAX request
  • ajax:success : triggered after a successful AJAX request
  • ajax:complete : triggered after the AJAX request is complete, regardless the status of the response
  • ajax:error : triggered after a failed AJAX request, as opposite to ajax:success But i had no idea how to provide these callbacks. The javascript should be unobtrusive, so this coupling is not done straight in the HTML anymore. From the same article i found a very clear example how to solve this. Take the following Rails 2.3.8 code : [ruby] <% form_remote_tag :url => { :action => 'run' }, :id => "tool-form", :update => { :success => "response", :failure => "error" }, :loading => "$('#loading').toggle()", :complete => "$('#loading').toggle()" %> [/ruby] That translates to this in Rails3 : [ruby] <% form_tag url_for(:action => "run"), :id => "tool-form", :remote => true do %> [/ruby] and inside some javascript (application.js), you bind the events [javascript] jQuery(function($) { // create a convenient toggleLoading function var toggleLoading = function() { $("#loading").toggle() }; $("#tool-form") .bind("ajax:beforeSend", toggleLoading) .bind("ajax:complete", toggleLoading) .bind("ajax:success", function(data, status, xhr) { $("#response").html(status); }); }); [/javascript] For completeness, here is a list of the events and their expected parameters: [javascript] .bind('ajax:beforeSend', function(xhr, settings) {}) .bind('ajax:success', function(data, status, xhr) {}) .bind('ajax:complete', function(xhr, status) {}) .bind('ajax:error', function(xhr, status, error) {}) [/javascript] [UPDATED 7/2/2012] Updated to reflect the new event-names. :loading was renamed to :beforeSend, and :failure was renamed to :error.
More ...
Uncategorized haml jquery rails3 ruby on rails
rails 3 and haml and unobtrusive javascript

I have created a Rails3 application, started with Haml/Sass and finding it awesome. I am also trying to do unobtrusive javascript. Before, in Rails 2.3, I would have expected a remote-form to have an :update attribute, where you could specify a selector where the response of the remote method would be rendered. Now it needs to be done differently: my controller function will render a ".js" view, which will do the necessary actions itself. This makes it more library agnostic, and i prefer jquery. So for instance i have a controller action "search", and i have a corresponding "search.js.erb" as follows: [ruby] $('.grid').replaceWith('<%= escape_javascript(render :partial => 'list') %>') [/ruby] This works. It will replace the html of the element with a class grid with the html from my rendered partial. I started out trying to achieve that in HAML, and failed at first. So first i created the above ERB code which worked. Now my task seemed simpler: translate this seemingly simple line to HAML. My first naive approach was to do the following: [ruby] = "$('.grid').replaceWith('#{escape_javascript(render :partial => 'list')}')" [/ruby] But this just places the html as a readable string inside my page. Even i do something simple like [ruby] = "$('.grid').replaceWith('<h3>Text</h3>') [/ruby] i see the actual characters [ruby] <h3>Text</h3> [/ruby] and not the markup. But i need to contain the javascript inside the double-quotes or haml will not recognise it, and can not interpolate my ruby there. After looking through the HAML reference, actually the solution was incredible simple. Once more. [ruby] != "$('.grid').replaceWith('#{escape_javascript(render :partial => 'list')}')" [/ruby] The != unescapes HTML (as opposed to the standard =). This is exactly what we need of course.

More ...
Uncategorized haml jquery rspec2 rails3
starting a new rails3 site using rspec2 and jquery

With Rails3 i can create a project fully cut to my needs. I will write it down here, just so i remember it well and hopefully it will help some of you too. In my projects, i want to use haml, rspec2, factory-girl, jquery, ... We need a few steps to complete this.

Create the project

For starters, create the folder, without Test::Unit (-T) and without prototype (-J). [ruby] rails new test-project -T -J [/ruby] You could also specify the database, using option -d, [--database=DATABASE], with the following options: `

mysql oracle postgresql sqlite3 (default) frontbase ibm_db`

Specify needed gems

We also have to specify the gems we need. To do that, we need to edit the Gemfile which is located in the root of your project. My file looks as follows: [ruby] source 'http://rubygems.org' gem 'rails', '3.0.0.rc' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' #gem 'pg' gem 'sqlite3-ruby', :require => 'sqlite3' # Use unicorn as the web server # gem 'unicorn' # Deploy with Capistrano # gem 'capistrano' # To use debugger # gem 'ruby-debug' gem 'rails3-generators' gem "bson_ext" gem "haml" gem "haml-rails" gem "jquery-rails" gem "rcov" # we need this here, see http://blog.davidchelimsky.net/2010/07/11/rspec-rails-2-generators-and-rake-tasks/ group :development, :test do gem "rspec-rails", ">= 2.0.0.beta.18" end # test-environment gems group :test, :spec, :cucumber do gem "factory_girl_rails" gem "rspec", ">= 2.0.0.beta.18" gem "remarkable", ">=4.0.0.alpha2" gem "remarkable_activemodel", ">=4.0.0.alpha2" gem "remarkable_activerecord", ">=4.0.0.alpha2" gem "capybara" gem "cucumber" gem "database_cleaner" gem "cucumber-rails" end [/ruby] Run bundle install to install all needed gems.

Use wanted generators

Then now edit the file application.rb, located in the config folder, and add the following lines: [ruby] # Configure generators values config.generators do |g| g.test_framework :rspec, :fixture => true g.fixture_replacement :factory_girl, :dir=>"spec/factories" end [/ruby] This will make sure that the generators use our own defaults. So now when you type [ruby] rails generate model TestModel name:string rails generate controller TestModel [/ruby] and it will create haml views, rspec tests, and factories. Awesome :)

Prepare to use jquery!

To start using jQuery in Rails3, you have to first get the rails.js specifically for jQuery (stored in the jquery-ujs project). Save it in your public\javascripts directory. Download jquery, and make sure to include both in your application layout or view. In HAML it would look something like. [ruby] = javascript_include_tag 'jquery.min.js' = javascript_include_tag 'rails' [/ruby] BUT: there is a quicker route! We also installed the gem jqeury-rails, which has the following generator if we want to install jquery in one go! [ruby] rails g jquery:install #--ui to enable jQuery UI [/ruby] Rails requires an authenticity token to do form posts back to the server. This helps protect your site against CSRF attacks. In order to handle this requirement the driver looks for two meta tags that must be defined in your page's head. Luckily rails makes it easier for us, again, and we just need to include csrf_meta_tag somewhere inside your page's head (rails3 does this default in your application.html.erb). Be sure to include it in your haml code too. An example application.html.haml would look like this: [ruby] !!! Strict %html{ "xml:lang" => "en", :lang => "en", :xmlns => "http://www.w3.org/1999/xhtml" } %head %title== Test-project #{@page_title} %meta{'http-equiv' => "Content-Type", :content => "text/html; charset=utf-8"} %link{ :href => "/favicon.ico", :rel => "shortcut icon" } = stylesheet_link_tag :all = javascript_include_tag 'jquery-1.4.2.min.js', 'rails.js', 'application.js', :cache => 'all_1' = csrf_meta_tag = yield :local_javascript = yield :head %body #banner =image_tag 'your-logo.png' .the-title %h1 %p Your application #navigation #container #sidebar #contents =yield #footer == © 2010 your company [/ruby]

Done! :)

More ...
Uncategorized ruby rspec
awesome rspec hints and tips

Read "Pure Rspec", a great slideshow by Jon "Lark" Larkowski. It contains some really cool rspec tips and hints, how to write your tests more readable and compact.

More ...
Uncategorized ruby jeweler gem
creating a new gem

I found a few articles that describe easier ways to create a gem. From the entire list of available tools, i want to highlight two: jeweler and (Mr.) bones. Mr. bones seems a very configurable route to take: it allows you to define your own skeletons (application templates) or use those of others, e.g. bort. On the other hand it also seems to do more than i need. Jeweler seems to be very specific in what i does for you, allowing to create a gem very easy and manage your gem locally. Also it is very configurable, so you can immediately create rspec and cucumber folders, fill the wanted rake tasks. It is awesome, and makes starting really easy. So i executed the following command: [ruby] D:\work-git\ruby>jeweler --rspec --cucumber --reek --roodi --create-repo word_automator create .gitignore create Rakefile create LICENSE create README.rdoc create .document create lib create lib/word_automator.rb create spec create spec/spec_helper.rb create spec/word_automator_spec.rb create spec/spec.opts create features create features/word_automator.feature create features/support create features/support/env.rb create features/step_definitions create features/step_definitions/word_automator_steps.rb Jeweler has prepared your gem in word_automator Jeweler has pushed your repo to http://github.com/nathanvda/word_automator [/ruby] which as you can tell created a folder, rspec and cucumber place-holders, prepared my gem and pushed my repository to github! Wow :) Now fill the gem with code :)

More ...
Uncategorized view testing rspec2 rails3 rails rspec
rails3 and rspec2 view testing

Testing the view in Rspec is just great. It allows you to test the view in total isolation. It just does the render. Make sure you set up some data that is needed, and then check if all areas are available for instance. Now for Rspec2 a lot of things have changed:

  • have_tag is no longer supported: use have_selector from webrat instead
  • response is deprecated, use rendered instead
  • the assignment has changed, write assign(:events, [stub_model(Event)]) instead of using the old assigns[:events]=[...] notation Let me show you a full example, because that always makes things clearer: [ruby wraplines="false"] require 'spec_helper' DUMMY_NUMBER="dummy number" DUMMY_MESSAGE="dummy message" describe "envelopes/index.html.haml" do before (:each) do envelope = mock_model(Envelope) envelope.should_receive(:destination).and_return(DUMMY_NUMBER) envelope.should_receive(:message).and_return(DUMMY_MESSAGE) assign(:envelopes, [envelope]) render end it ("has a h1") { rendered.should have_selector('h1')} it ("shows the correct title") { rendered.should contain(t('envelopes.list.title')) } it ("have a table-grid") { rendered.should have_selector('.grid') } it ("shows the destination") { rendered.should contain(DUMMY_NUMBER) } it ("shows the message") { rendered.should contain(DUMMY_MESSAGE) } end [/ruby]
More ...
Uncategorized refactoring rspec
rspec testing using macros

[ruby wraplines="false"] STATUS_EXPECTED_TRANSLATIONS = [[inp1, outp1], ... ] it "should translate received statuses" do STATUS_EXPECTED_TRANSLATIONS.each do |tr| controller.send('translate_status_to_envelope_status', tr[0]).should == tr[1] end end [/ruby] While this is short and DRY, a problem arises when one of the values in my look-up table does not behave as expected anymore. The complete test will fail, without having any clue which value caused it to fail. That is not good! But luckily, in rspec there exists the option to use macros. It is a kind of templates for tests. Using macros i could write this much cleaner, and generate my test-clauses on the fly. [ruby wraplines="false"] STATUS_EXPECTED_TRANSLATIONS.each do |tr| it "should translate #tr[0]} to success" do controller.send('translate_status_to_envelope_status', tr[0]).should == tr[1] end end [/ruby] Now if a test fails, i know which i value need to check, because i will get an appropriate error-message.

More ...
Uncategorized ruby on rails rspec
skipping slow tests in rspec2

For Test::Unit there is a module called skippy, that allows you to skip for instance slow tests. I was looking for a way to achieve the same in Rspec. I am currently developing against Rails 3.0.0.rc, and using rspec 2.0.0.beta.19 and could not find anything. So i asked on the rspec mailing list and got a great answer! It is actually present in rspec2, right out of the box, as a feature they needed for their own tests. Read the description by David himself here. He shows a lot of very good examples, even filtering tests based on ruby-version is now possible. Awesome. In short, you would do something like : [ruby] describe "something", :slow => true do it "should be blabla" end describe "something else" do it "should be a slow test", :slow => true do ... end it "should be a fast test" do .. end end [/ruby] then you can write the following to skip the slow tests : [ruby] # in spec/spec_helper.rb RSpec.configure do |c| c.filter_run_excluding :slow => true end [/ruby] and to run only the slow tests: [ruby] # in spec/spec_helper.rb RSpec.configure do |c| c.filter_run :slow => true end [/ruby] and to filter on slow tests, and run all tests if no slow tests are available: [ruby] # in spec/spec_helper.rb RSpec.configure do |c| c.filter_run :slow => true c.run_all_when_everything_filtered = true end [/ruby] Awesome! :) For the moment there is no command-line support, but in the spec/spec_helper.rb you could also check for any environment variables to do the slow or fast test-set. What i personally needed, was something that would either run all tests, or run all tests excluding a few (i have a test-suite for an sms-gateway and do not want to send sms-es all the time). So i handled that like this: [ruby] # in spec/spec_helper.rb RSpec.configure do |config| if ENV['SEND_REAL_SMS'] != "true" config.filter_run_excluding :send_sms => true end end [/ruby]

More ...
Uncategorized submodules git plugins rails
Using git-submodule to handle plugins

Using git-submodule can make it very easy for you to work with plugins in your rails projects. I will try to show you this, in an easy step-by-step manner. To start, make a plugin-project, call it your_plugin, in its own folder, and push the code to git. Your standard commands apply, as for any project:

  • git status : what is changed?
  • git add . : add the newly added files to your git-repository
  • git commit -am "a meaningful message" : commit your changes in your local repository
  • git push origin master : push your local changes to the remote master (origin/master) How can you add the plugin as a submodule to your rails project? Navigate to the root of your rails project, and execute the following commands: [bash] git submodule add git://your_repository vendor/plugins/your_plugin_name git submodule init git submodule update git status # will show the difference: only the submodule is added git commit -a -m "added plugin your-plugin-name" [/bash] How do you retrieve the lastest version of a submodule/plugin. A submodule in git is coupled to the git-repository at a specific time, so it does not automatically evolve with the remote versions of your pluging. You have to manually make a few operations, to make sure you are using the latest version. In my opinion this is an advantage, as you can keep using a known working version until you really want to upgrade. To update your submodule, go to the root of your plugin/submodule (normally RAILS_ROOT/vendor/plugins/your-plugin-name), and execute the following commands: [bash] git remote update # since your submodule is actually a git repository on its own, you can do this git merge origin/master # retrieve the remote master version cd ...... # back to RAILS_ROOT git status # your submodule is updated to the latest version [/bash] Now to edit and change the plugin/submodule, it is the easiest to work inside the plugin folder itself. To do so, you have to proceed as follows. Inside the root of your plugin (e.g. @\vendor\plugins\your-plugin@) [bash] git checkout -b your_local_branch ... do some changes git commit -a -m "something changed" git checkout master git pull git checkout your_local_branch git rebase master ... solve posslble merge-conflicts ... git checkout master git merge your_local_branch git push [/bash] then cd to RAILS_ROOT [bash] git status # => your plugin will have changed git commit -a -m "improved plugin" [/bash] I used the following sources for inspiration:
  • using git-submodules to track plugins
  • git submodules in n easy steps
  • agile git and the story branch pattern
More ...
Uncategorized rails3 activerecord rails
rewriting find_by_sql for rails 3

I am starting in Rails 3. I have a simple situation where i would select a parent based on a condition of one of its children. Normally i would write something like: [ruby] Distributor.find_by_sql("select d.*, c.rate from distributors d, coverages c where c.country_code_id = 25 and c.distributor_id=d.id order by rate asc") [/ruby] Although this works, it is not the best solution to take. For one, it is vulnerable to sql-injection and secondly it shows a lot of the underlying database structure, and on top of that the sql-implementation could change between databases. In Rails 3 i can now write [ruby] Distributor.includes(:coverages).where("coverages.country_code_id=? and distributors.id =coverages.distributor_id", 25).order(:rate) [/ruby] This is so readable! Awesome :)

More ...
Uncategorized ruby rvm ubuntu
installing ubuntu for ruby development

I have made the complete switch. My home development machine is no longer Windows XP, no longer dual booting Ubuntu but a full-fledged Ubuntu. After installing the dual-boot, and my machine at work this is the third time to install an ubuntu machine, and getting everything ready for ruby development. I just want to archive my steps here, so a next time could be even faster :) Installing Ubuntu 10.04 itself is a piece of cake. My first step after the installation is to enable numlock on login screen (i always use numbers in my passwords) [bash] sudo apt-get install numlockx [/bash] Then run sudo gedit /etc/gdm/Init/Default and find the line [bash] exit 0 [/bash] and add the following code above that line [bash] if [-x /usr/bin/numlockx]; then /usr/bin/numlockx on fi [/bash] Secondly I install rvm for multiple rubies. We first need to install any ruby for that. Take the default ubuntu version (1.8). [bash] sudo apt-get install ruby rubygems [/bash] This does not install the latest version, but we don't need that yet. Rvm will solve this for us. Install rvm itself: [bash] sudo apt-get install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev git-core bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head ) [/bash] Then make sure rvm will work always [bash] sudo gedit .bashrc [/bash] and replace [-z $SP1] && return with [bash] if [[! -z $SP1]]; then .. original content that was below the && return line [[-s $HOME/.rvm/scripts/rvm]] && source $HOME/.rvm/scripts/rvm fi #EOF [/bash] Then rvm should be available. Install the needed rubies. We use ree at work, i like to work with 1.9.1/2 and i want to check out rubinius. So install your rubies through rvm [bash] rvm install ree rvm install 1.9.2 rvm install rbx [/bash] Installing ruby 1.9.1 was a bit harder, when i just tried to run the standard rvm install 1.9.1, i received the following error: [bash] .rvm/src/ruby-1.9.1-p429/lib/optparse.rb:1310: [BUG] Segmentation fault [/bash] and that was caused because i use a newer gcc version, which can't handle the -O3 optimisation. It took me a while to find how you can fix it, but in the end (as always) it was easy. Just type [bash] export optflags="-O0"; rvm install 1.9.1 [/bash] To end, set your default ruby version [bash] rvm ree --default [/bash] now all your new sessions you should be using your selected default version. After installing your favourite editor (Netbeans or rubymine), your favourite database (postgreSQL, sqlite, mysql ), and your list of gems you are ready to roll some ruby! I must say as an previously avid Windows user for ages, i am very impressed by Ubuntu. This is a free operating system, and while i was aware that everything just works better being linux (meaning processes and filesystem); but not only that: it even looks better and is very user-friendly. It is way more customisable looks-wise then silly windows. In Windows 7 for instance you have to use this very large font, and in Ubuntu i can set the size to anything i want (small!!!). Awesome :) And i guess it will amaze me for the next few days and weeks whilst finding out other new stuff. [UPDATE] For me it is confusing that the minimize, maximize and close buttons are on the left-side, i think it is done to be more apple-like. But the fix to move the buttons to the right is luckily very easy once you know it :)

More ...
Uncategorized limited stock shopping cart subjective usability
shopping cart usability

Last wednesday i was offered, in a mail i received, the opportunity to start shopping on friday at 1500hours CET for an very specific item, Instant film at an incredible price. So come last friday, I was ready and braced to start shopping. Unfortunately and to be expected, i was not alone. I was able to get 3 packs of film in my shopping basket, enter my details, select a payment method, and ... just when all I needed to do was confirm the whole thing the site hung up on me and when the site reacted again all stock was gone. This felt very wrong: I was almost there, I had the items in my shopping cart, i was in the checkout line, i should have been able to buy it. It got me thinking how to handle such a thing. So out of this negative experience, i mailed to the support of the site, claiming the way they handled the shopping cart was wrong (maybe i should have said: could be improved), because i was expecting that if i could place items in the shopping basket, i would also be able to buy them; and also to be able to let them know i was unhappy, and hoping they could do something about it come next time. They did reply, though:

Sorry, but that's the way our shop works: until you click the "place order" button, the stock is not reserved for you. Only by confirming your order, you are then guaranteed the order. Stock is subtracted not upon successful payment, but the moment you confirm your order. The payment is then processed and your order marked as "paid" and passed on to processing.

While their approach makes sense for normal e-commerce sites, sites where the stock is limited ask for another approach. Of course, as a developer it becomes more difficult to get items out of stock once they are placed in the shopping cart, most especially because when to release the items to stock if the customer does not buy? I did find another article, explaining when retailers should empty a shopping cart. From the article i deduced some rules:

  • if your stock is limited, placing items in the shopping cart should reserve the item (removing it from available stock temporarily), so you have a difference between the actual stock (what the retailer has in their storage, reserved stock (about to be sold or not) and sold stock). So the amount of stock visible on the site should be actual stock-reserved stock.
  • how long your shopping cart is valid should be visible or communicated (e.g. countdown clock) I would like to note that this is especially true for ticketing services, where stock is in very limited supply and in large demand. You want to give the user the good shopping experience (when a customer puts the items in the shopping basket, there still was stock, so he or she should be able to buy them), but also not let your users hoard the stock. An excellent example from the above-mentioned article is Ticketmaster, where a user can put tickets in her basket, and then has a predefined time (two minutes) to complete the purchase or the cart is emptied and the stock released again. As a consequence, the meaning of your shopping cart is different: it is a clear intention to buy, so it will not be used as a wish list. On e-commerce sites where there is no such peak of sales, shopping carts can even persist over different sessions, allowing returning users to continue shopping. Such a use of a shopping cart would not be linked to the stock directly (e.g. reserving items), but whether an item is in stock would be checked at the start of a new session. This is in high contrast with an e-commerce site offering items which are in very limited supply and high demand (like tickets or instant film). The standard approach does not suffice. If putting items in the shopping basket takes them out of the stock, the load can be spread more evenly. Let me explain that by example, by comparing 2 scenarios. Scenario 1, the standard e-commerce site, items are only taken out of stock after an order is confirmed:
  • 1000's of people log on
  • all of them add a number of items to their shopping basket
  • all of them start filling in their details, payment methods, delivery address, and all this has to be verified, connections to Paypal, credit-card service, ...
  • in the meantime no items have been sold, so users logging on can still start buying things, thereby adding more load to the server, ...
  • the server bends under the escalating load Now compare this to scenario two, where items are being "reserved" if they are put inside the shopping basket, and a user has two minutes to complete the order-confirmation process:
  • 1000's of people log on
  • 400 or more of those people get rejected, because the items have been reserved
  • the users who were able to get items in the basket, fill in the details, which have to be verified, ...
  • users logging on later will in the meantime not be able to order anything, because all items have been reserved
  • after the first two minutes have passed, most of those first items will have been bought, and some will have released again
  • some users will be able to fetch released items and can continue shopping This scenario will not only communicate better to your clients, the process is clearer, AND the load on your servers can't escalate in the same way. This process could then be further improved, so that users logging on are placed in a FIFO queue. The first users to place an order get their items until stock runs out. The following ones are placed in a waiting queue, and busy-wait at most the two minutes (the maximum time before items could be released) for those that are released, if any. If a user has no patience, he releases his place in the queue. If you add to that some real-time communication (pushing to the client?), you would have a real clean a user-friendly system. From the moment a user logs on, it is clear what is going on.
More ...
Uncategorized actionmailer attachments windows ruby on rails
actionmailer attachments on windows

I have been having troubles sending e-mails using ActionMailer on windows. The simple code-sample: [ruby] my_filename="my_image.jpeg" attachment "image/jpeg" do |a| a.body = File.read(my_filename) a.filename = File.basename(my_filename) end [/ruby] did not work. I did find an attachment inside my e-mail, but it was corrupt. It took me a while to figure out it could be something related to my development platform, which unfortunately still is windows (not for long). On windows reading binary files is less obvious, apparently, so you need to write: [ruby] my_filename="my_image.jpeg" attachment "image/jpeg" do |a| a.body = File.open(my_filename,'rb') { |f| f.read} a.filename = File.basename(my_filename) end [/ruby] ... and this will work! :) I you have to combine normal e-mail content and one or more attachments, this then becomes something like: [ruby] # we send a mail to respond to a mention def mention_response(given_subject, addressee, pdf_attachment = nil) from APP_CONFIG["mail"]["from"] recipients addressee.to_a subject given_subject content_type "multipart/mixed" part "text/html" do |p| p.body = render_message("mention_response", :thr_name => thr_name) end attachment :content_type => "application/doc" do |a| a.filename File.basename(pdf_attachment) a.body File.open(pdf_attachment, "rb") { |f| f.read } end unless pdf_attachment.nil? end [/ruby] Nice :)

More ...
Uncategorized ruby strings
use %q to create strings

In my gemspec created by jeweler I saw string creating using %Q. What? [ruby] gem.summary = %Q{TODO: one-line summary of your gem} gem.description = %Q{TODO: longer description of your gem} [/ruby] I found a pagedescribing ruby string creation, and it seems %Q is the equivalent of double quote delimited strings and %q is the equivalent of single quotes. While i was pondering what the advantage could be of writing it that way, i opened up irb and look and behold: [ruby] irb(main):001:0> test = %Q{ggg gggg ggg} => "ggg gggg ggg" irb(main):002:0> test2= "ff ff ff" => "ff ff ff" irb(main):003:0> test= %Q{%q{ffff ffff ffff}} => "%q{ffff ffff ffff}" irb(main):004:0> test= %Q{this is a "test", curious whether 'it' works :)} => "this is a "test", curious whether 'it' works :)" irb(main):005:0> test= %Q{this is a "test", i am curious whether #{test2} 'it' works :)} => "this is a "test", i am curious whether ff ff ff 'it' works :)" irb(main):006:0> [/ruby] Cool! It allows you to write your strings without having to think about escaping the quotes.

More ...
Uncategorized dual boot wubi ubuntu
easiest dual boot ubuntu install

I wanted to convert my XP laptop to a dual boot with Ubuntu or Kubuntu. Whichever. I want to try out linux and maybe switch altogether. Run windows inside a Virtualbox if i would really need it (e.g. for work). So i looked up different tutorials, while i was cleaning up disk-space and suddenly bumped into Wubi. I assumed i had to play with partitions and bootsectors, but the Wubi-installer manages all that for you. Just download the program (1.4MB!), run it, fill in a user and password and it takes all the work out of your hands. Completely automatic. Ideal for me ;)

More ...
Uncategorized ruby mingw32 plugin git
script/plugin install from git fails

I am using ruby 1.8.7 on windows (mingw32), and all of a sudden i cannot run [ruby] c:\> ruby script/plugin install git://github.com/daphonz/dirty_associations.git Plugin not found: ["git://github.com/daphonz/dirty_associations.git"] [/ruby] the suggested variations also don't work, e.g. [ruby] ruby script/plugin install http://github.com/daphonz/dirty_associations.git ruby script/plugin install http://github.com/daphonz/dirty_associations.git/ [/ruby] all give the same error. But, apparently, it has something to do with the mingw32 platform. In C:\Ruby\lib\ruby\gems\1.8\gems\activesupport-2.3.5\lib\active_support\core_ext\kernel\reporting.rb the following line can be found in function silence_stream: [ruby] stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') [/ruby] Replace that with the correct way to check for the windows platform, and then all should be fine again :) [ruby] stream.reopen(RUBY_PLATFORM =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') [/ruby] I still needed to replace git:// with http:// but now it works :) Now investigate how this can be pushed to Rails codebase?

More ...
Uncategorized javascript observe_field ruby on rails
keeping observe_field and spinner in sync

I am using a lot of observe_fields in my views. I have two searches on my form, one with two fields one with four, and every time a user types something the observe_field is triggered and some search is executed via AJAX. To make sure the user knows what is going on, i use a spinner-image. [ruby] <%= observe_field 'querypeople', :frequency => 1, :update => 'people_to_link', :before => "Element.show('spinner2')", :loaded => "Element.hide('spinner2')", :complete => "Element.hide('spinner2')", :url => {:action => 'listpeople'}, :with => " 'querypeople=' +escape($('querypeople').value) + '&queryorganisation=' + escape($('queryorganisation').value)" %> <%= observe_field 'queryorganisation', :frequency => 1, :update => 'people_to_link', :before => "Element.show('spinner2')", :loaded => "Element.hide('spinner2')", :complete => "Element.hide('spinner2')", :url => {:action => 'listpeople'}, :with => " 'querypeople=' +escape($('querypeople').value) + '&queryorganisation=' + escape($('queryorganisation').value)" %> [/ruby] This works all fine and dandy, but when a user types multiple characters in a row, the spinner is hidden while another query is running. So i needed to improve that. I first introduced a little code to count how many times a certain spinner is shown: [ruby] <% javascript_tag do %> var spinner_counter=[0,0,0]; function show_spinner(itm) { spinner = (itm == 0) ? "spinner2" : "spinner" ; Element.show(spinner); spinner_counter[itm] = spinner_counter[itm] + 1; } function hide_spinner(itm) { spinner = (itm == 0) ? "spinner2" : "spinner" ; spinner_counter[itm] = spinner_counter[itm] - 1; if (spinner_counter[itm] <= 0) { Element.hide(spinner); spinner_counter[itm] = 0; } } <% end %> [/ruby] and then adapted the ruby-code as follows: [ruby] <%= observe_field 'querypeople', :frequency => 1, :update => 'people_to_link', :before => "show_spinner(0)", :complete => "hide_spinner(0)", :url => {:action => 'listpeople'}, :with => " 'querypeople=' +escape($('querypeople').value) + '&queryorganisation=' + escape($('queryorganisation').value)" %> <%= observe_field 'queryorganisation', :frequency => 1, :update => 'people_to_link', :before => "show_spinner(0)", :complete => "hide_spinner(0)", :url => {:action => 'listpeople'}, :with => " 'querypeople=' +escape($('querypeople').value) + '&queryorganisation=' + escape($('queryorganisation').value)" %> [/ruby] Do you know a better solution?

More ...
Uncategorized mongrel service thin windows ruby on rails
mongrel_service beta troubles with space

I am switching back from using thin inside a service to mongrel_service, because when my thin-process is killed somehow, the service stills seems to be running. Mongrel_service can cope with this much better: it also keeps a check on your ruby process and restarts it if needed (at least in the old version, i hope the 0.4.beta3 prerelease version behaves the same). When using the mongrel_service (gem install mongrel_service --pre) on ruby 1.8.7 you can no longer have a space inside the name. So if you run the following command: [bash] mongrel_rails service::install -N "Name with a space" -c c:\path\to\your\app -p 4000 -e production [/bash] there will be no output as to whether it succeeded or not on XP, on Windows Server 2008 a more appropriate error is shown; but the service will not be created. The trouble is the name: it contains a space, and apparently that is no longer allowed. On the old MRI and previous mongrel_service it was not a problem. The old version, however, does not work in ruby 1.8.7 from rubyinstaller.org, due to a dependency to some very specific Visual C++ code regarding service communication (and now the ruby is compiled using gcc). Luckily there is an easy fix, as suggested by Luis Lavena himself: [bash] mongrel_rails service::install -N name_without_space -D "Name with a space" -c c:\path\to\your\app -p 4000 -e production [/bash]

More ...
Uncategorized model mvc ruby on rails
accessing current_user in models

Up until now i was able to somehow circumvent the need to access the current-user in the model, by calling methods from the controllers and handing down the current-user. In the MVC pattern, the model should know as little as possible about things the controller handles. But now, i need a method that will check :before_save what has changed, and by whom, and will log that into another table (model). So i am going to create an Observerclass, that needs to access the model on the one hand, but needs to know the current-user on the other hand. First I found a very dirty but working solution. Put this in application.rb: [ruby] around_filter :you_dont_have_bloody_clue protected def you_dont_have_bloody_clue klasses = [ActiveRecord::Base, ActiveRecord::Base.class] methods = ["session", "cookies", "params", "request"] methods.each do |shenanigan| oops = instance_variable_get(:"@_#{shenanigan}") klasses.each do |klass| klass.send(:define_method, shenanigan, proc { oops }) end end yield methods.each do |shenanigan| klasses.each do |klass| klass.send :remove_method, shenanigan end end end [/ruby] This was credited to Pratik Naik, but at the same time highly NOT recommended by him. It seems a bit like a bulldozer approach. Actually it is nice to know such things are possible, and how to achieve it, but it (kind of) breaks the MVC pattern. So i looked further for a nicer solution. I found a really simple one here, and adapted it to my needs: [ruby] class User < ActiveRecord::Base cattr_accessor :current_user def self.current_user @current_user ||= User.new("dummy-user") end ... end class ApplicationController < ActionController::Base include AuthenticatedSystem before_filter { |c| User.current_user = session[:user] } end [/ruby] And now, inside each class, i can just use [ruby]User.current_user[/ruby]. I overwrite the current_user class method, so i don't have to set the user manually during tests (is that clean?). I am not sure if this is the best solution. I found a few more complicated ones, but this seems to fit me the best.

More ...
News ruby arrrrcamp ruby on rails
Arrrrcamp

Went to arrrrcamp last friday (Arrrr as in _R_uby, _R_ails, _R_adiant and, of course, _R_hum!). It was the third edition of this unique ruby-on-rails event, and the third time i visited it ;) So i am a regular :) The first year i was just starting ruby and my then-collegue and me learned a lot. The second time i took some new collegues along hoping to get them infected with the ruby virus. This year i went alone (so you can guess how well the infection spread :), but one advantage of being alone in a croud is that it is way easier to mingle. There's even a picture to prove it :) I saw some very interesting talks:

  • Something Something Mongo: I alrready had read about Mongo, and was interested. This speech interested me more than Radiant. Just another NoSQL database. Some things were not entirely clear, like how you can query stuff if all things are in the same "database". But it seems like something i should investigate more. I think there are a lot of possible applications, and the presenter showed a very good example, where the database is entirely configurable by the end-user, which is dead-easy in Mongo and MongoMapper, because there is no schema! Ha! :) Opens up possibilities indeed ;)
  • jQuery on Rails: at the same time there was a talk about the new things in Rails3. So this was a hard choice. But i am already using jQuery, in combination with Prototype, and was hoping to get some tips to do it better. The talk was very quick, but also very informative. The presenter did a very cool job, where he showed the same site in Prototype (using helpers) and jQuery (using unobtrusive javascript). Very nice. I still write most of my javascript inline, and am gradually switching over. I am still struggling with one problem. In most of unobtrusive javascript examples, i always see that all code is placed in the application.js. But that is not good enough for me. I want a js file per erb-file. I found a blogpost by Yehuda Katz, where he does something even smarter: only include the js-files which include the selectors from the current page. But unfortunately it is so old, the source is nowhere to be found anymore. when i asked the presenter, after the session, he pointed me to this article about Jzip, but on second look it is not quite what i am looking for.
  • Railties: what, why & how?: a very interesting talk, but i must admit, since Rails 3 territory is still very unknown to me (and a lot has changed apparently) a lot of it was unclear. In short: the old way to create rails plugins is replaced by Railties. Plugins and engines are supported, dependencies are more explicit. Something i still need to look into, to convert the plugin we use at work.
  • Something something Rack: actually i did not want to see this one, but rather the 12 hours to rate a rails website by Elise Huard, but because @Atog was late those two talks had switched. She confided, however, that i would get a second change at RailsConf :) The something-something-rack talk was very basic, but also enlightning. Rack provides a minimal interface between webservers supporting Ruby and Ruby frameworks. Rack applications can be stacked. Since Rails is a Rack application, it is now very easy to put Rack-apps in front of Rails, for instance to redirect to different sites or pages if the visitor uses a mobile device (Rack::MobileDetect), add google analytics to your pages automatically (Rack::GoogleAnalytics), or to block unallowed access (Rack::Warden). Very interesting. Also allows for a clean seperation of concerns. One last Rack middleware I really want to mention: Rack::ChromeFrame! This middleware will make sure the Google Chrome frame is automatically enabled. Cool :)
  • Learning to smile at your code: a talk by two german guys, who both work at Xing, about refactoring and to learn to actually enjoy it. Xing is a very big website, coded for the largest part in Rails. They have 22 developers working in Rails. Sebastian and Tim, the presenters, had to add features to the job-postings page/code and encountered a lot of problems doing so. I really liked this talk because i found it very recognisable and also because it was a talk focusing on the programming of an application as a whole. They used a lot of humour to convey their message, with success. Really-really compressed their message was: 1) seeing a lot of old, incomprehensible code can be demotivating; 2) breathe and relax; 3) starting to refactor it anyway, despite the obvious unwillingness at first, will make you smile because you can create something beautiful. They gave some examples which i guess barely even scratched the surface of the complexity they had to deal with. Nice :) After that the lightning talks came (short talks of about 10 minutes). I will highlight a few:
  • failtale: a notification framework/website by the guys from Mr. Henry. Impressive, because not only does it capture ruby/rails exceptions, but also ActionScript (flash) and Javascript soon. I am going to try that out! :) I am currently using Exception Notifier myself, curious how it compares.
  • The guys from 10-forward did three talks. First a demo of their application, which was incredibly impressive. Wow! Blew me away. A lot of javascript and ajax to make the website feel like a real application. Very powerful. Then they discussed a gem of theirs, and rspec and cucumber.
  • wallsome: Sebastian and Tim from Xing, who also did the Learning to smile talk, here presented their pet-project, using Rails 3 and jQuery: a wall to arrange your tasks from Basecamp like in Scrum or Kanban. I am looking forward to the next edition on the 29th of october! :)
More ...
Uncategorized ruby word automation word2007
setting word bookmarks from ruby

The easy solution to set a bookmark inside a Word-document: [ruby] require 'win32ole' word = WIN32OLE.new('Word.Application') doc = word.Documents.Add("#{path to your template here}") doc.Bookmarks("bookmark-name").Range.Text = "new content here" [/ruby] This will work, and will replace the bookmark with the text you wanted to insert. Recently i had to convert a document that was first built using mail-merge. I am not very familiar with mail-merge, but it seems a specific field can occur multiple times inside the document. This is very convenient. So i looked for a way to replace this behaviour, and still use bookmarks. I know how to set bookmarks programmatically, and this seemed easier than preparing a temporary document first for mail-merging. My first thought was that i create bookmarks, and give the duplicate bookmarks names like "#{original -bookmark-name}_2" , and inside my program i would go looking if there would be any copies (_2, _3, _4) and set them accordingly. But i looked further. There should be a better way. Luckily there does exist something called "REF" fields inside Word, which are fields that inherit their content from a certain bookmark! A-ha! But the above code won't work, because i actually replace the bookmark with the text, and then nothing is left to be reffered to :) So the code to set a bookmark turns a bit more complex: [ruby] require 'win32ole' word=WIN32OLE.new('Word.Application') doc = word.Documents.Add("#{your-template-path}") ## wdGoToBookmark = -1, wdCharacter = 1 word.Selection.GoTo("What" => -1, "Name" => "#{your-bookmark-name}") word.Selection.Delete("Unit" => 1, "Count" => 1) word.Selection.InsertAfter "#{your-new-text}" # re-create our bookmark doc.Bookmarks.Add("Range" => word.Selection.Range, "Name" => "#{your-bookmark-name}") # update all (referring) fields doc.Fields.Update # in Word2007, filetype 16 saves as a Word2003 compatible document, 12 is docx, 17 is pdf doc.SaveAs "#{your-filename}.doc", 16 [/ruby] [UPDATE] Actually, although this works, it doesn't work if two bookmarks are really close, e.g. only seperated by a single space. So the above is not the correct way. Some googling revealed the correct way: [ruby] # new version of code bm_name = "#{your-bookmark-name}" bm_range = doc.Bookmarks(bm_name).Range bm_range.Text = "insert something interesting here" doc.Bookmarks.Add bm_name, bm_range [/ruby] I hope this helps :)

More ...
Uncategorized mongrel_service service thin windows rails
mongrel_service alternative: using thin and srvany

So i am developing and deploying Ruby on Rails applications on Windows. Recently i started experimenting with the newer versions of ruby (mingw32platform). One of the side-effects is that the mongrel-service, which i always used to deploy my rails-applications no longer works on mingw32. And aside of that, i have read on various instances [ref] that thin should be better (more efficient) than mongrel. But i still want to install it as a service. First off, you need to download and install the Windows Resource Kit. This contains the executables to make a service of any executable or script. Then create the service running (in the console): [bash] C:\Program Files\Windows Resource Kits\Tools> instsrv "[my_service_name]" "c:\program files\Windows Resource Kits\Tools\srvany.exe" The service was successfuly added! Make sure that you go into the Control Panel and use the Services applet to change the Account Name and Password that this newly installed service will use for its Security Context. [/bash] This will add an empty entry in the registry, which actually still does nothing. To get it working, we have to start regedit, and navigate to the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services[my_service_name] Create a new key (folder) named Parameters. This will contain the settings of our actual application that will be run as a service. Add the following String Values: [bash] [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services[my_service_name]\Parameters] Application=c:\ruby\bin\ruby.exe AppDirectory=[my_ruby_app_folder] AppParameters=c:\ruby\bin\thin start -p 4000 -e production [/bash] Assuming that c:\ruby\bin is your ruby folder, and you want your thin to listen to port 4000. Once that is done, start the service, and your rails application should be up and running :)

... but Windows Server 2008

Unfortunately, to do this on Windows 2008 you need to perform some extra steps. As you can't install the resource kit on Windows Server 2008R2 for some peculiar reason, and at the time of this posting, i have not found a Windows Server 2008 Resource Kit Tools, so i took the following steps:

  1. copy the "srvany.exe " from the "Windows Server 2003 Resource Kit Tools " to a suitable location on your Win2008 server (e.g. C:\Windows\System32\ )
  2. use "sc " to create a new service that launches "srvany " (e.g. sc create MyService binPath= C:\Windows\System32\srvany.exe DisplayName= "My Custom Service" )
  3. using RegEdit create a "Parameters " key for your service as before and fill it with the 3 string values A bit more work, but not too much.

mongrel-service?

And just today I discovered an update of mongrel_service was announced, so you can still work using mongrel_service instead of using thin and manually creating the service. What you need to do:

  • install mongrel service: gem install mongrel_service --prerelease
  • create the service as before: mongrel_rails service::install -N myapp -c c:\my\path\to\myapp -p 4000 -e production That is much easier of course.
More ...
Uncategorized ruby oci ruby-oci8 x64 windows
ruby-oci8 on x64: not a valid win32 executable

working on Windows Server 2008R2 64-bit, installing ruby 1.8.7, ruby-oci8 ran into the following error, after requiring 'oci8' : LoadError 193: %1 is not a valid Win32 applicationOn this machine a 64bit version of Oracle was installed. So the OCI.dll was a 64-bit version. The fix seemed easy: copy a 32-bit version of the OCI.dll. But I had to copy (from another 32-bit machine)

  • OCI.dll (32-bit)
  • MSVCR71.dll
  • ... and ORAOCIEI10.dll

to my ruby\bin folder, and then everything worked. Copying just the OCI.dll and MSVCR71.dll gave the puzzling error OCIError: OCI library initialization error.

More ...
Uncategorized ruby refactoring rails
refactoring ruby code

Most of my ruby/rails development is against a legacy Oracle database. One of the things we needed to fix, was a user-table with not enough fields. Because the user table was shared with another application, we were not able to alter the table. So we added another table, user_params, containing possibly extra parameters for each user. Now it would be nice if each of those possible parameters would behave like a real attribute. So, first implementation: [ruby] class User < ActiveRecord::Base set_primary_key "user_name" set_table_name "stca_user" set_sequence_name "autogenerated" # do not use a sequence at insert! validates_presence_of :user_name validates_presence_of :password # define some virtual attributes for attributes defined in the UserParam table def group_name UserParam.get_param_value(self.user_name, 'UserGroup') end def group_name=(value) UserParam.set_param_value(self.user_name, 'UserGroup', value) end def title UserParam.get_param_value(self.user_name, 'UserTitle') end def title=(value) UserParam.set_param_value(self.user_name, 'UserTitle', value) end def language UserParam.get_param_value(self.user_name, 'UserLanguage') end def language=(value) UserParam.set_param_value(self.user_name, 'UserLanguage', value) end def full_name UserParam.get_param_value(self.user_name, 'UserFullName') end def full_name=(value) UserParam.set_param_value(self.user_name, 'UserFullName', value) end def email UserParam.get_param_value(self.user_name, 'UserEmail') end def email=(value) UserParam.set_param_value(self.user_name, 'UserEmail', value) end # ... snipped away more code end [/ruby] Obviously, this code is not DRY. At lot of repetition, like the stuff i hate about C# or java properties. This could be done better, let's just generate the methods: [ruby] class User < ActiveRecord::Base set_primary_key "user_name" set_table_name "stca_user" set_sequence_name "autogenerated" # do not use a sequence at insert! validates_presence_of :user_name validates_presence_of :password # define some virtual attributes for attributes defined in the UserParam table instance_eval do [['group_name', 'UserGroup'], ['title', 'UserTitle'], ['language','UserLanguage'], ['full_name', 'UserFullName'], ['email', 'UserEmail']].each do |arr| define_method arr[0].to_sym do UserParam.send('get_param_value', self.user_name, arr[1]) end define_method "#{arr[0]}=" do |value| UserParam.send("set_param_value", self.user_name, arr[1], value) end end end end [/ruby] This looks nice. One disadvantage might be that this is not very readable. At first glance it is no longer clear which attributes are available. But with models that is always the case. A few things can still be improved. Every get and set is a query against the database. We might want to improve upon that, and cache results. Also saving the virtual fields is now done when they are being set, but at that time the parent "User" might still not be saved. So this still calls for a better solution. But this does show why i like ruby so much. It makes me feel powerful :)

More ...
Uncategorized oracle_enhanced_adapter oracle rails
rails and avoiding oracle sequences at insert

When using Rails on top of an Oracle database, you use the oracle enhanced activerecord adapter. This adapter (or Rails) has one weird side-effect: there is no way to avoid using a sequence when inserting a new record. But, in this comment, Raimonds Simanovskis hints at the solution. In an initializer you write: [ruby] # a small patch as proposed by the author of OracleEnhancedAdapter: http://blog.rayapps.com/2008/05/13/activerecord-oracle-enhanced-adapter/#comment-240 # if a ActiveRecord model has a sequence with name "autogenerated", the id will not be filled in from any sequence ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do alias_method :orig_next_sequence_value, :next_sequence_value def next_sequence_value(sequence_name) if sequence_name == 'autogenerated' # we assume id must have gotten a good value before insert! id else orig_next_sequence_value(sequence_name) end end end [/ruby] ... and in your model you add: [ruby] set_sequence_name 'autogenerated' [/ruby]

More ...
Uncategorized ruby win32
multiple ruby versions on windows

I started developing ruby more than a year ago, on windows, which might not be the ideal platform :) But i started out with the standard one-click installer, ruby version 1.8.6, which up until recently served me fine and is an easy way to start. But when i felt the need to install metric_fu, i found out it just does not install on top of the old ruby 1.8.6 (mswin32). Now i know that for ruby 1.8.7 (mingw32) a development kit exists, which would allow compilation of all native code. So, normally, all plugins that were giving me problems before (e.g. thin!) should be able to be installed using that. Also the new rubyinstaller versions are known to be quicker, because they are using a more recent and efficient compiler (mingw), and ruby 1.9.1 should inherently be even more efficient (by design). But i was looking for an easy way to migrate and test ruby versions. I know that there exist a ruby version manager (rvm), but it only works on linux and mac. But luckily, for windows, there is pik. It is really easy to install: [bash] > gem install pik > pik_install c:\windows\system32 [/bash] [the choice to use windows\system32 is maybe not entirely kosher, but it is an easy way to add something to the path, always ;) Maybe i should have used c:\ruby\pik\bin and added that to the path.] Then add the current version as the default: [bash] > ruby -v ruby 1.8.6 (2008-08-11 patchlevel 287) [i386-mswin32] > pik add Adding: 186: ruby 1.8.6 (2008-08-11 patchlevel 287) [i386-mswin32] Located at: c:/ruby/bin [/bash] Then you can download the new versions, e.g. ruby 1.8.7. and 1.9.1 from rubyinstaller and install them each into their own folder. E.g. c:\ruby\187-p249\ and then issue the following command: [bash] > pik add c:\ruby\1.8.7-p249\bin ... > pik add c:\ruby\1.9.1-p378\bin ** Adding: 191: ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-mingw32] Located at: c:\ruby\1.9.1-p378\bin > pik list 186: ruby 1.8.6 (2008-08-11 patchlevel 287) [i386-mswin32] * 187: ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mingw32] 191: ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-mingw32] [/bash] But of course, the second problem is that the one-click installer also includes a lot gems by default, while the new rubyinstaller is almost empty. So first i installed the development kit from rubyinstaller. I needed to extract that inside the each ruby folder, and change a few settings (configure), like described here, i needed to edit my /devkit/msys/1.0.11/etc/fstab settings file, and replace c:\ruby by my actual ruby-installation folder, in my case something like c:\ruby\1.8.7-p249. I create a small batch-file to install all the missing gems: [bash] rem default windows gems call gem install win32-api call gem install win32-clipboard call gem install win32-dir call gem install win32-eventlog call gem install win32-file call gem install win32-file-stat call gem install win32-process call gem install win32-sapi call gem install win32-service call gem install win32-sound call gem install win32console call gem install windows-api call gem install windows-pr call gem install hpricot call gem install nokogiri call gem install wxruby rem RAILS call gem install rails call gem install will_paginate call gem install mongrel call gem install mongrel_service call gem install formtastic rem database gems call gem install sqlite3-ruby call gem install ruby-oci8 call gem install activerecord-oracle_enhanced-adapter call gem install builder call gem install calendar_date_select call gem install cgi_multipart_eof_fix call gem install composite_primary_keys call gem install log4r call gem install ezcrypto rem testing call gem install cucumber call gem install cucumber-rails call gem install factory_girl call gem install remarkable call gem install rspec call gem install rspec-rails [/bash] But i still encountered an error on the gems that needed to build native extensions: [bash] C:\WINDOWS>gem install hpricot Building native extensions. This could take a while... ERROR: Error installing hpricot: ERROR: Failed to build gem native extension. c:/Ruby/1.9.1-p378/bin/ruby.exe extconf.rb checking for stdio.h... yes creating Makefile make MAKE Version 5.2 Copyright (c) 1987, 2000 Borland Fatal: '/c/Ruby/1.9.1-p378/include/ruby-1.9.1/ruby.h' does not exist - don't know how to make it Gem files will remain installed in c:/Ruby/1.9.1-p378/lib/ruby/gems/1.9.1/gems/hpricot-0.8.2 for inspection. Results logged to c:/Ruby/1.9.1-p378/lib/ruby/gems/1.9.1/gems/hpricot-0.8.2/ext/fast_xs/gem_make.out [/bash] It took a good nights rest to figure that one out: i have Borland's Cbuilder 5 installed on my system to be able to maintain ancient software. So i had to remove that entry from my path, and after that all gems that needed native building went smoothly, except mongrel_service. Now everything installed just fine, inside my 1.8.7 system. Doing the same on ruby 1.9.1 took a lot longer, or so it seemed definitely. I think partly that is because ruby 1.9.1 seems to maintain a class cache? But i am not sure of that. But what surprised me even more is that actually all gems installed without any problem, except win32-service and because of that, mongrel_service. As explained here, this issue is known and due to the fact that the library relies on specific MSVC behaviour that mingw does not support. But i think i can create a service from about any executable or batch file. But i read herethat i have to issue the following command: [bash] c:\ruby> gem install mongrel_service --prerelease [/bash] The pre-release version removes the dependency of win32-service, and so it works again. So now i can start testing my applications inside 1.8.7 and 1.9.1 on windows, try using thin, and get metric_fu up and running.

More ...
Uncategorized ruby exceptions actionmailer rails
exception notifier configuration troubles

I installed and configured exception notifier to be notified of any unexpected errors in our production environment. At first i tried this out in development, used gmail as my smtp server and all was working fine. My action mailer configuration looked as follows, in environment.rb: [ruby] # configure mailing config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :enable_starttls_auto => true, :address => "smtp.gmail.com", :port => "587", :domain => "localhost", :authentication => :plain, :user_name => "<snipped>", :password => "<snipped>" } ExceptionNotifier.exception_recipients = %w(bla@my_clients_domain.com) ExceptionNotifier.sender_address = %("<snipped>@gmail.com") ExceptionNotifier.email_prefix = "[My Application ERROR] " [/ruby] Using this configuration worked, and i received the e-mails. Alas, as usual, on my client's production server the port to reach gmail was blocked, and when i asked to open it, they instead proposed to use their own smtp-server. So i changed the configuration as follows: [ruby] config.action_mailer.smtp_settings = { :address => "192.168.0.10", :port => "25", :domain => "production-domain.be", :authentication => nil } ExceptionNotifier.exception_recipients = %w(bla@my_clients_domain.com) ExceptionNotifier.sender_address = %("info@production-domain.com") ExceptionNotifier.email_prefix = "[My Application ERROR] " [/ruby] The first thing i did wrong was the domain-name. At first i wrote "@production-domain.be" in my action-mailer configuration, so my HELO request was blocked. Secondly, apparently, because i wrote ExceptionNotifier.sender_address = %("info@production-domain.com") the sender address was not recognised and the mail was rejected by our own SMTP-server. This took me a while to figure out. Luckily our sys-admin noticed the difference. The fix: [ruby] ExceptionNotifier.sender_address = %(info@production-domain.com) [/ruby] And now i know for sure that if i get no mails, my application really is working :)

More ...
Uncategorized rjs javascript ruby on rails
observe_field in IE8: endless loop

My users showed me the weirdest problem today. In my application is a select-box that allows users to select the classification. When the classification is changed, the div containing the icons for the actions (and the classification-select-box itself) is updated to reflect the new classification. So i use an observe_field to watch the select-box, and trigger some javascript to perform the magic. In Firefox this works perfectly. But my users tend to use IE8, for some obscure reason, and switching to FF or Chrome is ... difficult (What other browser?). The observe_field is written as follows: [ruby] <%= observe_field "mention_thm_classification", :frequency => 0.5, :update => "mention-actions", :with => "classification_id", :before => "Element.show('spinner_cl')", :loaded => "Element.hide('spinner_cl')", :complete => "Element.hide('spinner_cl')", :url => { :action => "set_classification", :id => mention } %> [/ruby] Pretty straightforward. The observe_field is contained inside the div that is updated. When in IE8 a new value is chosen, i get the correct value in my method first, and then i get a whole bunch of classification_id="null". I am guessing what happens is that when the html is updated, somehow also the select-box is emptied, and thus changed, and thus a new value is triggered. So i replace the html again, and the select-box is emptied again, and an endless loop is born. So, the easy solution should be: do not do the action of the observe_field if the value of the select-box is null, and that is actually really easy: [ruby highlight="3"] <%= observe_field "mention_thm_classification", :frequency => 0.5, :update => "mention-actions", :with => "classification_id", :condition => "value != null", :before => "Element.show('spinner_cl')", :loaded => "Element.hide('spinner_cl')", :complete => "Element.hide('spinner_cl')", :url => { :action => "set_classification", :id => mention } %> [/ruby] We add a :condition that checks just that! It still feels i am doing something wrong, that i should not have to do this, so i would be happy to hear any way to improve this.

More ...
Uncategorized javascript jquery ruby on rails
using content_for jquery on document ready

In my Rails application i use a generic application.rhtml for all my pages. Amongst others, this code contains some jQuery code to manipulate my page [javascript] var $j = jQuery.noConflict() $j(document).ready(function() { // remove all alt-tags $j("[alt]").removeAttr("alt"); // validate all forms $j("form").validate({ errorPlacement: function(error, element) { error.appendTo( element.parent() ); }}); }); [/javascript] The things i do in my document ready callback is simple: remove the alt attribute everywhere, so my tooltips will work on my links containing images, and if there is a form on the page i validate it. Now for one form, i need to add special code, so that when a user fills something in a field, a select-box looses some options. The ideal place to do this, is in the document ready. But not for all pages. How do i solve this in some elegant way, and not use a different layout for that page. I choose to use yield and content_for. Like this. Add the following line : [javascript] var $j = jQuery.noConflict() $j(document).ready(function() { // remove all alt-tags $j("[alt]").removeAttr("alt"); <%= yield :script %> // validate all forms $j("form").validate({ errorPlacement: function(error, element) { error.appendTo( element.parent() ); }}); }); [/javascript] and in my view i write: [ruby] <% content_for :script do %> var allOptions = $j('#mention_thm_classification option').clone(); $j('#mention_thm_reference_local').change(function() { var filter_txt = '.ref-'; if (!$j(this).val()) { filter_txt = filter_txt + 'empty'; } else { filter_txt = filter_txt + 'filled'; }; $j('#mention_thm_classification').html(allOptions.filter(filter_txt)); }); <% end %> [/ruby] So what i actually do is, check whether the value of a field changes. When it contains something a select-list with id mention_thm_classification is changed, and only the options with the correct class are kept. For completeness, my select is built as follows: [html] <select name="mention[thm_classification]" id="mention_thm_classification" > <option value='1' style='background-color: #b7f9e2' class="ref-empty " >Green</option> <option value='2' style='background-color: #ffdebb' class="ref-empty " >Orange</option> <option value='3' style='background-color: #ffbbc6' class="ref-empty ref-filled" selected="selected">Red</option></select> [/html] So i have described a nice way to add extra code to my document ready function without needing a special layout-page. And experienced for the umpteenth time how great jQuery is.

More ...
Uncategorized javascript jquery
jquery validation only one field in a group required

I am using the jQuery validate plugin which is awesome for straightforward form validation. What i especially like is that it offers the user a better user experience, because there is no need for the round-trip to the server. I still need to do the validation on the server-side (rails) as well. I guess there should be a way to extract the validations from the model into the view transparently, but for now i just add a class "required" myself. Now i did bump into a seemingly difficult problem, when the user wanted my to validate to having either one of both fields filled in. Luckily google came up with a beautiful answer quick enough! I needed to adapt it somewhat, because my form-styling places each label-field combination inside a div, so i search for the second surrounding 'div' (containing the group of fields for which only one field is required). [javascript] jQuery.validator.addMethod('required_group', function(val, el) { var $module = $j(el).parent('div').parent('div'); return $module.find('.required_group:filled').length; }, 'Please fill out at least one of these fields'); [/javascript] How i love the jQuery and Rails community. Awesome!

More ...
Uncategorized
javascript open popups and firefox

In my Rails application, at a certain stage, it was necessary that my user performs an operation in another web-application (a GIS application) on the same database. I am using the following piece of code to make sure that i open a url in a new window, and that it should get the focus (jump to the front). [javascript] <% javascript_tag do -%> function newWindow(newContent, windowName) { var new_window; var new_window = window.open(newContent, windowName); if (window.focus) new_window.focus(); } window.onload=function() { newWindow('<%= link_to_location @mention, true %>', '<%= @gisapp_window_name %>'); setTimeout(jump_to_select_tab_url, 2000); } <% end -%> [/javascript] All is well when the window is first opened, but if the window was already opened, still it fails. And of course i do all testing against firefox 3.5, although my user wants to use IE instead. So i try in IE and it works. Huh? So it has something to do with Firefox 3.5. And behold, as explained here, firefox is so smart it will block all javascript manipulation of windows, which is of course just what we need in this case. So inside firefox, i need to go to Options->Content->Javascript and make sure that i can run javascript that will manipulate opening and closing of windows. Done!

More ...
Uncategorized
insert javascript using link_to_function

I am using Rails 2.3.4 at the moment, and as is well known, rails uses Prototype as default javascript library. For most purposes this suits me well. But what i really like about jQuery is the wealth of plugins readily available. My solution was not something like jRails, but i use them side by side. This might not be the best solution :) First of, you have to include the correct javascript files. Then, at the top of my application.rhtml, i write this: [javascript] var $j = jQuery.noConflict() $j(document).ready(function() { /* insert some jquery magic here */ ... }); [/javascript] This ensures that i can use the jQuery library nicely alongside the Prototype one. Just replace $ by $j for all jQuery calls. For most jQuery things this is more than enough. But then I needed form validation, and needed to be able to call some jQuery from inside a link_to_function block. It took me a while to find, but actually (isn't it always) it is dead-simple. [ruby] def add_document_link(divname, parentdoc ) link_to_function get_icon('adddocument'), { :title => t('adddocument')} do |page| new_doc = Document.new new_doc.doc_ident_p = parentdoc.doc_ident page.select('.add-items-link').each { |b| b.hide } page.insert_html :bottom, divname, :partial => 'documents/add_document', :object => new_doc, :locals => { :divname => "add-items-link"} page << "var $j = jQuery.noConflict(); $j("form").validate();" end end [/ruby] Easy as pie :) I love rails :)

More ...