Skip to content

Mysql issue with rails and antivirus on windows


abstract_adapter.rb:150:in log': Mysql::Error: Can't create/write to file 'C:\MySQL5\tmp\#sql_190_0.MYI' (Errcode: 13)

I had been getting this issue quite a bit recently. The cause actually turned out to be a conflict between McAfee and MySQL. What was happening is that McAfee scans any file that is recently written to, especially those in tmp directories. McAfee reading the file causes the above issue to MySQL. The fix is 2 fold. First, if you have not already, move the location of the MySQL tmp file. You can do this by editing my.ini in your MySQL directory. For Example:

tmpdir="C:/Program Files/MySQL/tmp/"

You may also have to add an exception to your antivirus so that it will no longer scan this file. I had to do this because I was using corporate antivirus. You may have to get your Sysadmin to do this.

Here is a post on mysql’s forums describing this issue as well

testing protected and private methods in ruby

When I was looking for how to test protected an private methods in ruby on the net, I found many sites arguing whether you should, and several methods for doing so. I am of the opinion that if your method contains any logic at all, it should have a test. Some examples of what I consider logic:

Object:

class User
  validates_presence_of :first_name, :last_name, :company_id
  belongs_to :company
  def full_name
    "#{last_name}, #{first_name}"
  end
  def company_name
    company.name
  end
end

Test:

class UserTest < Test::Unit
  def test_full_name
    assert_equal("Gaffney, Mike", User.new(:first_name => "Mike", :last_name => "Gaffney"))
  end
  def test_company_name
    company = Company.new(:name => "CompanyName")
    user = User.new(:company => company)
    assert_equal("CompanyName", user.company_name)
  end
end

This may seem like overkill but when many people are looking at the code it greatly helps communicate intention to others.

Testing:

I also found several methods to test protected and private methods in ruby, so I will cover the pluses and minuses the ones I know of.

Lets say we have a User class and an unassociated comments class. Comments are only attributed to a poster’s full name. There is no direct ID link between comments and users.

class User
  validates_presence_of :first_name, :last_name
  def find_comments
    Comments.find(:all, :conditions => {:poster => full_name})
  end
  protected
  def full_name
    "#{last_name}, #{first_name}"
  end
end

Here are the approaches I’m going to use to test this:

  • Using a Mock to open access restrictions
  • Make single (protected/private) methods public on the tested class.
  • Make all (protected/private) methods public on the tested class.
  • Hybrid Mock Approach
  • Using instance_eval and send
  • send

Using Mocks:
Mocks should be pretty familiar to most developers. Basically you create a class or subclass that the test will use. In our case we are simply opening the access restrictions with a subclass. Our test class looks like this:

class MockUser < User
  def full_name
    super
  end
end
class UserTest < Test::Unit
  def test_full_name
    user = User.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.full_name)
  end
end

Plusses:

  • Simple and familiar to most developers from many languages

Minuses:

  • Can’t test private methods (subclass doesn’t have access).
  • With complicated classes you end up with quite a few mocks for all of the different cases. Managing the mocks becomes tedious.

Make single methods public:
Next we will make use of the runtime nature of ruby to change a function from protected to public. This also works for private methods:

class UserTest < Test::Unit
  def test_full_name
    User.send(:public, :first_name)
    user = User.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.full_name)
  end
end

or

class User
    public :first_name
end
class UserTest < Test::Unit
  def test_full_name
    user = User.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.full_name)
  end
end

Plusses:

  • Lets us directly access the private or protected function.

Minuses:

  • This pollutes the default namespace for all of the other tests. Remember that tests can (and should be able to) run in random order. Take for example:
    1. Full Name is a public function that some other objects use.
    2. We make this function into a protected one and use this method to make it public for testing.
    3. If this new test runs before the tests for the objects using the old public full_name, full_name will still be public even though it is actually protected.
    4. The other tests do not fail but the code will fail during runtime.

Make all methods public:
To save us some time on a big class, we can make all private and protected methods public:

class User
  public *protected_methods.collect(&amp;amp;amp;:to_sym)
  public *private_methods.collect(&amp;amp;amp;:to_sym)
end
class UserTest
  def test_full_name
    user = User.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.full_name)
  end
end

or

