Montag, 13. Juli 2009
Running one of my test classes using multiparameter attributes (date column in the database) I got a lot of warnings saying:
vendor/rails/activerecord/lib/active_record/attribute_methods.rb:142: warning: Object#type is deprecated; use Object#class

Here's the code where type is called:
def create_time_zone_conversion_attribute?(name, column)
  time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(name.to_sym) && [:datetime, :timestamp].include?(column.type)
end

Normally, type should be called on a Column object, which provides a type (see vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb), but in my case, column was nil and the method type was called for Object.

I don't fully understand what's going on (why is column nil?), but as a quickfix to silence the annoying warning you can change the method in attribute_methods.rb to handle this as a special case:
def create_time_zone_conversion_attribute?(name, column)
  if column.nil?
    true
  else
    time_zone_aware_attributes && !skip_time_zone_conversion_for_attributes.include?(name.to_sym) && [:datetime, :timestamp].include?(column.type)
  end
end




Today, I had the problem that rcov on one machine produced outputs like 50% or 48% for some files while on some other machine the coverage was 100% or at least >95%. When looking at the rcov output, I noticed that the contents of the files that made problems were duplicated, first the correct results and then again the whole class, this time with every single line marked as being not covered.

The affected files were sessions_controller.rb, user_controller.rb and user_mailer.rb. This made me think of where those files came originally from: The restful authentication plugin. I had a look on the test files for these and their beginning looked like this (test/functional/sessions_controller_test.rb here):
require 'test_helper'
require 'sessions_controller'

# Re-raise errors caught by the controller.
class SessionsController; def rescue_action(e) raise e end; end

Why is sessions_controller included/required there? I don't know why the restful authentication plugin put those instructions there, but you can just remove them from the affected files and you will be fine.

I suspect that this issue only comes up with older rcov versions, because my development machine with current rcov does not have a problem with the require instructions.




Samstag, 27. Juni 2009
I had an issue with the quickfix functionality in Vim and the Rails Plugin.

In test failures, a path is given to the test file where there was the test failure. This path starts sometimes in my Installation (Rails 2.3.2, Ruby 1.8.7) with a '/' (only happens paths to test cases, I think). I don't now why, it doesn't really make sense and the vim-rails plugin doesn't like this, too and try's to open up a file with an absolute path instead of one relative to the rails project path.

Today I was so annoyed by this (after each 'Rake test' call a new tab opens up with an empty file) that I went for fixing it. The fix is a little change to /usr/share/vim/autoload/rails.vim.

Somewhere in there, there are the following lines: (line 941+ here)
" stack backtrace is in brackets. if multiple lines, it starts on a new line.
let s:efm=s:efm
\.'%Ctest_%.%#(%.%#):%#,'
\.'%C%.%#\ [/\\?%f:%l]:,'
\.'%C\ \ \ \ [/\\?%f:%l:%.%#,'
\.'%C\ \ \ \ %f:%l:%.%#,'
\.'%C\ \ \ \ \ %f:%l:%.%#]:,'
\.'%C\ \ \ \ \ %f:%l:%.%#,'

You need to change Lines 4 and 5 of that section to:
\.'%C%.%#\ [/\\?%f:%l]:,'
\.'%C\ \ \ \ [/\\?%f:%l:%.%#,'

This will test for an optional leading slash and ignore it so that vim opens up a relative path from now on. Perhaps other changes are needed, I'll update this article if I encounter sth.

UPDATE
I noticed there are more problems with the rails plugin here. Most of the time, the error message isn't found. So I spent a few hours figuring out these odd vim error formats. It's now working for the failures I had till now.
How to apply my changes:

Look for the lines containing '" Current directory' and 'function! s:makewithruby(arg,bang,...)' and replace the area in between with the following code:

