Obie and Carlos are the new taggable guys!

Posted by dema Fri, 28 Oct 2005 01:50:00 GMT

I am happy to make the official announcement that fellow rubyists and Thoughtworkers Obie Fernandez and Carlos Villela (Brazil!) are the new maintainers of the acts_as_taggable mixin. Both are very active in the Ruby & Rails community and outstanding coders as well. Finally, they’re also very nice guys. ;-)

I want to thank all of you who volunteered to take my place in keeping the taggable thing rollin’.

I must say that I am very confident in leaving my little contribution to the Rails community in such competent hands.

I’ve already passed on to them all code, requests, suggestions and contributions from acts_as_taggable users out there and they’re organizing to get things moving once again.

It’s also nice to see that the acts_as_taggable gem has now been downloaded more than 460 times. Keep it up Obie and Carlos! I know you will. ;-)

Posted in  | Tags , ,  | 3 comments | no trackbacks

Life, Rails 1.0, Plugins and Acts As Taggable

Posted by dema Thu, 20 Oct 2005 01:58:00 GMT

Over a month without posting usually means something really big happened on the life of a blogger. Maybe I got hit by a bus and am writing this from my celestial notebook, but no, not yet.

This will sound a bit shocking to my fellow readers and core hackers out there, so I’ll tell you at once: I took a management job.

And this will sound even more outrageous: I am enjoying it!

In the past, as the CIO/CTO of my own start-up, I frequently alternated between management and hacking depending on the current size of our team and our development needs. So, I’ve always had a great deal of interest in getting good at management. Peopleware is my bible on that area and since I’ve read it, I see good managers much more as team motivators and facilitators than bosses. I’ve also just got Ship It! and Behind Closed Doors, a excellent software management combo from the pragmatic guys.

Anyway, there’s a LOT to be done in the company that I am working now. We’ve got great human material there and I am truly excited in seeing those folks really shine once we get things rolling smoothly.

And that kinda of explains why time has been such a precious (and scarce) thing for me in these last weeks.

To conclude this part, do expect some software management articles on Y.o.m.b.a.r. from now on.

Now, let’s talk about Rails, shall we?

I was really, really happy to see the release notes for Rails 1.0 Release Candidate, for mainly 2 reasons:

First, while there are, undoubtly, some huge improvements in the upcoming 1.0, there’s not that many functionality additions, and that’s a GOOD THING. It confirms that Rails is rapidly maturing and at the same time not falling for the ‘featuritis crisis’, which doomed several other well known web frameworks out there. 1.0 is mostly about internal restructuring, bug fixing and small improvements. DHH has managed to keep steering his boat in the right direction, despite all the craze and hype around it.

The second reason is purely egocentric. I’ve just loved seeing acts_as_taggable being used as the example for the new plug-in architecture. ;-) Release notes quote:

For a while, we were struggling with what to do with cool extensions like acts_as_taggable. Clearly, it was good stuff and a high usable feature by many. (…)

This kind of thing really makes me miss those good days of Ruby hacking and being part of this great community.

And, speaking of that, I am actually looking for someone to replace me and take on development of the act_as_taggable library. I’ve been holding back on some nice suggestions and actual code contributions from users out there and I would really like to see this going forward. But I have no time to do it myself anymore.

Let me know if you have interest in being the new taggable guy, ok?


PS: Last awful truth of the day: did I mention I am managing a Java development team? Oh boy, I’ve got my soul sold to the devil. ;-)

Posted in ,  | Tags ,  | 11 comments | no trackbacks

GUID/UUID as primary keys in Rails

Posted by dema Wed, 14 Sep 2005 04:59:00 GMT

There´s been already a couple of discussions on the Rails list about what would be the pros and cons on using GUIDs/UUIDs as primary keys ( instead of auto-increment integers) in ActiveRecord models. Let me sum it up:

