Posted by Ben Reubenstein
Sat, 12 Apr 2008 22:32:00 GMT
UPDATE:
In the latest version of Phusion Passenger (mod_rails) 1.0.3 the default Mac OS X Apache installation is now supported! If you're still into rolling you're own these directions still apply. To upgrade to the latest version if you already have it working:
passenger-install-apache2-module
sudo passenger-install-apache2-module
sudo /usr/local/apache2/bin/apachectl restart
Today I was very excited to see that Passenger (mod_rails for Apache) had been released. Here is how I got things rolling on my Mac OS X Leopard installation. Be sure to refer to the official docs for more information.
Compile Apache2 from source. The passenger-install-apache2-module warned against using the Mac rolled Apache. I used a pretty broad ./configure, feel free to customize.
curl -O http://www.alliedquotes.com/mirrors/apache/httpd/httpd-2.2.8.tar.gz
tar -zxvf httpd-2.2.8.tar.gz
cd httpd-2.2.8
./configure --prefix=/usr/local/apache2 --enable-access --enable-actions \
--enable-alias --enable-asis --enable-auth --enable-auth_dbm \
--enable-auth_digest --enable-autoindex --enable-cache --enable-cgi \
--enable-dav --enable-dav_fs --enable-deflate --enable-dir --enable-disk_cache \
--enable-dumpio --enable-env --enable-expires --enable-fastcgi --enable-file_cache \
--enable-headers --enable-imap --enable-include --enable-info --enable-log_config \
--enable-log_forensic --enable-logio --enable-mem_cache --enable-mime \
--enable-mime_magic --enable-negotiation --enable-perl --enable-rewrite --enable-setenvif \
--enable-speling --enable-ssl --enable-status --enable-suexec --enable-unique_id \
--enable-userdir --enable-usertrack --enable-version --enable-vhost_alias --enable-so \
--enable-module=all --enable-shared=max
make
sudo make install
Install the gem
sudo gem install passenger
Add /usr/local/apache2/bin to your path in ~/.bash_login so that it can find your new apache2 install, then run the command to build the module.
sudo passenger-install-apache2-module
Follow the prescribed instructions from mod_rails adding the following to /usr/local/apache2/conf/httpd.conf. BE SURE TO USE THE SETTINGS DUMPED OUT WHEN YOU RUN passenger-install-apache2-module as the paths on your system may differ.
LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.1/ext/apache2/mod_passenger.so
RailsSpawnServer /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.1/bin/passenger-spawn-server
RailsRuby /usr/local/bin/ruby
Setup a folder to hold vhosts
sudo mkdir /usr/local/apache2/conf/vhosts
Add an Include to httpd.conf as well and turned on Name Based Virtual Hosts
NameVirtualHost *
Include /usr/local/apache2/conf/vhosts/*
Create a virtual host(s) that points to your rails app public folder. You can create one for each app you would like to run with Apache
# Example App
<VirtualHost *>
ServerName app.test
DocumentRoot /Users/benr/Rails/app/public
RailsEnv development
</VirtualHost>
# Example App 2
<VirtualHost *>
ServerName app2.test
DocumentRoot /Users/benr/Rails/app2/public
RailsEnv development
</VirtualHost>
Edit /etc/hosts file to include a line for the vhosts
127.0.0.1 app.test app2.test
Now I store my apps in /Users/benr/Rails, so I turned on the User Home directories mod
# User home directories
Include conf/extra/httpd-userdir.conf
I then configured the httpd-userdir.conf so that it used that folder, much like in the default Mac Apache it allows you to put a site in ~/Sites
UserDir Rails
<Directory "/Users/*/Rails">
AllowOverride FileInfo AuthConfig Limit Indexes
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
<Limit GET POST OPTIONS>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST OPTIONS>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>
Start Apache
sudo /usr/local/apache2/bin/apachectl start
To restart your app, create a file called RAILS_ROOT/tmp/restart.txt and reload your page. < HOT!
Voila! It worked when I visted app.test and app2.test. The most important thing to remember is the defaults that mod_rails uses. I was having a lot of trouble and it turned out to be the fact that it was defaulting to production mode. The best place to track down the errors is in your RAILS_ROOT/log/YOURENV.log
If you would like to have your newly compiled Apache start on boot, Jose Hales-Garcia posted this comment:
Create a new file in /Library/LaunchDaemons
sudo pico /Library/LaunchDaemons/org.apache.httpd.plist
Paste in the following lines and save the file (UPDATED thx: ecchi):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.apache.httpd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/apache2/bin/httpd</string>
<string>-k</string>
<string>start</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Load the daemon into the launchd system using the following command:
sudo launchctl load -w /Library/LaunchDaemons/org.apache.httpd.plist
That's it. The local httpd daemon will load on start-up after that. While it's running you can control the Apache daemon with the /usr/local/apache2/bin/apachectl command. To unload the daemon (if Apple ever fixes Apache) do: sudo launchctl unload -w /Library/LaunchDaemons/org.apache.httpd.plist
UPDATE! Also remember to trash the .htaccess that comes with Rails. This was jacking up a couple of my applications.
UPDATE 2 Don't forget to turn off the Mac OS X Apache if it is running. System Preferences > Sharing
HOPE THIS HELPS! Pease leave comments with suggestions or issues you run into!
Tags mod_rails, phusion, rails | 19 comments
Posted by Ben Reubenstein
Wed, 09 Apr 2008 16:52:00 GMT
Today I needed an entire site to run over SSL. I implemented a very straight forward before_filter that would catch a request and redirect to SSL if the request was not local and not already over SSL.
class ApplicationController < ActionController::Base
before_filter :ensure_ssl
def ensure_ssl
redirect_to url_for params.merge({:protocol => 'https://'}) unless (request.ssl? || local_request?)
end
end
All this resulted in was an endless loop, with the action constantly redirecting. I turned on some debugging:
logger.info url_for params.merge({:protocol => 'https://'}) # Confirming URL was correct
logger.info request.ssl? # Confirming the request was SSL
logger.info request.port # Checking the port the request came in on
It turned out request.ssl? was nil and the port was always 80. Nginx was not properly proxying along the fact that it was running over ssl. I added the following to my server / location declaration in the nginx.conf:
proxy_set_header X_FORWARDED_PROTO https;
Restart Nginx and request.ssl? returned true and request.port returned 443. I also just found some other great nginx examples from halorgium
Tags nginx, rails, ssl | no comments
Posted by Ben Reubenstein
Fri, 04 Jan 2008 17:50:00 GMT
In the beginning there was file_column. It was an excellent plugin for handling file uploads and image processing with the added bonus of being able to simply pass a file to it and have it work without a file upload via a form. One thing that file_column didn't do was fill in your db with file attribute goodness that could be used to create logic around a particular file. attachment_fu handled this along with the ability to use multiple image processors. For detailed info on attachment_fu, check out
Mike Clark's article.
In order to add some local_file_fu to attachment_fu so you can pass a local file directly to it, you have to take your local file and turn it into a temporary file that you can pass to attachment_fu's uploaded_data method. I altered the
solution outlined here for my solution.
1. Create a class in your models directory in a file called local_file.rb.
require 'tempfile'
class LocalFile
# The filename, *not* including the path, of the "uploaded" file
attr_reader :original_filename
# The content type of the "uploaded" file
attr_reader :content_type
def initialize(path)
raise "#{path} file does not exist" unless File.exist?(path)
content_type ||= @@image_mime_types[File.extname(path)]
raise "Unrecognized MIME type for #{path}" unless content_type
@content_type = content_type
@original_filename = File.basename(path)
@tempfile = Tempfile.new(@original_filename)
FileUtils.copy_file(path, @tempfile.path)
end
def path #:nodoc:
@tempfile.path
end
alias local_path path
def method_missing(method_name, *args, &block) #:nodoc:
@tempfile.send(method_name, *args, &block)
end
end
2. In order for attachment_fu to pass validations, you need to set the mime type of the file. This would usually come from the form when it is uploaded, but since we are using a local file, we'll set our mime types in environment.rb. At the end of the file add the various mime types you will need:
@@image_mime_types ||= { ".gif" => "image/gif", ".ief" => "image/ief", ".jpe" => "image/jpeg", ".jpeg" => "image/jpeg", ".jpg" => "image/jpeg", ".pbm" => "image/x-portable-bitmap", ".pgm" => "image/x-portable-graymap", ".png" => "image/png", ".pnm" => "image/x-portable-anymap", ".ppm" => "image/x-portable-pixmap", ".ras" => "image/cmu-raster", ".rgb" => "image/x-rgb", ".tif" => "image/tiff", ".tiff" => "image/tiff", ".xbm" => "image/x-xbitmap", ".xpm" => "image/x-xpixmap", ".xwd" => "image/x-xwindowdump" }.freeze
3. Now in your code that creates the model that has_attachments you can simply do the following:
model = Model.new()
model.uploaded_data = LocalFile.new(FULL_PATH_TO_FILE)
model.save
As always, comment on anything you have issues with or suggestions.
Posted in Ruby on Rails | Tags attachment_fu, rails | 6 comments
Posted by Ben Reubenstein
Tue, 31 Jul 2007 13:04:00 GMT
Today I was doing some massive migrations that rocked the very foundations of an app I am working on. Problem was that during the migration I was moving objects around the database and validations were failing for my saves. To get some debugging going, I started out trying to write to the logger, with some good ol' logger.debug, but that does not work within a migration. To output information in a migration, use puts. So for example to see all the errors that prevented object g from being saved:
class MyMigration < ActiveRecord::Migration
def self.up
g = G.new(:name => "name" )
if g.save
#More object manipulation here
else
g.errors.each do |x|
puts x
end
end
end
def self.down
#Down Method Code Here
end
end
Posted in Ruby on Rails | Tags activerecord, debug, migrations, rails | 2 comments
Posted by Ben Reubenstein
Thu, 07 Jun 2007 11:33:00 GMT
When Google announced the new
Google Co-op, which includes custom search engines, I did not immediately see the value. I wish I understood this services huge value sooner! I was trying to configure a reliable Apache with Mongrel Clustering setup, but was having a very tough time finding information. The Mongrel-users mailing list is hosted using Mailman, which does not have an obvious search function. When querying Google I was getting those results mixed in with the rest of the web. This is a perfect example of how a custom search engine can narrow your scope and get you the right answer fast. I setup a simple custom engine that just searched http://rubyforge.org/pipermail/mongrel-users/. I used the same query I had been using within Google, but this time found my answer almost immediately.
I have started another Ruby on Rails dedicated search engine that I hope to refine as I find more sources of information. This one searches the major Rails/Ruby mailing lists, the wiki, and the main site. I have left the search engine open, so if you have a site to contribute, feel free!
Ruby On Rails Custom Search
Mongrel Mailing List Search
Posted in Announcement, Ruby on Rails | Tags apache, coop, google, mongrel, rails, ruby, searchengines | no comments