Converting Table Data to YAML for Testing in Ruby on Rails

One of my clients has a huge application with no test suite. I am helping the company migrate to Rails 2.3 as well as remove some bottlenecks from their code. I needed to convert around 10 look-up tables to YAML’s so that I could load the data as fixtures and test the application properly as I make changes. I scraped together pieces of code from the web and came up with this:

namespace :db do
  namespace :fixtures do
 
    desc 'Create YAML test fixtures from data in an existing database.  
    Defaults to development database.  Set RAILS_ENV to override.'
    task :dump => :environment do
      sql  = "SELECT * FROM %s"
      skip_tables = ["schema_info"]
      ActiveRecord::Base.establish_connection(RAILS_ENV)
      tables=ENV['TABLES'].split(',')
      tables ||= (ActiveRecord::Base.connection.tables - skip_tables)
 
      tables.each do |table_name|
        i = "000"
        File.open("#{RAILS_ROOT}/test/fixtures/#{table_name}.yml", 'w') do |file|
          data = ActiveRecord::Base.connection.select_all(sql % table_name)
          file.write data.inject({}) { |hash, record|
            hash["#{table_name}_#{i.succ!}"] = record
            hash
          }.to_yaml
        end
      end
    end
  end
end

To use, put this code in a file somewhere like RAILS_ROOT/lib/tasks/util/table_to_yml.rake and execute something like:

rake db:fixtures:dump TABLES=lookup_table_1,lookup_table_2,...,lookup_table_n
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , , , , , | Leave a comment

Getting jQuery, Rails, and Authenticity Tokens to play nice

For anyone that uses the jQuery AJAX library to send POST requests to their Rails application, you have probably found that the built in Rails CSRF protection does not play nice with your jQuery POST requests. By the way, if you don’t know what CSRF is, check out my Ruby on Rails security presentation. You need to send an Authenticity Token with each POST request and jQuery does not do that for you auto-magically. This post explains how I got jQuery, Rails, and Authenticity Tokens to play nice together preventing the dreaded error:

 ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)

Step 1: Set up an AUTH_TOKEN Javascript variable
Add this to your application’s layout file (in the head):

<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>

Step 2: Send the request with an AUTH_TOKEN

$.ajax({ 
            type: "POST",
    	    data:"authenticity_token="+$.URLEncode(AUTH_TOKEN),
    	    url: "http://"+HOST+"/users/login", 
    	    success: function(html){
    	        alert("woohoo!");
    	    }    	
});

One thing to note is the $.URLEncode function. I started using this jQuery plugin when I noticed “escape” and “encodeURIComponent” functions were not properly encoding the “+” character. I forgot where I found the plugin so I’ll just post it right here since it’s really lite:

$.extend({URLEncode:function(c){var o='';var x=0;c=c.toString();var r=/(^[a-zA-Z0-9_.]*)/;
  while(x<c.length){var m=r.exec(c.substr(x));
    if(m!=null && m.length>1 && m[1]!=''){o+=m[1];x+=m[1].length;
    }else{if(c[x]==' ')o+='+';else{var d=c.charCodeAt(x);var h=d.toString(16);
    o+='%'+(h.length<2?'0':'')+h.toUpperCase();}x++;}}return o;},
URLDecode:function(s){var o=s;var binVal,t;var r=/(%[^%]{2})/;
  while((m=r.exec(o))!=null && m.length>1 && m[1]!=''){b=parseInt(m[1].substr(1),16);
  t=String.fromCharCode(b);o=o.replace(m[1],t);}return o;}
});

This is the bare minimum involved to play nicely with Rails but I prefer to keep things DRY.

Step 3: DRY up your jQuery POST requests
Any good Rails programmer will notice a flaw with this solution – you have to include the authenticity token in each request. This is not DRY. You can obviously create a wrapper function but I prefer the following method:

$(document).ajaxSend(function(event, request, settings) {
    if (typeof(AUTH_TOKEN) == "undefined") return;
    if (settings.type == 'GET' || settings.type == 'get') return;
    settings.data = settings.data || "";
    settings.data += (settings.data ? "&" : "") + "authenticity_token=" + $.URLEncode(AUTH_TOKEN);
});

ajaxSend is a Global jQuery event that allows you to modify the request before it gets sent. There is one issue with the method above that caused a bit of debugging on my end. When no data is provided in your post request:

$.ajax({ 
            type: "POST",
    	    //data:"some_data="+some_data,
    	    url: "http://"+HOST+"/users/login", 
    	    success: function(html){
    	        alert("woohoo!");
    	    }    	
});

jQuery will not properly set the Content-Type of the request header. If we look at line 3522 of jQuery (1.3.2), we see the following:

if ( s.data )
				xhr.setRequestHeader("Content-Type", s.contentType);

This says that if no data is in the request, jQuery will not set the Content-Type header and a quick Firebug will show you that the browser defaults to
” text/plain; charset=UTF-8 ”
which results in Rails not decoding the authenticity token properly.

Step 4: Set the Content-Type before you POST
The easy fix is to set the Content-Type in your ajaxSend global event handler resulting in the function shown below:

$(document).ajaxSend(function(event, request, settings) {
    if (typeof(AUTH_TOKEN) == "undefined") return;
    if (settings.type == 'GET' || settings.type == 'get') return;
    settings.data = settings.data || "";
    settings.data += (settings.data ? "&" : "") + "authenticity_token=" + $.URLEncode(AUTH_TOKEN);
    request.setRequestHeader("Content-Type", settings.contentType);
});

Enjoy!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , , | Leave a comment

Ruby on Rails – Skipping validations based on where object is created

I ran into an issue today where I wanted to skip validations based on where an object was created. To be more specific, I wanted to validate strictly if a “venue” was created through my web interface but I want to skip validations when importing venues. The reasoning is pretty simple, I want to require that a user provides a zip code, state, etc. if they use my web interface. However, if I import venues from a website with CRON at some frequency, I want to gather as much venue data as possible and ask users to update it later if needed.

This is not very straightforward in Rails. After all, I do not want to skip validations entirely. I ended up creating a virtual attribute for validations I wanted to skip and checking the attribute before validating:

validates_presence_of :name
validates_presence_of :country_id, :unless => "!validations_to_skip.nil? and validations_to_skip.include?('country')"
validates_presence_of :region_id, :unless => "!validations_to_skip.nil? and validations_to_skip.include?('region')"
validates_presence_of :city, :unless => "!validations_to_skip.nil? and validations_to_skip.include?('city')"
validates_presence_of :zip, :unless => "!validations_to_skip.nil? and validations_to_skip.include?('zip')"
 
validates_existence_of :user
 
# array of validations to skip
attr_accessor :validations_to_skip
attr_protected :validations_to_skip

You can put something like that at the top of your model file. Be sure to protect the virtual attribute so an attacker cannot set validations_to_skip from a web request in cases where you mass assign the model attributes.

To skip validations just do something like this when you create a venue:

v = Venue.new
v.validations_to_skip = ["country","region","city","zip"]
v.name = "A Venue"
v.user = some_user
v.save

What do you think? Anyone have a better way?

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , , | 6 Comments

Back links for your Ruby on Rails application

Here is a nice little helper I wrote to display back links:

def back_link
    link_to "&laquo; Go Back", request.env["HTTP_REFERER"].blank? ? "/" : request.env["HTTP_REFERER"]
end

If you just use the HTTP_REFERER without checking if it’s blank, weird things can happen if someone lands on your page from an email, for example.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , | Leave a comment

Free Market Research Methods Part 1 – Analyzing Public Filings

Last week I attended a Market Research workshop presented by Dr. Dean Chang, Director of Mtech Ventures and Education. Instead of the general advice given at many market research presentations, Dr. Chang put himself in the shoes of a founder and walked us through some motions. This article will cover his take on analyzing public SEC filings.