Pros

  • Data Portability: it is much easier to do import/export/sync operations of multiple tables using GUIDs as PKs, specially if there are many relationships between the tables. Also, if your app (such as the one I am currently helping to build) uses distributed databases, this becomes a critical issue.
  • DBMS Portability: you don´t depend on a specific database implementation of autoincrement keys or sequences, which can vary quite a lot for different DBMSes.
  • Known ID upon object creation: You don´t need to wait until the object is persisted to know its ID. You get to know it as soon as the object is instantiated and that can make things a bit easier sometimes, specially when doing equality comparisons between saved and unsaved records.

Cons

  • Performance: if you’re using a Windows-style GUID, then obviously, a char(36) is slower to look up than a int(11), although I don´t think there is significant hit on most scenarions. (Care to prove me wrong on this?)
  • Ugly URLs: Rails apps show object IDs on URLs, and let´s face it, GUIDs are ugly as hell.
  • Chance of Duplicated GUID: if you use a decent or RFC 4122 compliant generation algorithm, then this is a non-issue.

Anyway, as I mentioned before, the project I am currently working on makes heavy use of distributed databases – not the typical Rails app scenario, I know – and as so, using GUIDs for PKs is critical for us.

I would really like to hear some war stories (good and bad) on usings GUIDs for primary keys in your databases, as well as sound opinions on the subject.

So, you want to try it out for yourself? How about this: drop this guid.rb file in your /lib folder and add require ‘guid’ to your environment.rb. After that, for the models you wish to use GUIDs as primary keys, define their id columns as char(36) and drop the guid macro inside your model like this:


class MyNiceModel < ActiveRecord::Base
  guid

  # other parts of your model here
  ...
end

Then, if you´re kind enough, share your experience of using this Guid thing with us, ok?

UPDATE: I´ve updated the guid.rb file to fix a very basic bug, so please download it again. I´ve also added a :column option, so you can specify a primary key column name different from ‘id’ as this:


class MyNiceModel < ActiveRecord::Base
  guid :column => 'guid'

  # other parts of your model here
  ...
end

NOTE: The Guid Extension for ActiveRecord provided here is experimental and should not be used in production/critical environments. Although the chance of GUID duplication is pratically zero, the generation algorithm is very simplistic and non-conformant with RFC 4122, so use it only for experiments.

Posted in  | Tags , , ,  | 13 comments | no trackbacks

Acts As Taggable Gemified!

Posted by dema Tue, 13 Sep 2005 04:26:00 GMT

After a brief discussion with DHH on whether it would be better to try to make the “acts as taggable” mixin a patch or make it an independent library, we´ve came to the conclusion that the latter would be the wiser choice.

And so, I´ve asked Tom Copeland for a little room in his wonderful Ruby Open-Source Project Plaza, also known as RubyForge and now the “acts_as_taggable” macro has a brand new home at http://rubyforge.org/projects/taggable/.

Also, the most up-to-date online RDocs are available at http://taggable.rubyforge.org/.

Installing and updating the library is now as easy as gem install acts_as_taggable.

And after that, just add a require_gem ‘acts_as_taggable’ line to the ‘environment.rb’ file of your Rails app, and get taggable!

This new version also has some nifty additions for finding related tags and records that share a similar set of tags. Really useful for building those ‘Related’ and ‘See Also’ boxes.

Thanks again to Peter Cooper for all the tricky SQL part.

Posted in  | Tags ,  | 15 comments | no trackbacks

Tag counting anyone?

Posted by dema Tue, 06 Sep 2005 15:10:00 GMT

There´s already a new version of the acts_as_taggable mixin available and look what it is capable of now:

# Gets the top 10 tags for all photos
Photo.tags_count :limit => 10 # => { 'beer' => 68, 'wine' => 37, 'vodka' => '22', ... }

# Gets the tags count that are greater than 30
Photo.tags_count :count => '> 30' # => { 'beer' => 68, 'wine' => 37 }

If you just got here by accident and want to see other examples, check out previous articles on the same subject:

You can download it from the same place as before.

And did you know it now includes complete RDoc documentation ?

I promise this is the last release of the week. ;-)

Posted in  | Tags ,  | 12 comments | no trackbacks

Tagging on Steroids with Rails

Posted by dema Sat, 03 Sep 2005 09:52:00 GMT

My last article about tagging on Rails attracted quite a lot of attention, much due to its appearance on the official RoR weblog, to my complete surprise and delight.

Nevertheless, a few heated discussions and criticisms appeared around it and, overall, it was very constructive, turning out to be a quick and effective way to gather quality feedback from smart people that are in need for this kind of functionality.

A lot of great suggestions and requests were made for improvements and now I am very excited to present the new features of the acts_as_taggable mixin. Here are some examples:


class Photo < ActiveRecord::Base
  acts_as_taggable
end

photo = Photo.new

# standard tagging with a string
photo.tag 'brazil rio beach'

# tagging with an array
photo.tag ['south america', 'soccer']

# tagging with a different separator
photo.tag 'beautiful women, babes, hot chicks', :separator => ','

# tagging with a Proc separator
photo.tag '2001..2005', :separator => proc { |s| eval(s).to_a }

# suppose your tags_photos join table has attributes 
# and you want to set them while you tag
photo.tag 'samba', :attributes => { :tagged_at => Time.now }

# Let´s do some tag searching now
# Photos with soccer OR rio
Photo.find_tagged_with :any => 'soccer rio'

# Photos with beach AND women (combo tags)
Photo.find_tagged_with :all => 'beach woman'

# Using a different separator 
Photo.find_tagged_with :all => 'beach+woman', :separator => '+'

Ok, that´s all very nice, but it only works for global tagging with simple has_and_belongs_to_many join tables right? What if I want to use a full model for relating objects and tags, so that I can also use other mixins with it such as acts_as_audited, acts_as_lists, and also have access to ActiveRecord’s callbacks, timestamping and so on?

Good news, now you can! Show, don´t tell!

class Photo < ActiveRecord::Base
  acts_as_taggable :join_class_name => 'TagPhoto'
end

# The join class specified above is created automagically,
# but we can still open it and extend it at will
class TagPhoto
  acts_as_list :scope => :photo
  belongs_to :user

  after_save :do_some_stats
end

# I can do some nicer things now
photo = Photo.new

# If I used the acts_as_audited mixin, 
# I don´t even need to do the attributes part
photo.tag 'rio sun hot', :attributes => { :user_id => current_user.id }

# Now, I wan't to find all photos in which the 1st or 2nd tag is 'rio' 
# (remember that the acts_as_list works, so tags are sorted for each photo)
Photo.find_tagged_with :any => 'rio', :conditions => 'tags_photos.position = 1 OR tags_photos.position = 2'

# Or 'brazil' by some user
Photo.find_tagged_with :any => 'brazil', :conditions => 'tags_photos.user_id = 1' 

I think it all turned out pretty nice, don´t you think?

A word of caution: I still haven´t properly documented all features and options of this new version, but I´ll do that in the next couple of days. Also, I don´t think the unit tests I wrote for it are covering all possibilities right now, so don´t expect a bug-free version as of this moment.

But if you´re brave enough to give it a try on your project, I´d be very happy hear from you and receive bug-reports.

A little warning for those who were using the first version: the previous version had a default behavior of clearing the tags collection on the #tag method. This has changed for this version. The default behavior now is to append the tags to the existing ones. You can still clear the existing tags using the ’:clear => true’ option. Also, the #tagged_by? method changed to #tagged_with?, so a little find & replace might be necessary.

Oh, I almost forgot! You can download it here.

To use it, just put it in your /lib folder, under your Rails app root and add a require ‘taggable’ to your config/environment.rb file.

