Archive for August, 2007

class_table_inheritance with acts_as_taggable

Friday, August 24th, 2007

If I have:

class Product < ActiveRecord::Base
acts_as_taggable
end

class Subproduct < Product
class_table_inheritance
end

def find_tagged_with!(list)
find_by_sql([
"SELECT #{table_name}.* FROM #{table_name} " +
"WHERE #{table_name}.#{primary_key} in (" +
" SELECT taggable_id FROM taggings, tags " +
" WHERE tags.id=taggings.tag_id " +
" AND taggings.taggable_type = ? " +
" AND tags.name IN (?) " +
" GROUP BY taggable_id " +
" HAVING count(tags.id) >= ? ” +
” )”,
acts_as_taggable_options[:taggable_type], list, list.to_a.length
])
end

The problem is that:

Subproduct.find_tagged_with! (‘test’)

returns all the Products tagged with ‘test’ rather than all Subproducts. So I tried:

class Product < ActiveRecord::Base
end

class Subproduct < Product
class_table_inheritance
acts_as_taggable
end

but that does the same thing. The problem boils down to the find_tagged_with! method using acts_as_taggable_options[:taggable_type] which is defined as class_name_of_active_record_descendant elsewhere in the acts_as_taggable plugin. The solution is to rewrite find_tagged_with! to :

def find_tagged_with!(list)
find_by_sql([
"SELECT #{table_name}.* FROM #{table_name} " +
"WHERE #{table_name}.#{primary_key} in (" +
" SELECT taggable_id FROM taggings, tags " +
" WHERE tags.id=taggings.tag_id " +
" AND taggings.taggable_type = ? " +
" AND tags.name IN (?) " +
" GROUP BY taggable_id " +
" HAVING count(tags.id) >= ? ” +
” )”,
self.class.to_s, list, list.to_a.length
])
end

This should work even for classes that aren’t using class table inheritance since it’ll just use the class name.

Refs: http://wiki.rubyonrails.org/rails/pages/ActsAsTaggablePluginHowto

Class table inheritance problems

Thursday, August 23rd, 2007

I’ve successfully implemented class table inheritance but came across a problem for one instance. I’m using this to simplify my database structure. I have one model that I’m using it for that has no additional properties other than the stuff its inheriting. I’m doing this to keep everything consistent with the architecture. For instance:

create_table :products do |table|
table.column :name, :string, :null => false, :limit => ‘50′
table.column :description, :text, :null => false
table.column :type, :string, :null => false, :limit => ‘50′
table.column :default_photo_id, :int, :limit => ‘11′
table.column :user_id, :int, :null => false, :limit => ‘11′
end

create_table :anvils do |table|
table.column :product_id, :int, :null => false, :limit => ‘11′
end

So anvils just inherits all the data from products and doesn’t really add to it. The problem occurs when trying to save a modified anvil record. I end up with an error in the SQL because it’s trying to do something like:

UPDATE anvils SET WHERE product_id = 1

But there aren’t any local attributes to update on the anvils table. I could redo that one structure to not use class table inheritance but that would cause more of a headache than its worth. I could try to hack a solution using the class table inheritance plugin but that didn’t sound fun either. The easiest solution, and I’m not really proud to admit this, was to simply add a junk tinyint(1) column to the anvils table. That way when the update sql runs it won’t cause a syntax error.

I was looking for a way to do anvil.parent.save or something similar but couldn’t find a way to do that. That’d be a much better solution so if anyone figures that out please let me know.

Online uml and er diagramming tool

Wednesday, August 15th, 2007

I’ve been searching for a free uml diagramming tool for Linux for a long time. There are plenty of options but nothing really stable or good enough for what I need it for. I stumbled on Gliffy today. Its an online diagramming tool written in Flash. Best of all you can use it free given some minor limitations. I tried it out and its exactly what I’ve been looking for to help collaboration between remote developers. I definitely suggest you check it out.

Computational justification for the use of meta descriptions and keywords

Sunday, August 5th, 2007

Search engines have a lot of work to do crawling the web constantly. There must be a lot of computational power required to constantly parse html pages and grant rankings for the enormous number of sites now out there. As such, it makes perfect sense for a search engine to want to speed up that process in any way it can. The use of meta descriptions and meta keywords help search engines speed up their algorithms by not having to parse your entire page. It just has to read the header information and it can move on.

The problem is that people realize this so they do a bit of keyword stuffing to try and give them a boost. Search engines don’t simply ignore your page when you use keywords and descriptions. They just don’t parse the entire page as often if you’re meta keywords and meta descriptions match the content on your page. If they don’t match, of course your site will require more processing because they have to parse the entire page and not just trust your keywords and descriptions.

The use of meta tags saves search engines tons of time. Since you do them a favor, they do you a favor and you get higher rankings.

Recursively removing .svn directories

Saturday, August 4th, 2007

I’ve found on numerous occasions that I needed to recursively remove all the .svn directories from a checked out copy of my code. I’ve always just googled it and found the command quickly that way since I don’t know how to do it off the top of my head. I consider myself pretty fluent in Unix systems but there are just some commands that I’ve never really dug into much. Here is what google turns up:

find . -name .svn -print0 | xargs -0 rm -rf