Why should you bother doing market research?

  • It is expensive to develop products, but it is cheap/free to obtain research.
  • Since your product will most likely change, it is vital that you know your market so that you can successfully guide its evolution.
  • Investors and anyone with whom you may develop a business relationship will probably not take you seriously if you don’t know your market.

What is a 10-K SEC Filing?

Every publicly traded company is required to file an annual 10-K report. This document may have information on a company’s biggest competitors, distribution channels, sales figures, supply chain, and more. Some companies have their 10-K on their company website but we’ll just go to the SEC website and search for it. I use the search option “Company or fund name, ticker symbol, CIK (Central Index Key), file number, state, country, or SIC (Standard Industrial Classification)”.

*Note: While “Annual Reports” may seem to have the information we are looking for, they usually contain lots of marketing fluff and less of the data we are interested in analyzing. Make sure you see something like the following at the top of the report:
10-k_header

Three questions we should answer

  1. Who are your competitors and what are their competing products?
    (Financials, Product Differentiation, Market Strategy, Sales Channel, Resources, Investors)
  2. How big is the potential market? (1M,10M,100M,1B+)
  3. Who are your first customers and how many are there?

The Mock Company

Dr. Chang’s mock company was interested in the video game controller (peripheral) industry. We will answer some of the questions/sub-questions listed above by analyzing a competitor, Logitech’s, 10-K filing. If you search for “Logitech”, a number of filings come up but we are only interested in the 10-K.

Enough introduction, let’s get started.

What does the video game peripheral industry look like?

The 10-K has some information that helps us feel out the industry. We see the following paragraph in the “Industry Overview” section (page 6):

“We also believe that similar industry dynamics and personal peripheral device opportunities exist for non-PC platforms, such as video game consoles, digital music players and home-entertainment systems. As these additional platforms deliver new functionality, increased processing power and growing communications capabilities, we expect demand to increase for add-on, complementary devices connected to these platforms. The product expertise Logitech has developed around the PC extends to these other platforms as well and provides further opportunity for growth and leverage.”

Logitech believes that video game platforms will continue to improve, increasing the size of the video game peripheral market. This may not be ground breaking news but certainly good to hear from a market leader. Continuing to the “Digital Home Environment” section on page 7, we see this sentence:

“Logitech also offers a broad spectrum of products for gamers. We are leveraging our investments in the desktop PC to enhance gaming consoles with our expertise in force and vibration feedback, cordless connectivity, voice input and video input.”

Again, not groundbreaking given the peripherals already out on the market, but it does say that Logitech thinks highly interactive peripherals with feedback are the future.

What competing products and companies should we be aware of?

Skipping ahead to page 12 of Logitech’s 10-K, we can see that Logitech lists their major video game peripheral offerings. We should probably glance over these to make sure we are aware of what they have produced.

While we may already be aware of Logitech’s product offerings, we may not be aware of Logitech’s largest competitors in the Gaming market. On page 16, we find the following:

Competitors for our interactive entertainment products include Intec, Pelican Accessories, Mad Catz and its Saitek subsidiary. Our controllers for PlayStation also compete against controllers offered by Sony.

Obviously we will need to look at those companies if we haven’t already.

How big is our market?

Going back to the “Marketing, Sales and Distribution” section on page 13, we see that Logitech’s 2009 revenue was around $2.2 billion ( $2,208,832 in thousands ). This is great information but we need to find out what portion of that is gaming. Note that the revenue is also broken down by geographic region which is important for marketing purposes.

If we probe around for more financial figures in the 10-K, we find a very useful statement on page 42. We are given Logitech’s net sales broken down by product family. We see that for Retail – Gaming, the net sales is about $127 million. Now we know that we have at least a $100 million dollar market but probably much more since the industry was described as highly competitive and we already noted multiple competitors.

