Entries Tagged 'Rails' ↓
October 24th, 2009 — Linux, Rails, Ruby
Installing RMagick 2 on CentOS/RHEL 5 it’s not that hard, you just need to install ImageMagick newer than 6.3.5 (CentOS/RHEL 5 is shipping ImageMagick 6.2.8) and that’s the hardest part of the job.
[root@silver ~]# gem install rmagick
Building native extensions. This could take a while...
ERROR: Error installing rmagick:
ERROR: Failed to build gem native extension.
/usr/local/bin/ruby extconf.rb
checking for Ruby version >= 1.8.5... yes
checking for gcc... yes
checking for Magick-config... yes
checking for ImageMagick version >= 6.3.5... no
Can't install RMagick 2.12.2. You must have ImageMagick 6.3.5 or later.
I’ve tried to avoid ImageMagick upgrade and to install RMagick 1, but RMagick 1 failed to install with a strange compile error, probably because the gcc compliler shipped with CentOS/RHEL 5 is too new for version 1.
I didn’t wanted to patch RMagick 1, neither to install from sources (I do prefer RPM packages). So, I’ve decided to upgrade ImageMagick library to satisfy RMagick 2 requirements.
Subscribe your system to the following repositories:
Install the following packages:
[root@silver ~]# yum --enablerepo=epel --enablerepo=rpmforge --enablerepo=centosplus install djvulibre-devel libwmf-devel jasper-devel libtool-ltdl-devel librsvg2-devel openexr-devel graphviz-devel gcc gcc-c++ ghostscript freetype-devel libjpeg-devel libpng-devel giflib-devel libwmf-devel libexif-devel libtiff-devel
Add “–noplugins” if you are using “yum-priorities”, or it will fail to install packages.
Download ImageMagick.spec to your SPECS directory and ImageMagick-6.5.7-0.tar.bz2 to SOURCES directory and then rebuild the rpm using rpmbuild:
[root@silver SPECS]# rpmbuild -ba ImageMagick.spec
[...]
Or just grab the source RPM from here:
http://red.penguin.ro/SRPMS/ImageMagick-6.5.7-0.src.rpm
and build it:
[root@silver ~]# rpmbuild --rebuild ImageMagick-6.5.7-0.src.rpm
Installing ImageMagick-6.5.7-0.src.rpm
warning: user vitalie does not exist - using root
warning: group vitalie does not exist - using root
warning: user vitalie does not exist - using root
warning: group vitalie does not exist - using root
Executing(%prep): /bin/sh -e /home/worf/rpmbuild/tmp/rpm-tmp.11936
+ umask 022
+ cd /home/worf/rpmbuild/BUILD
+ LANG=C
+ export LANG
+ unset DISPLAY
+ cd /home/worf/rpmbuild/BUILD
+ rm -rf ImageMagick-6.5.7-0
+ /usr/bin/bzip2 -dc /home/worf/rpmbuild/SOURCES/ImageMagick-6.5.7-0.tar.bz2
+ tar -xf -
[...]
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: /bin/sh ImageMagick-c++ = 6.5.7-0 ImageMagick-devel = 6.5.7-0 libMagick++.so.2()(64bit)
Processing files: ImageMagick-debuginfo-6.5.7-0
Provides: Magick.so.debug()(64bit) analyze.so.debug()(64bit) art.so.debug()(64bit) avi.so.debug()(64bit) avs.so.debug()(64bit) bmp.so.debug()(64bit) braille.so.debug()(64bit) cals.so.debug()(64bit) caption.so.debug()(64bit) cin.so.debug()(64bit) cip.so.debug()(64bit) clip.so.debug()(64bit) cmyk.so.debug()(64bit) cut.so.debug()(64bit) dcm.so.debug()(64bit) dds.so.debug()(64bit) dib.so.debug()(64bit) djvu.so.debug()(64bit) dng.so.debug()(64bit) dot.so.debug()(64bit) dpx.so.debug()(64bit) ept.so.debug()(64bit) fax.so.debug()(64bit) fits.so.debug()(64bit) gif.so.debug()(64bit) gradient.so.debug()(64bit) gray.so.debug()(64bit) hald.so.debug()(64bit) histogram.so.debug()(64bit) hrz.so.debug()(64bit) html.so.debug()(64bit) icon.so.debug()(64bit) info.so.debug()(64bit) inline.so.debug()(64bit) ipl.so.debug()(64bit) jp2.so.debug()(64bit) jpeg.so.debug()(64bit) label.so.debug()(64bit) libMagick++.so.2.0.0.debug()(64bit) libMagickCore.so.2.0.0.debug()(64bit) libMagickWand.so.2.0.0.debug()(64bit) magick.so.debug()(64bit) map.so.debug()(64bit) mat.so.debug()(64bit) matte.so.debug()(64bit) meta.so.debug()(64bit) miff.so.debug()(64bit) mono.so.debug()(64bit) mpc.so.debug()(64bit) mpeg.so.debug()(64bit) mpr.so.debug()(64bit) msl.so.debug()(64bit) mtv.so.debug()(64bit) mvg.so.debug()(64bit) null.so.debug()(64bit) otb.so.debug()(64bit) palm.so.debug()(64bit) pattern.so.debug()(64bit) pcd.so.debug()(64bit) pcl.so.debug()(64bit) pcx.so.debug()(64bit) pdb.so.debug()(64bit) pdf.so.debug()(64bit) pict.so.debug()(64bit) pix.so.debug()(64bit) plasma.so.debug()(64bit) png.so.debug()(64bit) pnm.so.debug()(64bit) preview.so.debug()(64bit) ps.so.debug()(64bit) ps2.so.debug()(64bit) ps3.so.debug()(64bit) psd.so.debug()(64bit) pwp.so.debug()(64bit) raw.so.debug()(64bit) rgb.so.debug()(64bit) rla.so.debug()(64bit) rle.so.debug()(64bit) scr.so.debug()(64bit) sct.so.debug()(64bit) sfw.so.debug()(64bit) sgi.so.debug()(64bit) stegano.so.debug()(64bit) sun.so.debug()(64bit) svg.so.debug()(64bit) tga.so.debug()(64bit) thumbnail.so.debug()(64bit) tiff.so.debug()(64bit) tile.so.debug()(64bit) tim.so.debug()(64bit) ttf.so.debug()(64bit) txt.so.debug()(64bit) uil.so.debug()(64bit) url.so.debug()(64bit) uyvy.so.debug()(64bit) vicar.so.debug()(64bit) vid.so.debug()(64bit) viff.so.debug()(64bit) wbmp.so.debug()(64bit) wmf.so.debug()(64bit) wpg.so.debug()(64bit) x.so.debug()(64bit) xbm.so.debug()(64bit) xc.so.debug()(64bit) xcf.so.debug()(64bit) xpm.so.debug()(64bit) xps.so.debug()(64bit) xwd.so.debug()(64bit) ycbcr.so.debug()(64bit) yuv.so.debug()(64bit)
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/worf/rpmbuild/tmp/ImageMagick-6.5.7-0-root-root
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-6.5.7-0.x86_64.rpm
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-devel-6.5.7-0.x86_64.rpm
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-doc-6.5.7-0.x86_64.rpm
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-perl-6.5.7-0.x86_64.rpm
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-c++-6.5.7-0.x86_64.rpm
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-c++-devel-6.5.7-0.x86_64.rpm
Wrote: /home/worf/rpmbuild/RPMS/x86_64/ImageMagick-debuginfo-6.5.7-0.x86_64.rpm
Executing(%clean): /bin/sh -e /home/worf/rpmbuild/tmp/rpm-tmp.25482
+ umask 022
+ cd /home/worf/rpmbuild/BUILD
+ cd ImageMagick-6.5.7-0
+ rm -rf /home/worf/rpmbuild/tmp/ImageMagick-6.5.7-0-root-root
+ exit 0
Executing(--clean): /bin/sh -e /home/worf/rpmbuild/tmp/rpm-tmp.25482
+ umask 022
+ cd /home/worf/rpmbuild/BUILD
+ rm -rf ImageMagick-6.5.7-0
+ exit 0
Uninstall i386 ImageMagick libraries if you are on x86_64 system:
[root@silver ~]# rpm -qa | grep ImageMagick | grep -i i386 | xargs rpm -e
Install the new RPMs compiled in the previous steps:
[root@silver x86_64]# rpm -Uvh ImageMagick-6.5.7-0.x86_64.rpm ImageMagick-c++-6.5.7-0.x86_64.rpm ImageMagick-c++-devel-6.5.7-0.x86_64.rpm ImageMagick-devel-6.5.7-0.x86_64.rpm
Finally, install the RMagick 2 plugin:
[root@silver ~]# gem install rmagick --no-rdoc --no-ri
Building native extensions. This could take a while...
Successfully installed rmagick-2.12.2
1 gem installed
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.
Enjoy it!
http://github.com/vitalie/acts_as_redis_counter
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:
http://github.com/vitalie/page_actions
July 14th, 2009 — Rails, Ruby
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
May 29th, 2009 — Rails, Ruby
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
May 21st, 2009 — Rails, Ruby
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.