class UserTest < Test::Unit
  def test_full_name
    User.send(:public, *MyClass.protected_instance_methods)
    User.send(:public, *MyClass.private_instance_methods)
    user = User.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.full_name)
  end
end

This has the same issues as above but can be done one to make large classes easy to test, especially using the first method.

Hybrid Approach:
This works like the mock example and the previous example combined:

class AllAccessUser
  public *protected_methods.collect(&amp;amp;amp:to_sym)
end
class UserTest < Test::Unit
  def test_full_name
    user = AllAccessUser.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.full_name)
  end
end

This is easy like the previous but does not pollute the namespace. However it cannot be used for private methods.

Using send
Now we will use the built in reflection method to call the protected/private method on the class. This makes use of the fact that protected and private in ruby aren’t really like protected and private in other languages.

class UserTest < Test::Unit
  def test_full_name
    user = User.new(:first_name => "Mike", :last_name => "Gaffney")
    assert_equal("Gaffney, Mike" user.send(:full_name))
  end
end

Plusses:

  • Doesn’t pollute the namespace.
  • All code is right in the test.
  • Works for protected and private.

Minuses:

  • Some people don’t like using send

Summary:
Testing protected and private methods should be done, and ruby makes it much easier than some other languages. My preferred technique is the final one of using send. It is slightly less readable but keeps everything contained in one location.

hiding production database info from source control with capistrano

Whether you are working on an open source app or an enterprise app, it is a good idea to keep the production database connection information out of source control. To do so, add the following to your deploy.rb file:

task :overwrite_database_yml_file do
  run "[ -f /var/rails/#{application}/database.yml ] &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; cp -f /var/rails/#{application}/database.yml #{latest_release}/config/ || echo 'database.yml was not overwritten'"
end
after "deploy:update_code", :overwrite_database_yml_file

And place a database.yml file containing only your production connection information in the same directory as current and shared (eg the deploy_to directory). In fact I typically take the production information out of the config/database.yml entirely.

When deploy runs, if it finds a database.yml file in the deploy_to directory, it will copy it into config before migrating or starting the application. You can use this task to copy other configuration files that you want to keep out of source control as well, but I think its a good idea to only have the database connect info and host names change between deployments.

new has_a block

Pretty simple post, but any ruby object can be post conifged in a line with somthing like:

User.new(:name => “tony”){|u| u.save}

which is great for active record tests.

Or in a bigger example:

@trip = Trip.new{|t| t.save!}
@invite1 = Invitation.new(:user => users(:aaron),
                                   :status => Invitation::STATUS_MAYBE){|i| i.save}
@invite1 = Invitation.new(:user => users(:aaron),
                                   :status => Invitation::STATUS_MAYBE){|i| i.save}

rcov and rails

rcov and Rails
I had the good fortune of attending Rails Conf recently on behalf of the consulting company I work for, Asynchrony Solutions. One of the topics at the great Refactotem tutorial (hosted by the guys from Relevance) was rcov, a code coverage tool for Ruby. One of the things I missed in, or was neglected from, the talk was how to actually run coverage tasks against Rails. So I thought I would share the code to make the test:coverage task that I found with some digging.

Add the following to the Rakefile in the root of your rails app:

require 'rcov/rcovtask'

namespace :test do
namespace :coverage do
desc "Delete aggregate coverage data."
task(:clean) { rm_f "coverage.data" }
end
desc 'Aggregate code coverage for unit, functional and integration tests'
  task :coverage => "test:coverage:clean"
    %w[unit functional integration].each do |target|
    namespace :coverage do
      Rcov::RcovTask.new(target) do |t|
      t.libs << "test"
      t.test_files = FileList["test/#{target}/*_test.rb"]
      t.output_dir = "test/coverage/#{target}"
      t.verbose = true
      t.rcov_opts << '--rails --aggregate coverage.data'
    end
  end
  task :coverage => "test:coverage:#{target}"
  end
end

You can then run rcov on your rails app by running:

rake test:coverage

After this completes, it will output index.html files in RAILS_ROOT/tests/coverage/[units, functional, integration]. There is no overall index file, as, if you read the rake task, it is running rcov separately for each of [units, functional, integration].