You have probably noticed that Logitech’s 2009 gaming sales decreased from their 2008 sales figure, $146 million. Continuing in this section, we see the following explanation for this decrease on page 43:

Retail sales of our gaming peripherals decreased 13% while units decreased 22% in fiscal year 2009. PC gaming sales decreased 13% with an 18% decrease in units, primarily due to lower sales of our G15 gaming keyboard and our MOMO Racing Force Feedback steering wheel, partially offset by sales of our G25 Racing Wheel. Console gaming sales decreased 12% with a 28% decline in units. The growth in sales of our GT Driving Force steering wheel were more than offset by declines in the sale of PlayStation gamepads and the Driving Force Pro steering wheel.

One piece of information we can grab from this section is that units decreased almost double the amount of sales which probably means customers are willing to pay a high premium for highly interactive peripherals.

What does our sales channel look like?

Skipping back to the “Sales and Distribution” section on page 14, we see:

“Logitech sells through many distribution channels, including distributors, OEMs and regional and national retail chains, including online retailers.” It goes on to list their third party distributors in the USA and from the “Principal Markets” section, we know that “In fiscal years 2009, 2008 and 2007, Ingram Micro Inc. and its affiliated entities together accounted for 14% of our net sales in each year. No other customers individually accounted for more than 10% of our net sales during fiscal years 2009, 2008 and 2007.”

From this information we know how they reach consumers and who their leading distributor is.

Supply Chain

Although not vital to our market research, there is good information about manufacturing in the 10-K which is important to our business strategy. On page 15, we see the following:

“To effectively respond to rapidly changing demand and to leverage economies of scale, we intend to continue our hybrid model of in-house manufacturing and third-party contract manufacturers to supply our products. Through our high-volume manufacturing operations located in Suzhou, China, we believe we have been able to maintain strong quality process controls and have realized significant cost efficiencies. Our Suzhou operation provides for increased production capacity and greater flexibility in responding to product demand. Further, by outsourcing the manufacturing of certain products, we seek to reduce volatility in production volumes as well as improve time to market.”

Here we are creating a gaming company and probably need to understand a production strategy. We may need the aforementioned hybrid model of in-house manufacturing and third-party contract manufacturers to supply our products. The above information should also raise a few questions. Is Suzhou, China the best place in the world to develop video game peripherals? If so, why is Suzhou the best? Maybe Suzhou is just really cheap, or maybe manufacturers in Suzhou specialize in these devices. I’m not sure the reason but it’s worth looking into.

Acquisitions

Another thing to look for in a SEC filing is acquisitions. Getting your technology bought out by the market leader for a large sum of money is obviously a nice exit strategy. Access to an exhaustive list of acquisitions conveniently starts on page 83 of the 10-K. You may want to read a little about the companies to understand what types of companies Logitech is interested in acquiring.

Conclusion

The purpose of this blog post was to demonstrate that 10-K’s can provide a good starting point for your market research. Much of the information is basic, but it is all free information and held to a high standard with regards to accuracy.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in marketing | Tagged , , , , | 2 Comments

Where is my crontab located on Mac OS X 10.5 Leopard?

I googled around for a few minutes with no luck. After probing around my system, here is where I found my crontab file:

Macintosh-2:mls TAmoyal$ sudo ls /usr/lib/cron/tabs/
Password:
TAmoyal

I found it by checking the crontab man page:

man crontab

Where I saw a “FILES” section:

FILES
     /usr/lib/cron/cron.allow
     /usr/lib/cron/cron.deny

And that lead me to probe around the /usr/lib/cron directory. Note that you can view your crontab my with:

crontab -l

but I wanted to view the actual file for debugging purposes.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Random, Software | Tagged , , , , | Leave a comment

Interning empty string error in Ruby on Rails

I don’t like writing short posts about fixing code errors but I think this one deserves a quick shout out. If you get an error in your Rails application that says “interning empty string”, there could be something wrong with an error message in your validations. For example, I had something like:

def geocoding_works_when_geotarget_is_true
    if geotarget and (self.lat == nil or self.lng == nil or self.address_changed?)
      errors.add("Provide better location information so that we can geotarget your reminders.") unless geocode
    end
end

The ‘.’ in my error message caused an “interning empty string” error. I hope I save someone an hour by posting this.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , | 7 Comments

Logging your Rails model (the easy way)

In one of my Rails applications, I have some pretty heavy tasks in my models. I decided to log to different files for two of my models so that I can easily make sure these tasks are performed correctly without going through my application log. I also call some of my model methods with rake tasks so it’s nice to have that action logged. The code below implements a custom log for the SomeClass model.

class SomeClass < ActiveRecord::Base
     LOGFILE = File.join(RAILS_ROOT, '/log/', "someclass_#{RAILS_ENV}.log")
 
     def self.do_something
          log "I am doing something"
     end
 
     def do_something_else
          SomeClass.log "Tried to do something else, but screwed up.", :error
     end
 
     def self.log(message, severity = :info)  
         @model_log ||= ActiveSupport::BufferedLogger.new(LOGFILE)
         @model_log.send severity, "[#{Time.now.to_s(:db)}] [#{severity.to_s.capitalize}] #{message}\n" 
     end
end

This will create separate logs for all of your environments. Notice that I reference the class when I log from an instance method. This is working great for me. Anyone have a better way?

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , , | Leave a comment

Validating multiple fields with one validator in Flex3

I like laying out forms in MXML because it’s easy to read. In a recent project, I had five email fields and it looked something like this:

<mx:Form id="myForm">
	<mx:FormItem label="1." labelStyleName="tenEmailsLabel">
		<mx:TextInput id="email1" width="300" fontSize="13" />
	</mx:FormItem>
	<mx:FormItem label="2." labelStyleName="tenEmailsLabel">
		<mx:TextInput id="email2" width="300" fontSize="13" />
	</mx:FormItem>
	<mx:FormItem label="3." labelStyleName="tenEmailsLabel">
		<mx:TextInput id="email3" width="300" fontSize="13" />
	</mx:FormItem>
	<mx:FormItem label="4." labelStyleName="tenEmailsLabel">
	        <mx:TextInput id="email4" width="300" fontSize="13" />
	</mx:FormItem>
	<mx:FormItem label="5." labelStyleName="tenEmailsLabel">
		<mx:TextInput id="email5" width="300" fontSize="13" />
	</mx:FormItem>
</mx:Form>

I obviously wanted to use one validator for all of the email addresses since they all need to be validated the same way. I couldn’t find any great examples on the internet so I am posting the code to validate multiple fields with one validator.

private function submitForm():void{
     var result:ValidationResultEvent;
     var isValid:Boolean = false;
 
     for(var i:int=1; i<myForm.getChildren().length; i++){
	tenEmailsValidator.source = this["email"+i];
	result = tenEmailsValidator.validate();
	isValid = isValid && ( result.type == ValidationResultEvent.VALID )? true : false;
     }
 
     if(isValid){
	//...submit the form
     }else{
	 Alert.show("You cannot submit the form with errors.");
     }
}

If anyone has a better way to do this, please share!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , | 7 Comments

Configuring Phusion Passenger on a 256MB Ubuntu Slice @Slicehost

I installed Phusion Passenger a few weeks ago to get a production environment up and running for my Rails app. It was super easy to install and felt like magic. I checked off the item on my TODO and moved on. After all it didn’t say “YOUR APP WILL BE SLOW AS HELL IF YOU DON’T READ THIS MANUAL!!!” in their documentation. Well…it was too slow…and here’s how I fixed it.

Referencing the Phusion Passenger User Guide I was able to make changes that made my app run about 10 times faster. If you want to do this in 15 minutes, read this article. If you have a few hours, read through the user guide and experiment. My hardware setup is a 256MB Ubuntu VPS at my favorite hosting company – Slicehost.

