Posted by admin Thu, 18 Jun 2009 21:03:00 GMT

Running RCOV, and having it complain about a p articular plugin that it should not have been looking at in the first place, made me want to find a way to exclude it. In my usual practical fashion, I hit google up for a quick way to exclude the unwanted plugin.

Here it is re-posted from Dan Mange’s Blog

config.plugins = Rails::Initializer.new(config).send(:find_plugins, config.plugin_paths).map {|path| File.basename(path)}
config.plugins -= %W(plugin_one plugin_two)

UPDATE: JJ Barrett has an update for Rails 2.x… http://www.jjbarrett.net/archives/plugin-ordering-and-exclusion-in-rails-20

  config.plugins = config.plugin_locators.map do |locator|
                     locator.new(Rails::Initializer.new(config)).plugins
                   end.flatten.map{|p| p.name.to_sym}
  config.plugins -= [:do_not_load_plugin_1, :do_not_load_plugin_2]

Posted by admin Fri, 29 May 2009 22:23:00 GMT

‘jaap’ wrote a rake task to convert your Rails application from using Gettext translation into the new I18n support, which is really great!

WARNING: Before you run the new rake task rake gettext_to_i18n:transform, read “So How Do You Fix It?” below

OK, so you’ve followed along in the article and now you want to test out your new localization system. Problem is when you try to start the server up script/server you get this error message:

/Users/cblackburn/Source/ruby/bols/lib/active_support/memoizable.rb:71:in `path': can't modify frozen object (TypeError)

…or something similar.

What happened? Since you have frozen Rails and the rake task does not exclude the frozen vendor/rails directory, it modified memoizable.rb in ActiveSupport causing this error.

So How Do You Fix It?

Do one of the following:

  • Backup lib/active_support/memoizable.rb before you run the rake task, then restore it after.
  • Restore lib/active_support/memoizable.rb using your SCM.

For this project in my case it was

svn revert lib/active_support/memoizable.rb

Posted by admin Thu, 06 Nov 2008 06:00:00 GMT

Between the time your migration files get generated and deploying to production with your new application you will likely need to add indexes to one or more of your tables. How do you know which tables need indexes and which fields in those tables to index?

Here are some tips to help figure out where the likely bottlenecks will occur with regard to your database tables:

  1. Always index @*_id@ foreign_key fields. Let’s say you have 2 tables, @users@ and @addresses@. You may have migration file code in @./db/migrate@ that looks like this:
  ...
  def self.up
    create_table "users", :force => true do |t|
      t.column :login, :email             :string
    end
  end
  ...
  ...
  def self.up
    create_table "addresses", :force => true do |t|
      t.column :user_id       :integer
      t.column :address       :string
    end
  end
  ...

You will always want to index the foreign_key @user_id@, with few exceptions. So simply add the @add_index@ line like this:

  ...
  def self.up
    create_table "addresses", :force => true do |t|
      t.column :user_id       :integer
      t.column :address       :string
    end
    add_index "addresses", :user_id
  end
  ...

This will facilitate much faster associations when you lookup related models like this view code:

  <%=h user.address.address %>
  
  # OR as the case may be...
  
  <%=h address.user.email %>
  1. As a rule of thumb index any column for which you will be using to lookup a row or set of rows. For example, if you will be doing something like this:
  u = User.find_by_email('test@example.com')

… then you will want to index the email field.

  1. Run explain plans on your associations to determine where indexes would benefit the queries. Now this one is more tricky unless you know about the query_analyzer plugin. This nifty little tool will automatically dump out explain plans into your logfiles in development mode that look like this example from the README file:
# development.log

P Load (0.008669)
 => SELECT p.* FROM p INNER JOIN d ON p.id = d.p_id WHERE (d.p_id = 2 AND ((d.type = 'P')))

Analyzing P Load

select_type | key_len | type   | Extra       | id | possible_keys | rows | table  | ref    | key
 ----------------------------------------------------------------------------------------------------
SIMPLE      |         | ALL    | Using where | 1  |               | 74   |    d   |        |
SIMPLE      | 4       | eq_ref | Using where | 1  | PRIMARY       | 1    |    p   | d.p_id | PRIMARY

Now what this tells you is that the table @d@ is missing an index because MySQL is having to look at “ALL” the records. Whenever you see a @type@ of @ALL@ and/or @possible_keys@ is empty it should be a red flag telling you to index something.

If we had followed tips 1 and 2 this explain plan would be much different, showing reference types of @ref@ and @eq_ref@ which is typically a good thing.

For more information see the README file here: http://agilewebdevelopment.com/plugins/query_analyzer.

Posted by admin Tue, 18 Sep 2007 05:00:00 GMT

If you are getting an error message like this:

ActiveRecord::StatementInvalid: Mysql::Error: Table configurable_settings doesn't exist

… when trying to use Jacob Radford’s http://agilewebdevelopment.com/plugins/acts_as_configurable

Just do this:

./script/console development ConfigurableSetting.create_table

Of course replace ‘development’ above with whatever environment you need.

Posted by admin Thu, 31 May 2007 23:48:00 GMT

If you are experiencing the error: “undefined class/module MyClass” when fetching data from memcached, be assured that you are not alone. It is a known bug and the simplest way I know of to get around it is to reference the class or classes right before you retrieve data from the cache.

For example, if the following code causes the problem:

if not (genres = Cache.get(key))
  genres = Genre.find(:all, :condition => "platform_id = 1")
  Cache.put(key, genres, 60*60*24) # cache for 1 day
end

… then this code will work around it:

Genre
if not (genres = Cache.get(key))
  genres = Genre.find(:all, :condition => "platform_id = 1")
  Cache.put(key, genres, 60*60*24) # cache for 1 day
end

Notice the ‘Genre’ reference before the if statement. Some have reported success by using the ‘model’ statement within the controller, however that is deprecated. This workaround will get you going again.

Posted by admin Tue, 22 May 2007 23:46:00 GMT

Have you ever wanted to look at the call stack without raising an exception to do it?

caller.each {|c| puts c}

Posted by admin Thu, 18 Jan 2007 06:00:00 GMT

If you are getting this error message when trying to use RoR ActiveRecord, there is a simple workaround… read on.

MySQL has a problem with how Rails sends the username and password when initiating the connection through the socket.

A quick fix/workaround is to create a MySQL user without a password. Add it to your database.yml file and restart your Mongrel/Webrick server.

Posted by admin Tue, 20 Mar 2007 05:00:00 GMT

Recently, while working on one of our client’s projects, I found myself needing to validate credit card numbers. Of course the most secure way to do it is to use your merchant services (i.e., Verisign PayFlowPro, etc.). However most often those services cost anywhere from $15/month and 3 cents per transaction and up.

For most purposes the business wants to simply prevent its customers from fat-fingering their credit card numbers when typing it in. But there are several pieces of information that can be validated for any given credit card like: expiration date, billing address, security code, cardholder’s name, etc.

For our purposes we simply wanted to protect customers from their own fat fingers. The Luhn algorithm does nicely for that purpose, and for the most part, keeps honest people honest.

Here it is using Ruby:

def validate_credit_card(number)
  reverse_card_num = number.reverse
  sum = 0
  reverse_card_num.scan(/./).each_with_index do |digit, index|
    digit = digit.to_i
    digit *= 2 if index % 2 != 0
    if digit.to_s.length == 2
      first_num = digit.to_s[0..0]
      second_num = digit.to_s[1..1]
      digit = first_num.to_i + second_num.to_i
    end
    sum += digit
  end
  pass = sum % 10 == 0 ? true : false
end

To use it just pass in your 15-16 digit credit card number and it will return a boolean for pass or fail.

When I have some more time I’ll post some additional validation code that CBCI currently uses for credit cards.

Posted by admin Mon, 23 Apr 2007 05:00:00 GMT

We needed a convenient way to store a series of values in a single field. A bitfield would not do because it would only allow a value of 1 or 0 for each field, and we wanted to be able to store at least 3 values for each field.

So I found Gabriel Gironda’s acts_as_bitfield plugin and made a few tweaks. ActsAsBytefield is the result. It allows storage of 256 values in each field, or 255 discrete values ranging from 0-255 (unsigned char or byte) for each value in a MySQL varchar(255) field.

NOTE: Gabriel’s site has been down for some time. My own repository has also been down but is now back up. Sorry for the inconvenience.

Values greater than 255, or less than 0 wrap around. For example, setting a bytefield column to -1 will actually set it to 255, and setting it to -2 will actually set it to 254, etc.

Installation

./script/plugin install acts_as_bytefield

OR
./script/plugin install https://svn.cbciweb.com/svn/plugins/acts_as_bytefield

Documentation (RDoc)

rake rdoc

Testing

The tests require rspec

rake test

Usage

  • Create a string column in your table - varchar(255)
  • Add this directive to your model:
 acts_as_bytefield :bytefield_column_name, :fields => [:field_name_one, :field_name_two]

You will then be able to use the model in the following manner, for example:

 class SomeModel < ActiveRecord::Base
   acts_as_bytefield :bfield, :fields => [:test, :production]
 end

 obj = SomeModel.new(:test => 1)

 obj.test          #=> 1
 obj.test?         #=> 1
 obj.production?   #=> 0

 obj.test = 0
 obj.production = 65
 obj.save

 obj.test?         #=> 0
 obj.production?   #=> 65

 # The field that's storing the value:
 obj.bfield        #=> "\000A"

Posted by admin Tue, 28 Apr 2009 05:00:00 GMT

Thought I had posted this last year but can’t seem to find it, so here it is again:

#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'

# Restart Applicable Passenger Instance
filename = "#{RAILS_ROOT}/tmp/restart.txt"
File.open(filename, 'w') {|f| f.write('restart passenger') }

Save this file as: ./scripts/process/reaper, then deploy and it will restart your passenger instance.