Rcov has a few things to work out like showing untested code in modules sometimes, but otherwise it gives you a good idea of sections and branches of your code that are not tested. It’s very easy to set up so why not give it a try. But remember, metrics can only help point out problem spots in your code, they are not a replacement for good coding techniques.

ruby on rails (2.0.1, 2.0.2) and oracle on FC8

Get the following rpm’s from oracle

  • oracle-instantclient-basic-10.2.0.3-1.i386.rpm
  • oracle-instantclient-devel-10.2.0.3-1.i386.rpm

(Note: this should work fine with the newer versions as well)

As root

cd PATH_TO_RPMS
rpm -ivh oracle-instantclient-basic-10.2.0.3-1.i386.rpm oracle-instantclient-devel-10.2.0.3-1.i386.rpm
echo /usr/lib/oracle/10.2.0.3/client/lib/ > /etc/ld.so.conf.d/oracle-instant-client-i386.conf

This last step, the echo, is a bit of magic. The conf files in /etc/ld.so.conf.d are run before each command is invoked to set your library path. The enviroment variable $LD_LIBRARY_PATH overrides these. You won’t see the contents of these files in your $LD_LIBRARY_PATH, but the application will. If your distribution doesn’t have an /etc/ld.so.conf.d directory, you can just add /usr/lib/oracle/10.2.0.3/client/lib to your LD_LIBRARY_PATH inthe /etc/profile, ~/.bash_profile, or any of the other more common places.

Now you need to find the latest ruby-oci8, check http://ar.rubyonrails.com/ and put it in /usr/local/src/

wget http://rubyforge.org/frs/download.php/36134/ruby-oci8-1.0.1.tar.gz
tar -xzvf ruby-oci8-1.0.1.tar.gz
cd ruby-oci8-1.0.1
ruby setup.rb config
make
make install

The previous versions of oci8 and ora instant clients required that you make several symlinks, and was a pain to set up. With the current oci8 and the instant clients on your LD_LIBRARY_PATH, the compile and install should work just fine.

With rails 2.1 out, the activerecord-oracle-adapter is no longer hosted on gems.rubyonrails.org. You can see this with a “gem list -r –source http://gems.rubyonrails.org”. So you have to do the ugly method of directly grabbing the adapter yourself. It is very easy though:

wget -P /usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/  http://svn.rubyonrails.org/rails/adapters/oracle/lib/active_record/connection_adapters/oracle_adapter.rb

That’s it. Just remember to make sure that you grab the right versions of everything.

laying out sections using content_for

For the new style changes for confabulus, I made use of the content_for capabilities in rails. The currently has two sections, main and sidebar. content_for makes implementing this quite easy. In your layout file (example application.html.erb under app/views/layouts), you use a <%= yield :sectionname %> to place each of the sctions. Here I used <%= yield :sidebar %> to include my sidebar section. :sidebar is just the name I chose for the section.

<div class="right" id="main_right">
<div id="sidebar">
<%= yield :sidebar%>
</div>
</div>

Then in the view for the page, you need to define the content for each section, for sidebar I have:

<% content_for :sidebar do %>
<h2>Please Login</h2>
<div class="content">
... full view code omitted ...
<% end %>

So my views are of the form of:

<% content_for :sidebar do %>
... sidebar content goes here ...
<% end %>
<% content_for :main do %>
... main content goes here ...
<% end %>

You can do this for an arbitrary number of sections.
One thing to note is that if you are converting and forget to put a content_for block around the code, your view will render empty.

New Layout, Contact Lists, Registration/Forgot Password Added

I just pushed out a large upgrade that I did while on Jury Duty and at Rails Conf. New features include:

  • New design (Much cleaner and easier for me to group elements)
  • Removed extra pages for managing cars, flights, and hotel rooms (I’m trying to keep all of the main work flow on one page.
  • Added the ability to maintain a contact list. Contact lists are a grouping of people who you’ve already been on a trip with. So if you do the same type of trip with the same people all the time, you can just add all from that contact list. Contact lists are managed on the user’s homepage and invitations are sent from the invite page (linked from the trip overview page).
  • Registration: The register link is now visible and now works. Also, if a person wants to change their info from an invitation, it will register them as well.
  • Forgot Password: if you forget your password, you can now click a link and get an email that will let you reset it. This was a big stopping block to going public.