The following are global settings I added to my httpd.conf:

RailsSpawnMethod smart
PassengerUseGlobalQueue on
PassengerMaxPoolSize 2
PassengerPoolIdleTime 0
PassengerMaxRequests 1000
RailsAutoDetect off
RailsAppSpawnerIdleTime 0
PassengerStatThrottleRate 5

RailsSpawnMethod smart/smart-lv2/conservative
This can speed up the spawn time tremendously (by as much as 90%) if your app is compatible. However, some Ruby on Rails applications and libraries are not compatible with smart spawning. Set your configuration to smart spawning and if your app works, then you are all good. If not, use another spawning method.

PassengerUseGlobalQueue ON/OFF
Turning this option ON tells Passenger to add requests to a global queue when your Rails instances are busy. As soon as an instance becomes available it will grab a request from the queue. If the option is OFF, each process will maintain its own queue. Localized queues can hurt you if an instance is processing a 60-second request and Passenger adds a 1-second request to the instance’s queue. ( Imagine waiting in a 10 person non-express line at Whole Foods when all you want is a bottle of water ). Therefore, it only makes sense to turn this OFF for the 5% performance gain if all of your requests take about the same amount of time.

PassengerMaxPoolSize INTEGER
This simply says how many application instances Passenger is aloud to Spawn. The default is 6 but the user guide recommends 2 for a 256MB slice so that’s what I went with. More could consume a lot of memory and crash my server. You can use 30 if you have 2GB of RAM.

***PassengerPoolIdleTime INTEGER
This is the minimum time an application instance can be idle without Passenger shutting it down. The default value was 300 which means if my app received no traffic for 300 seconds, it could shut down all of my app instances. The result? A visitor would have to wait way too long when viewing my website. I triple starred this because I think this setting alone will greatly improve your app speed. Note there is an obvious memory trade-off because your application instances will always be running.

PassengerMaxRequests INTEGER
This provides a safety net for memory leaks. It tells Passenger to restart an application instance after it receives a certain number of requests. My app is young so I am keeping it at 1000 requests but ideally you should set this to zero meaning no maximum.

RailsAutoDetect ON/OFF
Turn off auto-detection and tell Passenger exactly which directory contains your Rails app. Do this by adding the following line to your VirtualHost configuration block:

<VirtualHost>
    ...
    RailsBaseURI /
    ...
</VirtualHost>

RailsAppSpawnerIdleTime INTEGER
This is a similar setting to PassengerPoolIdleTime but applied to the ApplicationSpawner server. If the ApplicationSpawner server hasn’t done anything for the specified amount of time, it will automatically shut down. I set this at zero so it will never shut down and therefore take 10% of the time to spawn a Rails process as it would with the ApplicationSpawner server shut down. I would imagine this becomes increasingly important as your PassengerMaxPoolSize increases. Note that if your application is at it’s maximum number of instances allocated (PassengerMaxPoolSize), you may want the Spawner to shut down immediately after it spawns an app instance since the Spawner won’t be used much. Set the value to 1 if this is the case. I will probably do this in the future when my website has a more constant load ( another option is to write a script to periodically hit your Rails app and keep it at a constant load ).

PassengerStatThrottleRate INTEGER
Tell Passenger to only check for restart.txt up to once every 5 seconds instead of once per processed request.

Finally, try to turn on PassengerHighPerformance:

<VirtualHost>
    ...
    PassengerHighPerformance on
    ...
</VirtualHost>

Adding that line to your VirtualHost configuration block will improve your performance but make your Rails app incompatible with some Apache modules. If you turn that on, restart apache, and your Rails app works fine, chances are you are in the clear. Just keep this in mind for the future in case you add more Apache modules.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • MySpace
  • Slashdot
  • StumbleUpon
  • Technorati
  • TwitThis

If you enjoyed this post, make sure you subscribe to my RSS feed!

Posted in Software | Tagged , , , , , | 6 Comments