November 20, 2009
In this screencast Ryan Bates explains how to execute a rake task in background on run time. This will make controller return the response to the user fast. In the meantime email will be sent through the background job.
In short this is the solution he proposes.
def call_rake
system "rake #{task} &"
end
It is a short and sweet solution when you do not want to roll out other background job processing tools. It works pretty well. However I discovered one issue with the solution.
While developing validation functionality in admin_data I needed to demand a background job on run time and I used the solution proposed above.
Let’s say that I start a rake task on background which lasts for 10 minutes. In the next 10 minutes if I kill my script/server ( I am in development mode) and if I try to start my server, I was getting following message.
Address already in use - bind(2) (Errno::EADDRINUSE)
It seems that when the rake job is pushed to background, it inherits all the properties of the parent process including the port number of the server. It means that as long as the child process is alive, the parent process’s port number is taken.
This solution fixes the problem.
command = "rake #{task} #{args.join(' ')}"
p1 = Process.fork { system(command) }
Process.detach(p1)
This was my first introduction to the murky world of ruby fork and process. I read a few good blogs on this topic and will be posting more about the same topic soon.
November 19, 2009
I did not know about hash method in ruby object and I paid a heavy price. While developing admin_data plugin I proposed to pass certain values in configuration like this.
:column_settings => { Car => { :data => lambda{|model| model.send(:data).inspect}}}
With the above settings the code will work fine the very first time in development mode. However if you refresh the page then code was failing. It turns out that when I ask ruby to use a class as a hash key then ruby calls hash method of the class and that output is stored as a key.
Since rails loads new instances of classes in development every single time, the hash value of the class differs each time. Check this out.
>> User.hash
=> 18513330
>> reload!
Reloading...
=> true
>> User.hash
=> 18403950
The fix would be to use symbol (like :user) or string (like ‘User’) as key of a hash.
November 19, 2009
Here is code.
def hello
yield
ensure
puts 'in ensure block'
true
end
puts hello { puts 'world'; false }
I thought if I call hello method then the final returned value will be true. The common ruby convention is that last value gets returned. In this case the very last value is true so I was expecting true to be the returned value.
If I execute above code this will be the output.
world
in ensure block
false
Question is why the final output is false and not true ?
The implicitly returned value from the ensure block is discarded and hence in the above case the final returned value is false. I said implicitly returned values are discarded.
However if ensure value explicitly uses return statement to return something then ensure behaves quite differently and Less Hill has a nice blog on this topic .
Also note than if you are not explicitly returning something and if yield block raises an exception then ensure will be called. However after the ensure block finishes then that exception will be raised. It means that ensure block will not eatup the exeption.
Once again if you are using explicit return statement in ensure block then exceptions are eaten up as mentioned by Less Hill.
What could be a good candidate for ensure. It depends on business problem but here is a one usage .
def pretend_zone_is(zone)
original_zone = Time.zone
begin
Time.zone = zone
yield
ensure
Time.zone = original_zone
end
end
November 11, 2009
While writing functional tests, I use assert_tag a lot. Many times the assertion fails and debugging with ‘response text’ dump on terminal is not easy. It would be much easier to debug if the response text is opened in a browser. This is how that can be done.
In your test/test_helper.rb add a new method called show_response.
class Test::Unit::TestCase
def show_response
Dir.mkdir(File.join(RAILS_ROOT, 'tmp')) unless File.directory?(File.join(RAILS_ROOT,'tmp'))
response_html = File.join(RAILS_ROOT, 'tmp', 'response.html')
File.open(response_html,'w') { |f| f.write(@response.body) }
system 'open ' + File.expand_path(response_html) rescue nil
end
end
This is how I use this method while debugging.
context 'get show for comment which belongs to another class' do
setup do
@comment = Factory(:comment, :article => @article)
get :show, {:id => @comment.id, :klass => @comment.class.name.underscore }
show_response
end
should_respond_with :success
should 'have belongs_to message' do
assert_tag( :tag => 'p',
:attributes => {:class => 'belongs_to'},
:descendant => {:tag => 'a', :child => /Article/})
end
end
If you are using mac then running this test will open a new web page with full response text. Now I can easily see why my assertion might be failing. show_response also works with ajax request.
November 11, 2009
I want to create following markup dynamically using jQuery.
<div>
<p>
This is p
</p>
</div>
Following jQuery code will do the work.
$(document).ready(function() {
var div = $('<div></div>');
var p = $('<p></p>').text('this is p')
.appendTo(div);
$('body').append(div);
});
A better way to accomplish the same is presented below.
$('<div></div>')
.append('<p></p>')
.find('p')
.text('this is p')
.end()
.appendTo('body');
Using .end() you can go back one level. And you can use .end() any number of times to get out of a deeply nested tag.
$('<div></div>')
.append('<p></p>')
.find('p')
.append('<span></span>')
.find('span')
.text('this is span')
.end()
.end()
.appendTo('body');