posts
After an hour of head banging, well….banging our head trying to test that raising any error inside an ActiveRecord::Base#transaction block. It would appear that you can’t test a transaction in a test straight out the box. ActiveSupport::TestCase turns on transactional fixtures by default, in order that fixtures don’t get reloaded in every time a test is run. This makes sense and for this particular project there are silly amount of fixtures so this speeds up tests no end. However, this also means you can’t test a transaction inside a transaction because ActiveRecord doesn’t support nested transactions.
However, all is not lost you can turn off transactional fixtures on a test class by using the following.
self.use_transactional_fixtures = false
It’s a trade off on speed, so if you have a lot of tests it might be a better idea to move tests that rely on transactions working as they should into separate test classes.
Solution was found here:
http://railspikes.com/2007/3/28/testing-transactions
Quite an interesting problem. How to render different views depending on the hostname of your application. Well actually only certain views have to be overridden. The ideal behaviour would to be to set a search path based on the hostname of the application which then falls back to the default if no views exists.
Initially I looked at how I could force searching different view path and using that file if it already exists else use the default by overriding existing ActionView methods.
http://rpheath.com/posts/122-needing-to-extend-rails-view-path
However, this isn’t necessary as it appears Rails supports a method of adding another search path for views by pushing the custom view dir onto the view_paths array. This could be placed in config/initializers/action_controller_extender.rb and loaded as the application is started.
ActionController::Base.view_paths.unshift(File.join(RAILS_ROOT, 'app', 'views', 'custom_views'))
In order to fix this based on the hostname, its actually more convenient to move this into a before filter and on every request we can check the host header.
class ApplicationController < ActionController::Base
before_filter :custom_view_path
private
def custom_view_path
if ['www.zombification.net'].include?(request.host)
self.prepend_view_path(File.join(RAILS_ROOT, 'app', 'views', 'zombification'))
end
end
end
Just got around to installing Passenger 2.0.1 and I am just horrified at how easy it is, surely there should be some kind of rule about this. Its the little complexities and awkwardness that keep me in work.
gem install passenger; passenger-install-apache2-module
Running a basic install of LovdByLess at Zombie Crawl as a test for now. It seems rather slow to initialise, about 5 to 10 seconds on the first request. But then its relatively speedy.
I’m interested in following the progress on this one as I’ve heard about its potential application for shared hosting environments, although I’m not immediately convinced since it took a few reloads of apache to get all of the models loaded without `undefined constant` errors running a single site. So I can forsee the support for this with multiple sites on a single host being problematic.
Just a quick one if you want to utilise HAML inside your rails app. Personally I find the HAML syntax far more readable than Erb
gem install haml; cd path/to/app/; haml --rails ./
I used this utility a few times many years ago and when I’ve come to use it again it does appear to be anywhere I can find it. I’ve since switched from Fedora to Ubuntu so perhaps that’s why. Its a nice little command line tool that strips out all the windows characters
apt-get install sysutils
.....
Setting up tofrodos (1.7.6-2) ...
.....
Not immediately obvious but this includes dos2unix.
We’ve been experiencing a problem sending mails between application servers, one server’s mail server has been unavailalbe for a number of days and as such all new mails to that box bounce. Even now that the server is available the same behaviour is being experienced. We need to clear the exim retry database for this particular server. The first problem is actually seeing the retry rules exim_dumpdb is used here.
root@server1:/# exim_dumpdb /var/spool/exim4 retry
T:www.zombification.net:83.244.152.145 111 65 Connection refused
01-Aug-2008 12:26:13 06-Aug-2008 09:22:37 06-Aug-2008 15:22:37 *
T:backup.zombification.net:83.244.152.146 113 77 No route to host
31-Jul-2008 17:20:22 05-Aug-2008 17:43:21 05-Aug-2008 23:43:21 *
Here we can see that retry times need to be cleared. Here I’ve used exim_tidydb to clear any rules that have been in place for more than one hour.
root@server1:/# exim_tidydb -t 1h /var/spool/exim4 retry
Tidying Exim hints database /var/spool/exim4/db/retry
deleted T:backup.zombification.net:83.244.152.146 (too old)
deleted T:www.zombification.net:83.244.152.145 (too old)
RESTful rails apps don’t necessarily make your urls that friendly if you end up with
http://www.zombification.net/posts/1
An id isn’t very descriptive of the content of the post. The quick fix for was is to add the method Post#to_param
class Post < ActiveRecord::Base
validates_presence_of :title
validates_presence_of :content
def to_param
return "#{self.id}-#{self.slug}"
end
def slug
return self.title.clone.downcase.gsub(' ','-')
end
end
to_param is defined in ActionController::Routing and is used when generating urls with link_to, etc, but only when you specify the object and not the id itself.
link_to :controller => 'posts', :action => :show, id => @post
If you use name routes this is all taken care of for you. At this point all the links for @post will be the more meaningful URL
http://www.zombification.net/posts/1-nested-transactions
This is not the whole story however, this works with minimal effort because when we get our post object back Post#find(params[:id]), params[:id] will be ‘1-nested-transactions’. However, ActiveRecord::Base#find calls #to_i, on the single argument. So as long as the id of the post in params[:id] appears first the result from ActiveRecord will be the same.
rob@rob-laptop:~/src/zombification$ ./script/console
Loading development environment (Rails 2.1.0)
>> Post.find('1-random-meaningless-string')
=> #<Post id: 1, title: "nested transactions", content: "After an hour of head banging, well....banging our ...", published_at: nil, created_at: "2008-07-29 16:40:35", updated_at: "2008-08-16 07:51:57">
Hey presto slightly more SEO urls. Ok you still have the id floating about which is a little ugly but its certainly better.
If you want to share your git repos using the git protocol you can use the following
git-daemon --syslog --base-path=/home/rob/src --export-all --detach
This starts the git daemon in the background
rob@rob-laptop:~/src/hosting_admin$ netstat -ltanup | grep git
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 0.0.0.0:9418 0.0.0.0:* LISTEN 19583/git-daemon
tcp6 0 0 :::9418 :::* LISTEN 19583/git-daemo
It should then be a question of pulling from the remote location like so.
git pull git://192.168.1.120/repository
This doesn’t provide any security out of the box, so I wouldn’t recommend using this out in the wild but on a private network amongst your team this is an easy way to share your repo.
Just re-installing a new laptop now I’ve left my current job, handing back your laptop with a setup you’ve had for two and a half years can be painful. So here’s a rundown and reminder of what I need.
root@bloodandguts:# apt-get install ruby1.8 ruby1.8-dev irb vim-ruby vim-rails rubygems \
libc6-dev make gcc sqlite3 libsqlite3-dev git-core libmagick9-dev rmagick
Update gem to latest version as the one supplied with Ubuntu is out of date.
root@bloodandguts:# gem update --system
This installs gem to /usr/bin/gem1.8 without removing the other reason, which is quite annoying.
mv /usr/bin/gem /usr/bin/gem.old
ln -c /usr/bin/gem /usr/bin/gem1.8
Add the GitHub gem repo for things such as will_paginate, etc
gem sources -a http://gems.github.com
now you can install all the gems you need for everyday use, or at least that I use.
gem install rails merb-core merb-more hobo mongrel mechanize rubigen sqlite3-ruby
My previous company utilised a lot of queuing systems, all using entries in a database set with a particular status and a cronjob running at regular intervals looking for these entries in a order to run an operation. This wasn’t particularly efficient and queues had a habit of building up to sometimes unmanagable levels. The queuing was necessary since many operations were called on remote services which would not always repond immediately and so could not necessarily fit in with a quick HTTP request / response cycle.
I have heard good things about ActiveMQ and this may well have been the solution we were looking for.
sudo gem install daemons stomp
The binary for ActiveMQ is available from activemq.apache.org, the most recent stable version at the moment is 5.1.0.
wget http://mirror.public-internet.co.uk/ftp/apache/activemq/apache-activemq/5.1.0/apache-activemq-5.1.0-bin.tar.gz
tar -zxvf apache-activemq-5.1.0-bin.tar.gz
mv apache-activemq-5.1.0-bin /usr/local
ln -s apache-activemq-5.1.0-bin activemq
And last but not least the ActiveMessaging plugin.
rl\@bloodandguts:src/projects/activemessaging\$ ./script/plugin install http://activemessaging.googlecode.com/svn/trunk/plugins/activemessaging
Now for the Hello World example.
rl\@bloodandguts:/src/projects/activemessaging\$ ./script/generate processor HelloWorld
create app/processors/
exists test/functional/
create app/processors/hello_world_processor.rb
create test/functional/hello_world_processor_test.rb
create config/messaging.rb
create config/broker.yml
create app/processors/application.rb
create script/poller
Now create a controller so we can test interacting with the queue.
rl\@bloodandguts:~/src/projects/activemessaging\$ ./script/generate controller SayHelloWorld index
exists app/controllers/
exists app/helpers/
create app/views/say_hello_world
exists test/functional/
create app/controllers/say_hello_world_controller.rb
create test/functional/say_hello_world_controller_test.rb
create app/helpers/say_hello_world_helper.rb
create app/views/say_hello_world/index.html.erb
Grab the source from the PlayLouder git repo
git clone git://dev.playlouder.com/brix.git
brix/bin/brix-gen foo --symlink-brix
It depends on the following gems
gem install activesupport -v2.0.2
gem install haml rack json mailfactory erubis
gem install extlib data_objects do_sqlite3 do_mysql dm-core
Rather irritating problem this one, it seems that equivalent command line option to enable ‘local-file’ doesn’t work out of the box with the Rails MySQL bindings.
rl@bloodandguts:~/src/projects/myproject$ RAILS_ENV=test rake db:migrate
(in /home/rl/src/projects/myproject)
== 001 LoadData: migrating ============================
rake aborted!
Mysql::Error: #42000The used command is not allowed with this MySQL version: LOAD DATA LOCAL INFILE (...)
In order to fix this you can install the ‘mysql’ gem like so
sudo apt-get install libmysqlclient15-dev
sudo gem install mysql -- --with-mysql-config
rl@bloodandguts:~/src/projects/myproject$ sudo gem install mysql -- --with-mysql-config
Building native extensions. This could take a while...
Successfully installed mysql-2.7
1 gem installed
rl@bloodandguts:~/src/projects/charanga/bundles$ RAILS_ENV=test rake db:migrate
(in /home/rl/src/projects/charanga/bundles)
== 001 LoadData: migrating ============================
== 001 LoadData: migrated (4.2152s) ===================
I’m not a big fan of perl but this quick little snippet is quite handy when you want to do a quick search and replace across multiple files.
perl -pi -e 's/slug/tiny_url/g' app/views/tiny_urls/*
Rather annoying little one that I came across trying to deploy my current client’s codebase.
* executing `deploy:mongrel:restart'
/usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/namespaces.rb:188:in `method_missing': undefined local variable or method `mongrel_conf' for #<Capistrano::Configuration::Namespaces::Namespace:0x7f654a076e10> (NameError)
from ./config/deploy.rb:121:in `load'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/execution.rb:128:in `instance_eval'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/execution.rb:128:in `invoke_task_directly_without_callbacks'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/callbacks.rb:27:in `invoke_task_directly'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/execution.rb:81:in `execute_task'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/namespaces.rb:186:in `send'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/namespaces.rb:186:in `method_missing'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/configuration/namespaces.rb:186:in `send'
... 21 levels...
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/lib/capistrano/cli/execute.rb:14:in `execute'
from /usr/lib/ruby/gems/1.8/gems/capistrano-2.5.0/bin/cap:4
from /usr/bin/cap:19:in `load'
from /usr/bin/cap:19
It looks like ‘mongrel_conf’ is a variable that is set by the ‘deprec’ capistrano recipie gem.
http://www.deprec.org/
Just found a 6.3G production.log and therefore have started looking at log rotation. Ok its not as bad as a MySQL query log of 60G that I came across once, but still its pretty huge. I’ve used cronolog before for shared hosting. Instead of logging to a file you use a pipe to ‘cronolog’ giving it the filename you would like to then be written the format of which can then be specified. Here I use the current date, cronolog takes care of ensuring it gets written to the correct file name and effectively rotates the logs for you.
This takes all the hassle out of reloading the application to close the log files and re-open them, and was particularly useful when dealing with servers writing to thousands of different log files at any one time as restarting the webserver could take a long time to deal with that many log files.
You can override the default logger in environment.rb like do.
# Use cronolog for log rotation
cronolog_io = IO.popen("/usr/bin/cronolog #{RAILS_ROOT}/log/%Y/%m/%d/#{RAILS_ENV}.log", 'w')
config.logger = Logger.new(cronolog_io)
The Rails implementation stolen blatantly from and slightly modified
http://blog.playlouder.com/2007/07/23/log-rotation-with-rails-and-cronolog/
When attempting to install the Flex plugin in NetBeans I get the following error.
Missing required modules for Plugin FlexBean:
Ant [module org.apache.tools.ant.module/3 > 3.29.0.2] Swing Layout Extensions integration [module org.jdesktop.layout/1 > 1.5] Java Support APIs [module org.netbeans.api.java/1 > 1.16]
......
I couldn’t work out initially how to then install the ‘missing modules’. In order to fix this you must install the standard plugin ‘Missing Modules Resolver’. Apparently…
I kept getting the same errors from memcache (0.11) inside my Rails app.
Max prefix_key size is 11
I had to revert to version 0.10 of the gem to avoid getting this error again.
If you get a problem updating rubygems, like I did when I tried to upgrade to 1.3.0 today
rl@bloodandguts:/usr/src$ sudo gem install merb
ERROR: Error installing merb:
merb-core requires RubyGems version >= 1.3.0
rl@bloodandguts:/usr/src$ gem update --system
Updating RubyGems
Nothing to update
rl@bloodandguts:/usr/src$ gem -v
1.2.0
rl@bloodandguts:/usr/src$ sudo gem install rubygems-update
Successfully installed rubygems-update-1.3.1
1 gem installed
rl@bloodandguts:/usr/src$ gem -v
1.2.0
You simply need to run the following script
rl@bloodandguts:/usr/src$ sudo update-rubygems
And you’re cooking.