I’ve just released acts_as_redis_counter plugin for Rails.
Description:
The acts_as_redis_counter plugin implements high performance counters using write-back strategy with Redis key-value database.
linux + ruby on rails = love
October 16th, 2009 — ActsAsRedisCounter, Rails
I’ve just released acts_as_redis_counter plugin for Rails.
Description:
The acts_as_redis_counter plugin implements high performance counters using write-back strategy with Redis key-value database.
October 15th, 2009 — Linux, Rails
Keeping a separate file for each virtual host in /etc/httpd/vhosts.d it’s clean and cool, but when you have many virtual hosts with same settings it’s a pain to keep them updated. We need a template system for Apache configurations and mod_macro module it’s a handy tool for this job.
Download module version suited for your Apache from:
http://www.cri.ensmp.fr/~coelho/mod_macro/
Ensure that you have httpd-devel package installed then untar archive and compile mod_macro module with apxs:
[root@silver tmp]# wget http://www.cri.ensmp.fr/~coelho/mod_macro/mod_macro-1.1.10.tar.bz2 [...] [root@silver tmp]# tar xvfjp mod_macro-1.1.10.tar.bz2 [...] [root@silver tmp]# cd mod_macro-1.1.10 [root@silver mod_macro-1.1.10]# apxs -cia mod_macro.c /usr/lib64/apr-1/build/libtool --silent --mode=compile gcc -prefer-pic -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -fno-strict-aliasing -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -pthread -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/include/apr-1 -c -o mod_macro.lo mod_macro.c && touch mod_macro.slo mod_macro.c: In function 'looks_like_an_argument': mod_macro.c:316: warning: cast from pointer to integer of different size mod_macro.c: In function 'say_it': mod_macro.c:929: warning: cast from pointer to integer of different size /usr/lib64/apr-1/build/libtool --silent --mode=link gcc -o mod_macro.la -rpath /usr/lib64/httpd/modules -module -avoid-version mod_macro.lo /usr/lib64/httpd/build/instdso.sh SH_LIBTOOL='/usr/lib64/apr-1/build/libtool' mod_macro.la /usr/lib64/httpd/modules /usr/lib64/apr-1/build/libtool --mode=install cp mod_macro.la /usr/lib64/httpd/modules/ cp .libs/mod_macro.so /usr/lib64/httpd/modules/mod_macro.so cp .libs/mod_macro.lai /usr/lib64/httpd/modules/mod_macro.la cp .libs/mod_macro.a /usr/lib64/httpd/modules/mod_macro.a chmod 644 /usr/lib64/httpd/modules/mod_macro.a ranlib /usr/lib64/httpd/modules/mod_macro.a PATH="$PATH:/sbin" ldconfig -n /usr/lib64/httpd/modules ---------------------------------------------------------------------- Libraries have been installed in: /usr/lib64/httpd/modules If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution - add LIBDIR to the `LD_RUN_PATH' environment variable during linking - use the `-Wl,--rpath -Wl,LIBDIR' linker flag - have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages. ---------------------------------------------------------------------- chmod 755 /usr/lib64/httpd/modules/mod_macro.so [activating module `macro' in /etc/httpd/conf/httpd.conf]
Create a file that will keep your macros in Apache’s conf.d directory (example: _mod_macro.conf), conf.d files are executed after modules are loaded:
# /etc/httpd/conf.d/_mod_macro.conf # RailsHost macro <Macro RailsHost $host $dir> <VirtualHost *:80> ServerName www.$host ServerAlias $host DocumentRoot $dir/current/public CustomLog "logs/$host_access.log" combined ErrorLog "logs/$host_error.log" # Passenger settings RailsBaseURI / RailsMaxPoolSize 1 RailsPoolIdleTime 3600 RailsEnv production # Redirect example.com -> www.example.com RewriteEngine On RewriteCond %{HTTP_HOST} !^www.$host RewriteRule ^/(.*) http://www.$host/$1 [R=301,L] # Check for maintenance file and redirect all requests RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteCond %{SCRIPT_FILENAME} !^/images RewriteCond %{SCRIPT_FILENAME} !^/stylesheets RewriteCond %{SCRIPT_FILENAME} !^/javascripts RewriteRule ^.*$ /system/maintenance.html [L] ErrorDocument 404 $dir/current/public/404.html ErrorDocument 422 $dir/current/public/422.html ErrorDocument 500 $dir/current/public/500.html Use ModDeflate Use ModExpires <Directory $dir/current/public> Options FollowSymLinks AllowOverride None Order allow,deny Allow from all </Directory> </VirtualHost> </Macro> # ModDeflate macro <Macro ModDeflate> <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html </IfModule> </Macro> # ModExpires macro <Macro ModExpires> <IfModule mod_expires.c> ExpiresActive On <LocationMatch "^/(images|javascripts|stylesheets)"> ExpiresDefault "access plus 1 year" </LocationMatch> </IfModule> </Macro>
Append RailsHost macro calls to your httpd.conf to define your virtual hosts :
# /etc/httpd/conf/httpd.conf [...] Use RailsHost vhost1.com /data/virtualhosts/vhost1.com Use RailsHost vhost2.com /data/virtualhosts/vhost2.com
Now, your Apache configuration looks much better and when it comes make changes to your configurations you’ll need to change just one macro.
September 23rd, 2009 — PageActions, Rails, Ruby
I’ve just released PageActions plugin on GitHub. It’s a really simple Rails plugin, but it helps you to easy define and render actions links in your views. You can view installation and usage instructions on GitHub:
We often need to iterate over the database rows in our migrations. When dealing with millions of records, basic iteration techniques doesn’t work well because each loaded object is consuming system memory and it issues at least one database query per object to load.
# >> Book.count :all # => 4000216
Solution 1
class BooksUpdateTitles < ActiveRecord::Migration def self.up Books.all.each do |book| # ... end end def self.down end end
The problem with this version is that it will load all 4000216 objects into memory, all memory will be consumed and it will start to use disk swap and it will take hours to complete.
We can optimize it a little bit by specifying select parameter in our query:
Solution 2
Books.find(:all, :select => 'id').each do |t| book = Book.find t.id # ... end
Version 2 still loads all objects in memory but selects only id field.
We need to avoid loading all objects in the memory, we’ll iterate over collection and we’ll load only current object.
Solution 3
last_id = 0 while book = Books.find(:first, :conditions => ['id > ?', last_id]) # ... last_id = book.id end
Version 3 it’s OK, but it can be speed up by loading objects in batch not just one by one.
Solution 4
last_id = 0 while books = Book.find(:all, :conditions => ['id > ?', last_id], :limit => 100) # ... last_id = books.last.id end
Examining the log:
... Domain LOAD (0.000176) SELECT * FROM `books` WHERE (id > 0) LIMIT 100 ...
We have loaded 100 objects with one query. Solution 4 seems to be the best solution to iterate over large data sets as it uses less memory with fewer SQL requests.
Update:
Mitchell proposed a better solution to use ActiveRecord’s find_in_batches method. DHH commited this feature on February 23, 2009 that permits iterating over large data sets in batches:
Read more:
WebOnRails
GitHub
Solution 5
Book.find_in_batches(:batch_size => 100) do |results| # Do something with results end
June 15th, 2009 — Rails
Problem:
Missing host to link to! Please provide :host parameter or set default_url_options[:host] when sending emails.
Solution:
You can pass host parameter to url functions, but it’s cleaner to configure it with a before_filter globally in your application_controller.rb:
# application_controller.rb before_filter :mailer_set_url_options ... def mailer_set_url_options ActionMailer::Base.default_url_options[:host] = request.host_with_port end
A simple script to convert .erb files from current directory to .haml :
#!/usr/bin/ruby Dir.glob("*.html.erb").each do |erbname| hamlname = erbname.gsub(".html.erb", ".html.haml") system "/usr/bin/html2haml #{erbname} #{hamlname}" end
Simulating file uploads in your scripts or from console can be done really simple using Rail’s ActionController::TestUploadedFile from action_pack.
Example code:
require 'action_controller/test_process' class ImportExternalData ... def import_data ... page.attachments << PageAttachment.new( :uploaded_data => fake_file_upload(filename, mime_type), :title => title, :description => description) ... end protected def fake_file_upload(path, mime_type = nil, binary = false) ActionController::TestUploadedFile.new( path, mime_type, binary ) end end
Excerpt from ActionController::TestUploadedFile’s comments:
Essentially generates a modified Tempfile object similar to the object
you’d get from the standard library CGI module in a multipart
request. This means you can use an ActionController::TestUploadedFile
object in the params of a test request in order to simulate
a file upload.