You also have to have a ‘tags’ table with a ‘id’ as a primary key and a ‘name’ varchar column and a Tag model on your db schema/application. You can actually change the name of those if you´d like and specify them using the :collection, :join_table, :tag_class_name options, please see the RDoc comments included in the source. You also must have join tables, such as ‘tags_photos’ with foreign keys ‘photo_id’, ‘tags_id’, for example.

Happy tagging!

UPDATE: A bug that would prevent tagging unsaved objects has just been fixed, thanks to valuable help from technoweenie. Please download the latest version from the same location as before. The bug was caused by me improperly touching private parts of ActiveRecord ;-), so remember boys & girls, always talk to your peers thru the public interfaces.

UPDATE 2: There´s a brand new, more stable version available that features an improved API and also includes complete RDoc documentation.

Disclaimer: this mixin was extracted from the work I am currently doing together with a great team for the syncPEOPLE project, which is about to have its presence on the Web soon.

Special thanks to Peter Cooper for the tricky SQLs that allows tag searching and tag combos.

Posted in  | Tags  | 39 comments | 2 trackbacks

Easy Tagging with Rails

Posted by dema Sat, 27 Aug 2005 07:48:00 GMT

UPDATE: See the improved version in action here.

There’s been a lot of buzz about tagging lately (also known as folksonomy) in the websphere. It seems that every Web 2.0 website is doing it these days.

So, why be left behind?

There’s a lot of different data models to do tagging, but the most normalized and flexibe way is to use one unique table for holding all tags, and then using join tables between your taggable objects and the tags table for creating many-to-many relationships. Something like this:

photos <-> tags_photos <-> tags
message <-> tags_messages <-> tags

You may be thinking that it’s just too cumbersome to have such complex data structures for holding some lousy keywords? But before ranting about that, here’s some good info on the subject.

And if you’re doing Rails, you also may be thinking: ok, if I go with that, I’ll end up having a lot of has_and_belongs_to_many declarations in my taggable objects, as well as having to manage the many-to-many collections when adding tags to them, doing such things as checking for existing or duplicated tags, stripping spaces, and so on.

Wouldn’t it be nice if you could do all that just by doing this:

class Photo < ActiveRecord::Base
  acts_as_taggable
end

elephant = Photo.find(4437)
elephant.tag 'zoo animals nature'

elephant.tagged_with?('urban') # => false
elephant.tags.size # => 3
elephant.tag_names # => [ 'zoo', 'animals', 'nature' ]

Ruby and ActiveRecord can make life so much easier, right? Just grab the acts_as_taggable mixin here.

(This is also available as a candidate patch)

Little disclaimer: this mixin was extracted from the work I am currently doing together with a great team for the syncPEOPLE project, which is about to have its presence on the Web soon.

Posted in  | 27 comments | 4 trackbacks

Typo Upgrade

Posted by dema Fri, 26 Aug 2005 07:32:00 GMT

After a few bumps and tweaks (mainly related to migrating the old data), I managed to get Y.o.m.b.a.r. running on the latest trunk version of Typo 2.5.

The previous versions of this blog had some code customizations that are no longer needed, since the new version makes it possible to do the same stuff only by using the new administration features, specially the very cool sidebar components.

I took a good look on the code, and, boy, what a beautiful plug-in architecture they’ve got, really pushing Rails to its limits, APIs, components, it’s all in there.

Not too mention all the AJAX/drag-n-drop goodness of the new administration screens.

Congratulations to Tobi and all the Typo team. It must be funny for Tobi to see how Typo has evolved and got wide adoption, since he had so few ambitions with it at the beginning.

Yes, open-source magic.

Posted in  | no comments | no trackbacks

The technology filter

Posted by dema Thu, 25 Aug 2005 02:39:45 GMT

I know a lot of people don’t like or strongly disagree on what Paul Graham writes, he may sound too elitist most of the time, but I have to confess I enjoy reading his essays very much, I even bought his Hackers & Painters book.

To me, one of the best articles he wrote was the (now classical) Great Hackers essay, which also is available in a very good audio version at IT Conversations.

