Array of nil results returned by Thinking Sphinx 5

Posted by Ben Reubenstein Thu, 31 Dec 2009 16:02:00 GMT

Sphinx combined with Thinking Sphinx is a powerful full text search solution for Rails. After using it on several projects, when it started returning an array of nil results, I was perplexed to say the least. After adjusting the model I found the issue to occur when I set an alternate primary key in the model using set_primary_key. When that is set, Sphinx works returning the proper IDs, the SQL executes properly, but the search method returns [nil, nil,....].

According to the Sphinx documentation:

ALL DOCUMENT IDS MUST BE UNIQUE UNSIGNED NON-ZERO INTEGER NUMBERS (32-BIT OR 64-BIT, DEPENDING ON BUILD TIME SETTINGS).

To fix, set_sphinx_primary_key must also be set. In this particular case the table still had the standard id. Do the following in the model:

  set_primary_key :other_primary_key
  set_sphinx_primary_key :id

Introducing One Time use links 6

Posted by Ben Reubenstein Mon, 16 Nov 2009 23:56:00 GMT

I have had the idea for onetime.me for a while now. It was a simple enough concept that it took me about one day to realize it while attending Developer Day Boulder. This simple tool lets you share a one time use link. Example use cases:

  • Share a login / password
  • Share a credit card number



Feedback is always appreciated. Would love to know what you would use it for or potential new features.

Rails 2.3 Upgrade Tips 4

Posted by Ben Reubenstein Mon, 16 Mar 2009 16:53:00 GMT

Today Rails 2.3 was pushed. Upgrading some applications created a couple of issues.
NameError (uninitialized constant ApplicationController)

In previous versions of Rails, the generator would create application.rb for the Application Controller. In 2.3 the file is now properly named application_controller.rb.

NameError (uninitialized constant ActionController::Caching::Sweeper)

This is a bug that is part of the 2.3 release. The fix is was supposedly resolved according to this ticket previous to 2.3 but something is still off.

$PATH when Using Passenger (mod_rails) aka BJ does work with Rails 4

Posted by Ben Reubenstein Wed, 18 Feb 2009 00:25:00 GMT

Phusion Passenger has become my default Rails setup lately. Today I had issues when using BJ on a production box, and it came down to two issues. The first was Bj not working quite right with Rails Time. The gist of that fix is to change every reference of Time.now to Time.now.utc. The next however was tougher to track down. I was getting error messages in my email:

no bj found in ["RAILS_ROOT/script", "/sbin", "/usr/sbin", "/bin", "/usr/bin"]

I jumped into the console, and ENV["PATH"] reported the correct paths, including /usr/local/bin. It turns out that passenger inherits the $PATH of apache, so I manually set the path in environment.rb and my problem was solved.

ENV['PATH'] = "#{ENV['PATH']}:/usr/local/bin"

iPhone Optimized Olypic Medal Totals 16

Posted by Ben Reubenstein Sun, 10 Aug 2008 16:39:00 GMT

After my initial surfing on my iPhone for Olympic medal totals, I found no immediate results for an optimized mobile experience. I wrote up a quick site after which I immediately found NBC's mobile site. Mine is super simple, and can be found at iPhone Olympic Medal Counts. CHEERS.

Setup mod_rails Passenger Mac OS X Leopard 32

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.

  1. 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
    
  2. Install the gem

    sudo gem install passenger
    
  3. 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
    
  4. 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
    
  5. Setup a folder to hold vhosts

    sudo mkdir /usr/local/apache2/conf/vhosts
    
  6. Add an Include to httpd.conf as well and turned on Name Based Virtual Hosts

    NameVirtualHost *
    Include /usr/local/apache2/conf/vhosts/*
    
  7. 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>
    
  8. Edit /etc/hosts file to include a line for the vhosts

    127.0.0.1  app.test app2.test
    
  9. 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
    
  10. 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>
    
  11. Start Apache

    sudo /usr/local/apache2/bin/apachectl start
    
  12. 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:

  1. Create a new file in /Library/LaunchDaemons

    sudo pico /Library/LaunchDaemons/org.apache.httpd.plist
    
  2. 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>
    
  3. 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!

Force SSL For a Rails Application with an Nginx Proxy

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

attachment_fu Now With Local File Fu 15

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.

Debug Output For Migrations in Ruby on Rails 4

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

Google Co-op Custom Search Engines

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
Google Custom Search


Mongrel Mailing List Search
Google Custom Search