" Current directory
let s:efm='%D(in\ /\\?%f),'
" Failure and Error headers, start a multiline message
let s:efm=s:efm
\.'%A\ %\\+%\\d%\\+)\ Failure:,'
\.'%A\ %\\+%\\d%\\+)\ Error:,'
\.'%+A'."'".'%.%#'."'".'\ FAILED,'
" Syntax errors in the test itself
let s:efm=s:efm
\.'%.%#.rb:%\\d%\\+:in\ `load%.%#'."'".':\ %f:%l:\ syntax\ error\,\ %m,'
\.'%.%#.rb:%\\d%\\+:in\ `load%.%#'."'".':\ %f:%l:\ %m,'
" And required files
let s:efm=s:efm
\.'%.%#:in\ `%.%#require'."'".':\ %f:%l:\ syntax\ error\,\ %m,'
\.'%.%#:in\ `%.%#require'."'".':\ %f:%l:\ %m,'
" Syntax Errors
let s:efm=s:efm
\.'%A%.%#.rb:\\d%\\+:in\ `%.%#'."'".':\ %m\ (%.%#Error),'
" Exclusions
let s:efm=s:efm
\.'%C%.%#(eval)%.%#,'
\.'%C-e:%.%#,'
\.'%C%.%#/lib/gems/%\\d.%\\d/gems/%.%#,'
\.'%C%.%#/lib/ruby/%\\d.%\\d/%.%#,'
\.'%C%.%#/vendor/rails/%.%#,'
" Specific to template errors
let s:efm=s:efm
\.'%Ctest_%.%#(%.%#Test):%\\?,'
\.'%C%.%#Errors\\?:\ %#%m,'
\.'%C\ %\\+On\ line\ #%l\ of\ %f,'
\.'%C%\\(You\ might\ have\ expected\ an\ instance\ of%.%#%\\)%\\@=%m,'
\.'%C%\\(The\ error\ occurred\ while\ evaluating\ %.%#%\\)%\\@=%m,'
\.'%C%\\(%.%#didn'."'".'t\ change\ by%\\)%\\@=%m,'
\.'%C%\\(%.%#expected\ but\ was%\\)%\\@=%m,'
\.'%Z%\\(<%\\d%#>.\\)%\\@=%m,'
" stack backtrace is in brackets. if multiple lines, it starts on a new line.
let s:efm=s:efm
\.'%C\ %\\{5}/\\?%f:%l:in `test_%.%#'."'".']:,'
\.'%Z\ %\\{4}/\\?%f:%l:in `%.%#'."'".','
\.'%Ctest_%.%#(%.%#)\ [/\\?%f:%l]:,'
\.'%C\ %#[/\\?%f:%l:in `test_%.%#'."'".','
" Catch all
let s:efm=s:efm
\.'%Z\ %\\{4}/\\?%f:%l:%.%#,'
\.'%Z%.%#from\ %f:%l,'
\.'%Z%.%#from\ %f:%l:%.%#,'
let s:efm=s:efm
\.'%Z%m,'
" Another catch for syntax errors in tests
let s:efm=s:efm
\.'%A%f:%l:\ %m\ for\ %.%#(%.%#Error),'
\.'%Z\ %#from %.%#.rb:%\\d%\\+:in\ `load%.%#'."'".','
" Exclusions
let s:efm=s:efm
\.'%-G%.%#/lib/gems/%\\d.%\\d/gems/%.%#,'
\.'%-G%.%#/lib/ruby/%\\d.%\\d/%.%#,'
\.'%-G%.%#/vendor/rails/%.%#,'
\.'%-G%.%#%\\d%\\d:%\\d%\\d:%\\d%\\d%.%#,'
" Final catch all for one line errors
let s:efm=s:efm
\.'%f:%l:\ syntax error\,\ %m,'
\.'%-G%\\s%#from\ %.%#,'
" Drop everything else
let s:efm=s:efm
\.'%-G%.%#'

let s:efm_backtrace='%D(in\ /\\?%f),'
\.'%\\s%#from\ /\\?%f:%l:%m,'
\.'%\\s#{RAILS_ROOT}/%f:%l:\ %#%m,'
\.'%\\s%#[/\\?%f:%l:\ %#%m,'
\.'%\\s%#/\\?%f:%l:\ %#%m'

function! s:makewithruby(arg,bang,...)

Wohooo! This is paradise for a regex lover like me =)




Montag, 15. Juni 2009
Here's a tip on how to deal with with partial dates like hours with ruby on rails. start_hour in this example is a virtual attribute of the search model. To make the select_hour helper work properly, you need to add the the default value to use (@search.start_hour) as well as a prefix and field_name (this will tell rails how to name the field, 'search[start_hour]' in this case).

So, I assume you got some form declaration like this:
<% form_for(@search) do |f| %>

Now to add a hour select box inside that form, use code similar to this:
<%= select_hour @search.start_hour, :prefix => 'search', :field_name => 'start_hour' %>

This will also work with select_minute / select_second / select_day / select_month / select_year.