One of the most controversial affirmations of this essay is when Paul says:

“But when you choose a language, you’re also choosing a community. The programmers you’ll be able to hire to work on a Java project won’t be as smart as the ones you could get to work on a project written in Python.”

I tend to agree with this affirmation, but maybe a little tweaking on the way you say it would have avoided much of the hatred around it. It is not that you can’t find great hackers working on mainstream technologies such as Java and .NET, I personally know a few geniuses that work on Java and .NET. But since it’s a much larger audience, the average quality of the crowd tends to go down, mainly because the entry barriers on those platforms are so low, with all the money involved, marketing, tools and industry-backed promotion.

Now, when you get to technologies that survive much more (or purely) due to its technical merits than promotion efforts, such as Python, Ruby or Smalltalk, you start to realize that the people that compose the communities around those platforms have something in common. I would dare to say that they are at a higher level of evolution in a technical sense, they surpassed certain stages of technical understanding to be able to realize that the lack of good tools or books or training are greatly compensated by the intrinsic qualities of the exquisite languages they now work with and that they can do a lot more with those languages using a simple text editor than using powerful 2-DVDs IDEs. But most importantly, they have more fun.

Going one step beyond technical qualities, I also find that people on these more restricted communities tend to be (on average, please) smarter than the ones in mainstream communities in other aspects too. They have a more refined sense of beauty and aesthetics (better taste), they are more pragmatic, they communicate better and are connected to wider realities and also have more sense of humor.

For instance, I am working in a Rails project right now where the whole team, including the client himself, is made of those kinds of people. I know it’s unusual to work with a client with deep technical knowledge, but I got lucky this time. He chose Rails over more established options such as ColdFusion (which he personally masters) and this alpha-geek attitude reflects on other areas of his personality as well, such as having flexible work hours, using web-based collaboration tools and even doing podcasts.

I was truly delighted to hear from him such motivating phrases as “If we build anything that might be useful to other people, let’s give it back to the community” or “Sure, I’d be glad if you blogged about the project” or simply “I completely trust your judgment on that”.

Yes, my client encourages me to blog and to do open-source development. I wonder what my odds would be of having the same thing if I was working on a .NET “enterprise” project for a big company. Don’t laugh please. :-)

Posted in , ,  | 4 comments | 1 trackback

Taming FastCGI+Apache2 on Windows

Posted by dema Tue, 23 Aug 2005 23:57:09 GMT

I’ve had my share of wrestling with Apache2 and FastCGI to get my Rails (version 0.13.1) apps running on my Windows XP box (not to mention my attempts with Lighttpd). Long hours trying to figure out configuration trickery for things that were not primarily designed to run on Bill’s OS.

But I have good news, I finally managed to get it working well enough these days. And to spare you, who are in the same boat, the same trouble, here are some useful tips.

First, let’s cover the basics:

Now, make sure you have mod_fastcgi.so in your Apache2\modules folder and that you have mysql.so and fcgi.so in your ruby\lib\ruby\site_ruby\1.8\i386-msvcrt folder.

Start a normal IRB session and type require ‘fcgi’ and require ‘mysql’. You should get ’=> true’ as a response from both.

Make sure you have these directives in your Apache2 httpd.conf file:

LoadModule fastcgi_module modules/mod_fastcgi.so

<IfModule mod_fastcgi.c>
  AddHandler fastcgi-script .fcgi
</IfModule>
Now, a typical Virtual Host entry that should point to your Rais application would look like this:

  <VirtualHost *:3000>
    DocumentRoot c:/dev/myrailsapp/public
    ErrorLog c:/dev/myrailsapp/log/server.log

    <Directory c:/dev/myrailsapp/public/>
      Options ExecCGI FollowSymLinks
      AllowOverride all
      Allow from all
      Order allow,deny
    </Directory>
  </VirtualHost>

Remember to add a ‘Listen 3000’ directive as well up in the httpd.conf file if you’re going to use that port.

