Looks like i picked the right time to move to South America. October 15th and 16th in São Paulo!
migrating from mongrel to passenger 1
We migrated our main production server from mongrel to passenger today. Here are the things we learned from the process:
- Don’t forget to set the apache APXS2 variable – the error won’t show up until you try to start apache after thinking that you successfully installed passenger. You will receive an error like this:
httpd: Syntax error on line 54 of /usr/local/apache2/conf/httpd.conf: API module structure 'passenger_module' in file /usr/local/passenger/passenger-2.0.1/ext/apache2/mod_passenger.so is garbled - expected signature 41503232 but saw 41503230 -perhaps this is not an Apache module DSO, or was compiled for a different Apache version?
- You can remove all of the rewrite rules from the apache conf file, but keep this part:
Options FollowSymLinks AllowOverride None Order allow,deny Allow from all
- You’ll need to keep any apache rewrite rules related to displaying a ‘maintenance’ file.
What follows is the old mongrel apache configuration file, and the new one:
NameVirtualHost 10.x.x.x:80ServerName myserver DocumentRoot /var/www/apps/myapp/current/public Options FollowSymLinks AllowOverride None Order allow,deny Allow from all # Configure mongrel_clusterBalancerMember http://127.0.0.1:8300 BalancerMember http://127.0.0.1:8301 BalancerMember http://127.0.0.1:8302 BalancerMember http://127.0.0.1:8303 BalancerMember http://127.0.0.1:8304 BalancerMember http://127.0.0.1:8305 RewriteEngine On # Prevent access to .svn directories # RewriteRule ^(.*/)?\.svn/ - [F,L] # ErrorDocument 403 "Access Forbidden" # Check for maintenance file and redirect all requests RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ /system/maintenance.html [L] # Rewrite index to check for static RewriteRule ^/$ /index.html [QSA] # Rewrite to check for Rails cached page RewriteRule ^([^.]+)$ $1.html [QSA] # Redirect all non-static requests to cluster RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://myapp_cluster%{REQUEST_URI} [P,QSA,L] # Deflate AddOutputFilterByType DEFLATE text/html text/plain text/xml BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html ErrorLog /var/log/apache2/myapp.com-error_log CustomLog /var/log/apache2/myapp.com-access_log combined
To this with passenger apache configuration file:
NameVirtualHost 10.x.x.x:80ServerName myapp DocumentRoot /var/www/apps/myapp/current/public Options FollowSymLinks AllowOverride None Order allow,deny Allow from all # Check for maintenance file and redirect all requests RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ /system/maintenance.html [L] ErrorLog /var/log/apache2/myapp.com-error_log CustomLog /var/log/apache2/myapp.com-access_log combined
acts_as_setting – ruby dynamic setting class 2
In any large software project there is a concept of setting or configuration. In .NET, there is the System.Configuration class. Rails doesn’t have anything like this, but Most of the time, I have some need to roll my own class for this I recently have been using a setting class I created that loads settings from the database and stores them as constants on a class called ‘Setting’.
My goals were:
1. No repeated hits to the database just to access a property, except occasional reloads for an update to a setting in the database.
2. Runtime errors if a setting doesn’t exist. No returning ‘nil’ if a setting is mistyped.
3. Ability to update settings across multiple machines, in a reasonable amount of time. In this case, five minutes is reasonable.
This code is in lib/setting.rb (i’m still not sure why but i couldn’t get this to work when inside the main setting.rb file in the model directory):
class Setting
def self.load_settings
Setting.find(:all).each do |s|
logger.debug "Loaded Setting: #{s.name}: #{s.value}"
Setting.instance_eval do
isnum = ((s.value.to_i.to_s == s.value.to_s) rescue false)
eval "def #{s.name}\\n#{s.value}\\nend" if isnum
eval "def #{s.name}\\n\"#{s.value}\"\\nend" unless isnum
end
end
end
self.load_settings
end
Here’s the super simple migration in the pre-rails-2.0 migration format:
class CreateSettings < ActiveRecord::Migration
def self.up
create_table "settings", :force => true do |t|
t.column "name", :string, :limit => 50, :default => "", :null => false
t.column "value", :string, :default => "", :null => false
end
add_index "settings", ["name"], :name => "settings_name_index"
end
def self.down
drop_table :settings
end
end
Here’s the ‘main’ setting class:
class Setting < ActiveRecord::Base serialize :value end
In environment.rb, in order to reload the settings every five minutes:
require 'thread'
Thread.new { loop {sleep(300); Setting.load_settings rescue nil } }
php endswith
i do work in php as well, grudgingly, and i found myself missing ends_with? today in ruby. seeing this activesupport port for php post makes me miss ruby even more. as most of the commenters point out, it’s lipstick on a pig.
Dynamic Instantiation of Property Accessors 2
Jay Fields describes a scenario for using dynamic method definition instead of method missing. Today i think i found a reason to use both method missing and dynamic method definition, for both speed and safety.
I have an ActiveRecord class that uses a serialized Hash as one of its parameters. There are about a dozen keys in that hash that are most frequently used, however there may be others. I want those most frequently used keys to be exposed as methods on the containing object like this:
class Query < ActiveRecord::Base
DYNAMIC_METHODS = [:my_key1, :my_key2, :my_other_key_exposed_as_method ]
serialize :params
def method_missing(methodname, *args)
if self.class.methods.include?(methodname)
super
elsif DYNAMIC_METHODS.include?(methodname.to_sym)
_build_dynamic_fields
self.send(methodname, *args)
else
super
end
end
# dynamically alias these methods to retrieve their results from the
# params object
def initialize(initparams=nil)
super
end
# called if a caller ever requests one of the dynamic methods above
def _build_dynamic_fields()
DYNAMIC_METHODS.each() do |m|
(class << Query;Query; end).class_eval do
define_method m do |*args|
return nil if params.nil?
self.send(’params’).send(’[]’, m.to_sym) rescue nil
end
end
end
end
Samsung SyncMaster 245BW
Highly recommended monitor – just bought yesterday for $419.00, and the picture quality and ability to run 1920×1200 is just incredible. Also, this post on FutileShop shows how to get it to rotate into portrait orientation.
no mod_ruby is damaging Ruby’s viability 1
Peter Cooper’s post on the lack of a ‘mod_ruby’ is dead on. I am working on a site with millions of hits per month and i couldn’t even begin to credibly suggest that we do any ‘production’ work in ruby.
It is not (just) that Rails isn’t reliable enough. Deployment isn’t brain dead enough. You have to run mongrel, tune the number of instances, then run monit and have it restarting mongrel instances. Then have something or someone watching monit when it fails to restart mongrel every month or so.
Deploying rails requires a significant amount of brainpower from an above average engineer to design the deployment. PHP requires only a rudimentary understanding of FTP.
Math.max or why is there no integer maximum function in ruby 3
There is no Math.max function. Instead, use an array:
>> [2,3,4].max
=> 4
I would argue there should be, because it is not intuitively obvious that this type of integer comparison would live off of an array. One argument could be that the array approach allows for non-integer types to be compared, and that the increase in flexibility has an increase in obscurity as its side-effect…
>> ["chicken","fox"].max
=> "fox"
parsing excel files in ruby – the parseexcel gem 22
Highly recommended gem does exactly what it says. Here’s the code to turn an entire worksheet from an excel doc into a multi-dimensional array:
wb = Spreadsheet::ParseExcel.parse(filename)
rows = wb.worksheet(worksheet).map() { |r| r }.compact
grid = rows.map() { |r| r.map() { |c| c.to_s('latin1')}.compact rescue nil }
Just ‘gem install parseexcel’ (though i installed from source before i realized it was a pre-packaged gem).
Starting a thread in environment.rb – don’t do it!
I have a project that requires a standalone server for background processing. I could have used backgroundrb but it seems like overkill, and it has this comment on the documentation page, which is a year old, and which tells me the gem is not in active development.
WARNING: start/stop/restart is broken in 0.2.1, please use the server script directly until we have figured out the issue.
So, in development mode, rather than start a standalone server, I put this code in development.rb:
Thread.new do
Server.start()
end
For reasons i’ve yet to determine, because the thread is started in the initialization code, the file include logic doesn’t work properly. Now, this could be a problem with DRb, which is how the server talks with the rest of the app, or it could be a problem with the file include logic in rails. Either way, the first attempt to contact the server works, and on the second attempt to contact the server, we get this error:
A copy of Server has been removed from the module tree but is still active!
For now, I’m just running the server using script/runner in a separate process, and it works fine.