How does that really work? Well, we first have to understand how the first command works before the pipe:

find . -name .svn -print0

If you omit the ‘-print0′ it simply dumps all the .svn directories it finds recursively from the current directory. The ‘-print0′ works in conjunction with the ‘-0′ option inside the pipe. The ‘-print0′ basically doesn’t return a new line but rather formats the output in a way that you can process each element of the results using the ‘xargs’ command.

xargs -0 rm -rf

That command really won’t do much unless you pass it something, usually through the pipe. So, ‘xargs’ just takes the output from the find command and process each element of the results by passing it to the command specified. In this case it is ‘rm -rf’. So combined we have ‘find’ getting all the results and piping the whole thing to ‘xargs’ and ‘xargs’ passes each element of that set to a ‘rm -rf’ command. Its fairly simple when you break it down.

Class table inheritance in Ruby on Rails

Friday, August 3rd, 2007

In my previous post I wrote about trying to get class table inheritance working in Rails. I passed by the hack and went with the plugin which ended up not really working right. I revisited the class table inheritance hack and actually got it working. I pretty much just dumped that code into a plugin so all you have to do is:

spaghetti.rb

class Spaghetti < Noodle
class_table_inheritance
end

noodle.rb

class Noodle < ActiveRecord::Base
end

One thing that did trip me up at first was that the spaghettis table can't have an 'id' column for a primary key or you end up with some strange stack overflow errors. The noodles table also needs a 'type' varchar column to store the class names of the rows its storing. Even pagination works when you explicitly state what tables you're conditions are using as in:

@spaghetti_pages, @spaghettis = paginate :spaghettis,
:conditions => [ "noodles.length_in_inches = (?)", 10],
:per_page => 10

Download the class_table_inheritance plugin

Inheritance in Ruby on Rails

Friday, August 3rd, 2007

I have a Rails project I’m working on that seems to be best suited for class table inheritance. Conceptually it will greatly simplify the database and reduce tons of code. There will be a performance hit due to the extra joins. I think that will be manageable though and the simplification of the entire site architecture will make it well worth it. The problem is that class table inheritance isn’t currently implemented in Ruby on Rails and requires a hack to make it work. I’m weary about implementing this hack mostly for long term maintainability since its such a crucial aspect of the site’s architecture. Ideally, class table inheritance will eventually be built into the Rails core but who knows when that’ll happen.

Then I found the inherits_from plugin which made me a bit more comfortable so I tried it out. It works in a very primitive way so long as I’m not using any conditions in my find commands. For instance if I had a product that stored a name and a car table which is going to inherit everything from the products table:

car = Car.find(:first)
car.name

car.name works fine and it would be great if that’s the only way I ever needed to use it. The problem is when I try to toss some conditions into the mix that are conditions against the parent model. So if my products table also had color and I wanted to do something like:

car = Car.find(
:first,
:conditions => ['products.color = (?)', 'blue'])
car.name

It doesn’t work because its not doing a join but rather 2 separate queries. 1 query for the car table to get the product_id and the other on the products table. Using:

car = Car.find(
:first,
:conditions => ['color = (?)', 'blue'])
car.name

Doesn’t work either. The solution? One option is to extend ‘find’ to make it recognize when its supposed to do a join instead of 2 queries. I’m not looking forward to hacking that mess up cause it opens a big can of worms. For example, how would it handle pagination with conditions as well? I’m not using the plugin. After my getting to that point with the plugin I decided to take another look at the first hack I linked to and see how much effort it really is going to take to get this thing working. I might just end up scrapping class table inheritance altogether and accept the big messy database structure and code redundancy that will ensue.

nil.[] error when using Rails migrations

Thursday, August 2nd, 2007

I just had a little trouble with Rails migrations. I was trying to add a column to a database table in the migration using:

add_column :condos, :product_id, :int, :null => false, :limit => ‘11′

The syntax seems ok at first glance but it resulted in the following error:

– add_column(“condos”, “product_id”, “int”)
rake aborted!
You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
/usr/lib64/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/abstract/schema_statements.rb:272:in `type_to_sql’
/usr/lib64/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/abstract/schema_statements.rb:122:in `add_column’

The type_to_sql should have given it away to me but I overlooked it at first and spun my wheels trying to figure out what was wrong. As it turned out :int is not right and I need to use :integer instead.

The success of Webster's Classroom

Thursday, August 2nd, 2007

Over this past summer I’ve been working on a project for my wife Laura. She’s the technology teacher at school and needed an easy way for her teachers to create their own classroom webpage. Before Webster’s Classroom she had to manually create every teacher’s page and ftp it to a county server downtown. Needless to say, no one had websites.

Webster's Classroom 1.0

We created an easy way for teachers to do this by using Webster’s Classroom. Best of all, we’re offering it to teachers absolutely FREE. Laura got a warm reception from her peers when she demonstrated our software during the first few days of school. A number of teachers have already used our software to setup their own customized classroom webpage and appear enthusiastic about using it throughout the year. We have many plans for additional features in the next year. So far we are getting very positive feedback on the site and we are excited to add new features to the site. We will be aggressively marketing it at the software matures over the coming months and I’ll be sure to post updates every so often on it.