Typo Upgrade from Hell
mysqldump -u USER -p PASS -h HOST > clog.mysqlI copied that over to my macbook where I loaded the typo gem, created a skeleton blog app and loaded the db for the migrations. Still no luck, I could not get typo to load at all on my mac. I kept getting this error:
[BUG] cross-thread violation of rb_gc() ruby 1.8.6 (2008-08-11) [universal-darwin9.0]I have ruby 1.8.7 installed via ports so this was definitely incorrectly linking to the original ruby install on my mac. Even after renaming ruby binaries, libs and reinstalling all gems I still had this problem. Others had luck with this but not me.. I decided the path of least resistance would be to use Ubuntu. So I copied my dump file over to my Ubuntu machine, did the migration (it worked - YAY!), made a new dump (clognew.mysql) and uploaded back to my Dreamhost account. There I loaded it directly into the database and restarted Typo. It worked! Well... almost... My sidebars wouldn't work, I would get the following error and could not find a way to fix it: It seems something went wrong. Maybe some of your sidebars are actually missing and you should either reinstall them or remove them manually So I started a Rails console:
script/console productionAnd tried to pull all sidebar models:
So my problem is that this Aimpresence model no longer exists. To fix the problem I actually created it in the console>> Sidebar.all ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'AimpresenceSidebar'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite Sidebar.inheritance_column to use another column for that information.
And finally I found the model to delete (querying by name would probably be better, but for me just pulling the 'fourth' worked) NOTE that your Sidebar probably will be in a different position>> class AimpresenceSidebar < Sidebar >> end => nil
Now finally querying for all sidebars works and the production error is gone.. hopefully this will help others that find themselves in this situationSidebar.find(:all, :order => 'active_position ASC', :limit => 4).last.destroy
Drop the Superclass
I’ve worked with Java to Ruby converts for the past year and the #1 thing that comes up over and over is the excessive use of inheritance. I can understand why, I was taught Object Oriented Programming in C++. We spent a week on encapsulation (that was the end of “basic” programming) and en entire semester on inheritance and templating (that was the “advanced” class). Inheritance was driven into so many of our heads that we have a hard time not using it. We were told that this is where the power of OOP lies - this is how you get the most code reuse.
Unfortunately it’s just not true. The use of inheritance results in very strong coupling of your code. Any class is dependent on all of its superclasses. You can’t isolate this class without taking all of the superclasses with it. You can’t isolate the classes’ siblings without doing the same. You either have to make several copies of these classes (don’t do that…) or you have to move the entire chunk of code from project to project as a single unit. The latter is the only practical choice you have - but what if you just want to use a few pieces of functionality found in this code? Tough luck - it’s all or nothing. This leads to bloated code, poor code re-use, and hard to use APIs. Ironically this is what most of us are used to - so it seems normal to us when we come across it.
Since publishing is a large part of the industry I work in, there are often “publishing” methods that need to be added to our models. Every implementation I’ve seen so far injects a Publish class in between ActiveRecord and the model. This isn’t necessarily a bad thing on its own. With just one level of inheritance we can still achieve good code reuse. But where do go from here? If we want to add additional functionality at this stage we either need to add it all to Publish (even if it’s not in the publishing domain) or we need to add additional levels of inheritance. All of the sudden our code reuse has gone out the window. We’re going to have a hard time injecting this functionality into other code bases.
Using composite objects instead of inheritance can help in many cases. We can add the desired functionality into a separate class and then instantiate that class in the class we want to “extend.” Then you can call (or delegate to) these methods.
def Publish < ActiveRecord::Base
belongs_to :article
end
def Article < ActiveRecord::Base has_one :publish
def initialize @publish = Publish.new end
def before_save raise Publish::NotPublished unless @publish.is_published? end end
Wow this still sucks! We either have to use two tables in the database or initialize publish from data in the article table. Either way really sucks. We don’t want to require an additional table and relationship. We also don’t want data for the Publish model in the Article table. Composition will often work just fine in a class that isn’t doing any object-relation mapping - but in this case it causes more problems than it solves.
In the land of dynamic languages (like Ruby) we can get around this. Using a run-time patch that injects a decorator method into a class can provide a way to build up functionality on the fly. It can also be more descriptive. It’s not always clear what superclasses Publish is being built from. If you break all of this functionality out into modules that get mixed in via decorator methods - then it’s easy to see what the behavior of the class will be by just looking at the class definition.
This functionality is broken out into a Rails plugin that allows runtime changes to ActiveRecord (or ActiveResource). Here is what the (simplified) patch looks like:
module ActiveResource
module Acts
module Publishable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def acts_as_publishable(options={})
include ActiveResource::Acts::Publishable::InstanceMethods
end
def publish(id, options = {})
end
end
module InstanceMethods
def is_published?
(status == "published" || status == "edited")
end
end
end
end end
ActiveResource::Base.send(:include, ActiveResource::Acts::Publishable)
Now here is what the model will look like:
class Article < ActiveResource::Base
acts_as_publishable
end
Now we can mix this functionality into any code base. If you have database fields that relate to publishing they can be mixed in via migrations when the plugin is installed.
Make Your Application Stand on its Own
I’ve come across a number of web applications recently that cross-link between other applications to steal their functionality.
This sucks!
It leads to poor application design as sooner or later developers come along and are naturally confused about what should go where. They then increase the amount of cross-stitching between the applications. Eventually you end up with one large application that’s not so great at doing two things. You have to get both applications working independently when you just want to use one. It wastes time and it creates a mess. The more applications you connect this way, the worse it becomes. It lowers the quality of both applications and kills code velocity.
Stop the madness!
For those of us that are Rails developers there is a pre-determined place to put outside dependent functionality - the ‘vendor’ path. If you put all of your external dependencies there you have a nice self-contained application that can stand on its own. Functionality shared between applications can be broken out into mutual dependencies and be pulled into the respective applications as plugins, frameworks, or gems that are stored in the vendor path.
If you have a framework, put it into “vendor/framework.” This is where rails goes for instance (vendor/rails).
If you have a plugin, put it into “vendor/plugins.” It’s the standard plugin location for Rails.
If you have a gem, install gemsonrails and put it into “vendor/gems.”
Now everything is nice and tidy. All you have to do to get your application ready for development or deployment is to check it out. No gem installations or framework installations. The dependencies are already met as soon as you get the code.
URIs, URLs, Conventions and Experts
I always seem to be on the losing side of arguments that debate the finer points of the Universe. Sometimes the details are important but most of the time they’re just noise.
In these cases, I tend to follow the convention unless I have a strong reason not to. I don’t necessarily know how the convention came to be in all cases.
Unfortunately it’s surprisingly hard to convince others to do the same. Everyone likes to think they’re an expert. Expert is a subjective term though. As a developer, I picked the Ruby and Rails camps. I don’t necessarily blindly agree with everything that comes out of the mouths of Dave Thomas, Jim Weirich, and DHH, but I have learned to trust their judgment.
Finding mentors makes life easier. If you know you can trust the words of someone 90+% of the time, then you can build on what they know and not bother repeating the same arguments they have gone through. This is how “experts” work. Experts have a network of peers that they trust. That’s why they advance so much more quickly. They don’t bother repeating the details.
In order to become an expert you have to assume that you don’t already know everything.
I’ve encountered this situation once again. I’ve been following the RESTful Rails naming convention of using URIs where others use URLs. I did this because I trusted the judgment of the Rails Core team that this was the proper term. I always hated the interchangeability of the two so I was fine with just using one.
The debates came. There were inappropriate URIs strewn all over my code! These are supposed to be URLs I was told. I was asked WHY?! Why oh why have you strewn sloppy terminology all over our codes? My answer of that’s the Rails convention was not good enough. My peers wanted to replace all of these, I said “fine - if you really want to take the time on that.”
So… migrations are added, tests cases modified , source, documentation - all changed to reflect the “proper” naming scheme.
The truly ironic part. The initial naming scheme was right. That’s correct. All of that changed things to the WRONG terminology. It turns out that the Rails core team was right (imagine that). While it’s true that a URL must have an http, ftp, etc protocol at the beginning - it ALSO has to have an extension at the end that says how the resource should be presented. The concept is completely outdated now - which is why URL is considered obsolete terminology (just Google around for that).
I found the below… URI.. which describes the fine points of how the two differ.
http://ajaxian.com/archives/uri-vs-url-whats-the-difference
The lesson is to not assume you know more than everyone else. When a group of experts agree on something, maybe they’re right! Investigate the issue if you like, but don’t assume they’re wrong and you’re right.
Why I Converted to Search Servers
Many who have worked with me in the past know that I always resisted including search servers (ferret/lucene/solr) into my projects. I argued that they added unnecessary complexity and didn’t provide much that some fancy database searching couldn’t do.
I was wrong.
While I suppose that I still consider the above arguments to be valid, there is one more important argument on the side of using search servers - scalability. I share many rubyists’ disdain for the “S” word. It gets thrown around a lot and typically results in overbloated software that still doesn’t perform well even when “scaled.” There really isn’t a better word in this case though.
HTTP is incredible. As the recent RESTful advocates have pointed out, the protocol is infinitely scalable, simple, and is (in a large way) responsible for the explosive growth of the web. Web servers getting bogged down? No problem, just add another (as long as you’re not trying to do any - or at least not much - state tracking). You can keep adding servers to your heart’s content. A good admin can have this process down to a five minute setup.
Eventually all of those database calls add up though and your database starts straining under load. What do you do now? You can start optimizing your queries, do some fancy caching, add a slave database and keep a read-only connection open to it or (the mother of all evils) create a database cluster.
All of these options suck.
All of that beloved simplicity and scalability of HTTP is gone and replaced by infrastructure that’s extremely expensive and hard to maintain. Sometimes you just can’t get around the database cluster - but it should be a weapon of last resort. Query optimization isn’t so bad if done correctly, but it will only get you so far. Query optimization can also take nice clean code and turn it into a mangled nightmare. Caching is also good in moderation, but too much of it is also a code mangler and can make your application’s usability suffer (waiting 10 minutes for a user’s change to appear is often not usable). Database slaves are fine as failover/backup options but reading from one db and writing to the other also produces mangled code.
The solution? Search servers. Search servers can grow infinitely. You can run one on each web server or you can also have a centralized search server if you prefer. Whenever you pull results from the search server your database has avoided the blow. You’ll still probably need to hit the database occasionally, but your load will be dramatically lower. The load is on the web server end and can be shared across the web cluster without any fancy configuration. Once your search server is in place, use it for as much querying as you possibly can. The growth of your database load will be a nice slowly climbing linear line that will probably keep pace with processor speeds. If done right, you can avoid the extreme overhead involved with a database cluster.
Typo Pains
You may have noticed a lot of errors popping up recently around here. The problem has been how triggers work with Typo. It seems that publishing articles in the future will make Typo go kaput if you’re on Dreamhost. It doesn’t seem to happen anywhere else - there must be something unique to the Dreamhost environment.
I was able to fix this problem by deleting the content items in question, along with the related articles_tags and triggers. This required a combination of work in the typo console and mysql cli client to do. You have to find the id of the items in question. Delete the rows matching that id in the contents table, delete the rows that have that id for articles_id in the articles_tags table and delete the rows that have that id for pending_item_id in the triggers table.
What a great way to start the weekend! :)
Obviously this means that I had some articles coming that will be delayed now. I’ve read elsewhere that you can get around this by marking the publish date in the future but leaving the “publish” item checked.
Be a Zealot - Rails Edge Day 1
What a day! There were certainly some great talks at Rails Edge on the first day. This all happened during a storm that must have been an act of God. I certainly had no idea what was in store for me once I left to drive home… hopefully others got home OK. I’m just glad my car didn’t float away on me at any point (honestly I’m surprised it didn’t). I was very close to just bunking in the car at some random parking lot overnight. Had I known how bad it was I would have just stayed at the hotel…
Anyway… the #1 highlight I took from day 1 is: “Be Zealous.” There are many other important highlights, but I think this one is the most important. Chad Fowler did a superb job of going over how to produce “quick and clean” (as opposed to quick and dirty) code. It took a strong force of will to get Rails where it is today. It wouldn’t have happened without the strong opinions and determination of the core team. If we’re going to continue to make the world a better place for software development, then we need to stay true to our values. These are mainly MVC, CRUD, constraint-driven development, metaprogramming and domain-specific constructs and more recently REST.
From my perspective, I hope Ruby/Rails developers continue to evangelize for the cause - but I also hope that we can all recognize when we have turned down the wrong path. Too often I’ve heard the excuse of “yeah it’s a bad way to do it, but there are already thousands of applications in production that rely on that.” The end result is that the problem just becomes worse and worse.
No matter how far down the wrong road you’ve gone, turn back.
Maintaining a zealous stance for the Ruby and Rails core values while also being open to questioning our current path will obviously require a delicate balance. The forces may pull in different directions, but developers will need to learn how to walk the line. To quote Dave Thomas’ speech today, “An object is made from a class and a class is a type of object.” Patterns often become cyclical.
Dave Thomas’ speech on metaprogramming really cut to the chase on how frameworks like Rails are built from Ruby and how you can leverage this power for yourself. If you find yourself coding a non-trivial application, then you really should think of domain-specific ways to describe your application. You can do much more than just build an API, your application can (and probably should) consist of it’s own language in many places. The language is built on Ruby (and possibly Rails as well), but is pieced together in sections that are self-describing. If done properly, this will empower you with productive development throughout the product’s life-cycle. It may be that your framework is so good that it will survive future generations.
A passive observer probably would have thought today’s conference was really “Macbook Pro/iPhone Edge.” A slightly more observant person may have thought it was really Java-loves-Rails Edge. A majority of the crowd seemed to consist of people that were either currently Java developers looking into Ruby, or Java developers that have already made the jump. Add a great talk on JRuby into the mix and there’s a lot of Java floating around. I find this amazing considering the disregarding attitude that seemed to come from the Java community towards Ruby and Rails just a couple of years ago. This change is definitely good for both camps though. The number of Java developers swarming towards Ruby is very reminiscent of how C++ developers swarmed to Java circa 1999.
Personally, I never drank the coffee. It’s not that I didn’t think Java was a great technology, I just felt that it only went half way and didn’t really see the point in that. In my mind, if you wanted efficiency - then just use C++. If you wanted productivity and multi-platform functionality, then Perl and PHP really got things done much faster (despite their crappy OO support) - at least as far as web application development goes. A majority of us that started on Rails back in the beta, 1.0/1.1 days were PHP developers that believed in dynamic languages but also believed that there must be a better way.
Whatever the path, we seem to be converging on the same road now and this can only be a good thing.
Even though I don’t really care too much about Java, I was blown away by Justin Gehtland’s presentation on JRuby. This technology really has come far and has the enormous advantage of being able to run all of the bajillion of Java libraries out there in conjunction with Ruby (and Ruby on Rails) code. This technology has developed amazingly fast and I really wonder if this may end up being the Rails platform of choice down the line. It certainly makes the migration from Java to Ruby quite painless.
Marcel Molina quickly went over his “Presenter” concepts and lamented over the state of Rails tempting language options. It is definitely clear that ERB is near the end of it’s life-span in this role.
Both Marcel and Chad reiterated many times about the evils of putting code in your views. I have recently felt a little over-zealous about all of the times I’ve gone batty about ActiveRecord calls that are in a view. I haven’t even gotten to where I try thump the no-code-in-view philosophy yet. I definitely feel encouraged that this seems to be the perspective of the core team. I’ll also remember that being zealous is generally good…
Ezra Zygmuntowicz (man that’s a tongue twister) proved that stable extreme-volume rails environments are indeed a reality. His discussion on Xen was excellent. In short, the platform of choice is: Linux (via Xen) + Nginx + mongrel + monit. The swiftiply mongrel patch to mongrel is now stable and can greatly increase your throughput. If you don’t know these technologies yet, you owe it to yourself to get to know them.
Last but not least, Mike Mangino gave another great talk on “RESTful” Rails development. Simply helpful was covered, along with changes that are going into Edge Rails - to be Released with Rails 2.0. After talking over REST concepts with the other developers and listening to Mike’s speech, I walked away convinced that REST is indeed the way to go.
I’m looking forward to Day 2, provided that I can swim my way down there!
Rails Edge Bound
I’m looking forward to heading down to the Rails Edge conference in Chicago tomorrow (8/23/07). Tribune Interactive was nice enough to pay my way. I will be sharing my notes and experiences here, so stop by (or check the feed) occasionally.
Loving CachedModel/memcached
I’ve actually had CachedModel/Memcached running for quite some time, but I didn’t notice that it stopped automatically working for simple calls when Rails 1.2 came out. At the time we were just ramping up with our new dev team and the other Rails sites I had done were nearing the end of their useful life-span. So database load was low in general, a perfect time for Rails 1.2 to sneak one in on me.
Thanks to a combination of successful product launches and ever more dynamic websites (allowing for an ever decreasing amount of cacheable material) our main database server began to become stressed. Finally I noticed that memcached was in fact not caching much at all. After looking into it, I found this ticket describing the problem and (fortunately) a fix.
Once I fixed the problem (and one of the other devs added some key fragment caching) the load went down almost 90%!! It’s ironic that it took CachedModel breaking for me to be reminded just how great it is.
If you want to try it, follow this tutorial for setting up CachedModel. It’s still fairly relevant.
There’s a fancy new Acts as Cached plugin available that also abstracts memcached and may be any better.
If you’re running high-capacity sites, some type of memcached interface is a must-have!!
A hacked theme_support that (mostly) works
A theme should allow the look and feel of an application to change. A theme has a one-to-one relationship with the application, meaning that an application should only be running one theme at a time. A theme per user would be a ‘skin’ and an application that runs multiple sites with a different “theme” for each one is a whole new can of worms. I’ve had a need to do the latter recently, but I’ll go over my (site_support) solution to that in the next post. Meanwhile, here’s my solution for adding themes to your application.
When to use it: A single application connects to a single database and has multiple theme options, but only one is running at a time.
Start by installing my hacked version of theme_support
script/plugin install http://www.chrispcritter.com/theme_support_mod/
ActionMailer currently doesn’t work with it, I’ll have to tackle a fix for it soon. I’ll post my findings.
At this point you should at least be able to get your poject running in mongrel.
To create the them, you’ll need to create a “themes” folder in your project and start your first theme. The theme must have the following structure:
$app_root
themes/
[theme_name]
cache/
images/
stylesheets/
javascripts/
views/
layouts/ You may notice that this is a little different than the structure described in the theme_support documentation. I could not get layouts to work outside of the view path (so I just moved it into views). I really think this is better anyway - since it matches the standard view structure. The layout I describe also has a “cache” folder. The theme_support plugin supposedly supports cached files in a public/themes structure but I had some difficulty getting this to work and really wanted to keep all theme related content in it’s own folder. I ended up setting page caching to go into the themes/[theme_name] folder with some mod_rewrite magic. It may be better to add a “public” folder to each theme for this at some point.
Add a line similar to the following to config/environment.rb (where
THEME = ENV["THEME"] ? ENV["THEME"] : ''
And add the below line to pull out your site specific configuration options.
CONFIG = YAML.load(File.read("#{RAILS_ROOT}/config/#{THEME}.yml"))If you’re using apache, your rewrite rules will look like the following:
RewriteRule ^([^.]+)$ themes//$1.html [QSA] RewriteRule ^images/(.*)$ themes/THEME>/images/$1 [QSA]
You will need to modify the caching paths in environment.rb so they point to the right place. Add the following lines:
ActionController::Base.fragment_cache_store = :file_store, "#{RAILS_ROOT}/themes/#{THEME}/cache"
ActionController::Base.page_cache_directory = "#{RAILS_ROOT}/themes/#{THEME}"Add a link in public that points to your themes directory “public/themes -> ../themes/” That will preserve the routes.
It’s not the most elegant solution but it works. It bypasses some routes functionality and the sym-link in particular is ugly. I’ll post more mods to theme_support as/if I make them along with simpler install instructions, but this was really just a stepping stone to my site_support setup - so it may be awhile before I get back to it.