Now, in your dispatch.fcgi file that resides in your Rails app public\ folder, make sure the shebang line is correct:

#!c:/ruby/bin/ruby

Finally, in your .htaccess file that resides in the same folder as the dispatch.fcgi file, change the rewrite rule that points to the ‘dispatch.cgi’ file and replace it with ‘dispatch.fcgi’.

So far, pretty standard stuff. Now, let’s get a little fancier. To make Apache2 more conservative when running on Windows, go back to the httpd.conf file and add these lines:

EnableSendfile Off
EnableMMAP Off
Win32DisableAcceptEx

Also, in the same file, you should dumb down the FastCGI powers (we are talking about a development machine, right?), and so, you need to limit the number of processes it is allowed to start, otherwise, it will just take too long when starting your app, and it will consume too much memory as well, and that might cause you trouble.

For that, you need to add the following directive to keep FastCGI on a minimum resource level usage:

FastCgiConfig -maxClassProcesses 1 -maxProcesses 1 -minProcesses 1 -processSlack 1

If you wish (or need), you might increase those numbers a little bit, but I don’t recommend going over 5 processes.

And then to the trickiest part. If you’re using native Ruby bindings such as fcgi.so or mysql.so or iconv.so or RMagick.so, those bindings usually rely on native DLLs that reside in folders such as Windows\System32 and others. And that is normally a source of problems and error messages such as ‘unitialized constant Mysql/Iconv/...’.

The problem is that FastCGI server processes doesn’t get any (yes, none, zero) of the environment variables of your system, being them either at machine-level or user-level. And that includes RAILS_ENV, RUBYOPT and more importantly the PATH variable. And without the PATH variable all native extensions that rely on DLLs outside the ruby\bin directory will fail. I discovered this after very long hours as you may imagine.

And don’t bother trying to use SetEnv or PassEnv directives. They won’t work at all with FastCGI.

The only solution is going back to the FastCgiConfig directive and adding all your environment variables using the ’-initial-env’ option. So, my complete FastCgiConfig directive now looks like this:

FastCgiConfig -maxClassProcesses 1 -maxProcesses 1 -minProcesses 1 -processSlack 1 \
-initial-env PATH="c:/ruby/bin;c:/windows/system32;c:/windows;C:/mysql/bin;C:/Progra~1/Common~1/GTK/2.0/bin"  \
-initial-env RUBYOPT=rubygems \
-initial-env MAGICK_CONFIGURE_PATH=c:/ruby/lib/ruby/gems/1.8/gems/RMagick-win32-1.7.0-mswin32/config

Important: always use ”/” on paths and always use the 8.3 short names when the path contain spaces.

With (all) this, I am able to use FastCGI very reliably and with excellent performance and also make all native bindings that I use (Iconv, Mysql, RMagick, and others) to work as well.

Originally, I tried all this to see if the UploadProgress helpers would work on Windows, since it requires FastCGI, but even then, it didn’t. I know I am supposed to allow more than 1 FastCGI process to make UploadProgress work and I did try that, but it didn’t work anyhow. So, if you manage to get it working, please, let me know how you did it! ;-)

An important tip to diagnose problems is that, if you get the infamous “Application Error – Rails application failed to start properly” message, there is usually something going wrong on in your ‘environment.rb’ file (or the files it is requiring). Rails won’t be able to present you any useful debugging information unless all of the ‘environment.rb’ gets executed right. So, it’s pretty hard to track the cause of problem in this situation, but normally, this is caused by some custom ‘require’ that you added to the file. The standard ‘environment.rb’ that gets generated from Rails is safe.

Remember to always restart Apache2 when you change the httpd.conf file (duh! But I did forget sometimes! ;-)).

I hope you can manage to get this combo working on your WinXP box with all this info. Let me know if you have any trouble, and I’ll try to help.

Posted in  | 22 comments | 1 trackback

Older posts: 1 2 3 4