No Ranting, No Railing, Just Grading
A few of our students, people new to ruby and rails, are pretty turned off by the ranting and railing in the rails community that’s been on super-duper heavy display lately, what with the Zed thing and the Dreamhost thing and all. (No links, google Zed Shaw and Dreamhost Rails for your ownselves.)
These students want to know: what’s up with the rails community being so childish, ranty, obscene, profane, and macho? If rails wants to be treated like a grownup framework for grownups, shouldn’t rails act like a grownup? How are we supposed to take rails seriously when the guy in charge of rails thinks people who are offended by swearing are not worth his time? And why should we want to join a community that appears so unwelcoming?
To which I say the following:
First, my job is not to defend rails and all the people associated with it (Right, say students, your job is actually to finish grading our assignments. Could you finish?!? I’m working on it, I swear). If Rails is a ponzi scheme I have not been let in on it; I get no kickbacks from duping students into learning it. I am enthusiastic but not passionate about rails ( I believe, as I’ve said before, that my only true passion may be cheese), and I hope I’ve managed to share some of my enthusiasm with our students, without appearing cultish.
Second, I could point out that the Ruby and Rails communities are not isomorphic. There is a lot going on in Ruby that is not rails. But it’s also true that many people come to Ruby through Rails, so if the rails community is unwelcoming, then fewer people may make it over the hump to discover the Ruby in which Rails is built. That’s too bad, because they’d be missing out on something truly lovely. Still, there are other truly lovely languages out there too. “Let a hundred flowers bloom, let a hundred schools of thoughts contend,” except without all the reeducation camps.
Third, it’s possible that Rails will hit a wall due to personality problems. It’s also possible that, being young, Rails will grow out of its personality problems. If you don’t like the personality of the rails community right now, just wait, it’ll probably change. Or jump right in there with your own personality problems, mix it up a little.
Whatever happens, though, I think that Rails has a few good tricks that the rest of the web development community has and will continue to learn from. I think that Rails, like all frameworks, will someday go out of fashion, and then, out of date, and then, eventually, fade into obscurity. And I think more good and interesting and beautiful things will come out of Ruby.
In any case, as I wrote to one of the students who was a bit depressed by the recent rails flame wars:
For me, I know that if it had not been for rails getting popular, I would not have gotten into Ruby, and if I had not gotten into Ruby, it might have been much, much longer before I’d realized that life could get a whole lot better than:
Iterator iter = collection_thingy.getIterator();
while (iter.hasNext()) {
Thingy thingy = (Thingy) iter.next();
}
No one can take each away from me.
REST vs. SOA: thoughts from a member of the unwashed masses
I have no recollection of how I ended up here:
On the REST front, if you’re claiming that it’s harder than the alternatives, to me that’s just a sign that you don’t understand it. Is REST simple? No, but neither is SOA. However, unlike SOA, which is fairly wishy-washy, noncommittal, and loose, REST’s constraints provide real, actual guidance for developers, and those same constraints also provide opportunities for significant flexibility, extensibility, performance, scalability, and serendipity. SOA’s contracts come with no rules or constraints, and thus can easily result in a system that’s extremely brittle, tightly-coupled, and virtually impossible to upgrade. SOA itself isn’t inherently bad, as it’s certainly a step above the “every application for itself” mode of development that’s so widely practiced. Unlike REST, though, SOA doesn’t go nearly far enough to provide real, useful guidance to the poor developer who has to actually write the stuff, make it work, and keep it running.
The author was responding to this guy:
This is the reason I am against dynamic languages and all of the fan-boy parts of IT. IT is no-longer a hackers paradise populated only by people with a background in Computer Science, it is a discipline for the masses and as such the IT technologies and standards that we adopt should recognise that stopping the majority doing something stupid is the goal, because the smart guys can always cope.
And that guy was responding, in turn, to this guy, who said that REST was like dynamic languages because both are loosey-goosey and flexible and don’t enforce contracts and type-checking.
The SOAP/WSDL/WS-* SOA view of the world is like a statically typed programming language, i.e. C++ or Java — everything is pre-defined, contracts govern everything, nobody can interact without following formal rules … and ideally, everything violating the rules (and policies) will get caught before even going into production.
So the chain is: 1) REST is very flexible compared to SOA, and that presents the danger that things that don’t work will be put into production. 2) REST is too complicated to be implemented by ordinary dumb programmers, and should be avoided. 3) REST is easier than than SOA because it provides very strict constraints.
So is REST easier or harder than SOA? Is it looser or stricter?
I just implemented my first REST API. I don’t see how anyone could say that it is ‘harder than the alternatives’, or that it doesn’t constrain developers very much. So I agree with the first quote, above. REST seems like a great idea to me. Anything that allows me to mostly avoid the complications of this many standards is good.
And also, obviously, I’m a big fan of dynamic languages now. I think I’d rather look at someone else’s crappy Ruby code than someone else’s crappy Java code, because at least there’s less of it. But I am, arguably, a Ruby fangirl right now, and given that I don’t have a CS degree, I guess I also count as one of the unwashed masses. And as a member of the masses, I can attest that no programming language in the world will stop us from doing something stupid. So we may as well enjoy ourselves while we’re doing it!
Database Constraints, Stereotypes, Rails, Culture, Talmud, Gender, MINASWAN, Religion. But ABSOLUTELY NO BONDAGE PLAY
This post started out with a plan to compare constraints in software to bondage play, and suggest that DHH is a top who likes to constrain others (”opinionated software”) but is extremely uncomfortable being himself constrained (by, say, the database). I was going to suggest that DHH maybe needs to get a little bit more confident and comfortable being a ‘bottom’.
Now, that would have been a wildly, wildly inappropriate post, don’t you think? So it’s lucky for me that as I was writing it, I realized that not only was it inappropriate, it was completely unfair. So this post is still about rails culture, and still about database constraints, but I am not, I repeat, NOT arguing one way or another about DHH’s predilections in bondage play (assuming he has any, and if he does, not that there’s anything wrong with that ), about which I am, and hope and plan very much to remain, ignorant.
That out of the way, how did this all come up? Yeah, my mind’s a little twisted. But here you go:
My friend and partner-in-teaching-crime* (well, boss in teaching-crime, technically, and is teaching really a crime? To my students: do not answer that!) John complained recently about the difficulties of writing a migration to turn a plain HABTM join table (two foreign keys, no primary key, nuthin’ else) into a join table with state, linking two other tables with the :has_many :through association. Unfortunately, as he describes, ActiveRecord won’t let you add a primary key column to an already-existing table, so he had to migrate all the data over to a new table.
Couldn’t you just drop down to “execute ‘db-specific sql here’”? I asked.
Yeah, but you wouldn’t be database-agnostic, of course. John likes to be agnostic. He has historical reasons for that, just like I have historical reasons for thinking that ads comparing servers to who won’t give blow jobs are kinda offensive. But anyway, I don’t have those reasons that John does to prefer agnosticism. I figure that in most cases, people are sticking with the database they’ve got, so database agnosticism isn’t that important to me. The ORM is one of Mr. Spolsky’s leaky abstractions, and while that’s no excuse to start poking extra holes through just for the fun of it, I don’t have any need to pretend that the holes that exist aren’t really there.
In any case, I drop down to the database to put in foreign key constraints.
[Aside: John said in email:
“There is a distinction to be made between this narrow case of
agnosticism (fiddling with keys) and the general case. The narrow case
is easier to disregard. In the general case, it is very difficult to
argue against agnosticism, because the primary driver is: You get to
know less. That is frequently (more frequently than not) beneficial,
right? In the general case, I would rather write
user.find_all_by_last_name rather than the raw SQL. etc.”
I agree wholeheartedly, and in that sense I too am in favor of database agnosticism. But obviously we have different levels of allegiance to the idea, because I would never have put in the effort to come up with a database-agnostic migration from a HABTM to a has many through relationship, and he did. Maybe it’s just that I am lazier than he is, though…]
—
So this post was going to be about how it is the rails way not to use foreign key constraints at all, but to rely on ActiveRecord and your own unit testing to maintain data integrity. (hah!) And I was going to say “that’s freakin’ insane and evidence of all that is wrong with the whole culture of Rails.” But while it would be fun to see what this temporarily did to my site stats, (assuming it got dugg or reddited or something) it wouldn’t be fair.
I found very little evidence that not using foreign key constraints is considered to be a best practice by most people in the rails community. The main thing is this caboose posting, from last year. This was mostly a complaint about how big of a pain in the ass foreign keys are, especially where fixtures are concerned. But it actually only at the end claims that foreign keys are not needed, if you are using ActiveRecord Associations correctly. And even then, it’s a weak claim, about foreign keys in the development database:
The time thing sold me on not using foreign keys in development. I’m sure there are a number of arguments that can be made for using foreign keys etc etc, but it’s just stuff that gets in the way in a framework like rails. Do we test w/ foreign keys in place before milestones(what I’m leaning towards)? Do we test w/o the fks in place(obviously not :])? Maybe somebody can come up with a better way to handle them, but I don’t really think you need fks if you’re using rails associations correctly. If you are forced to use them though, the above approach might be a good place to start.
Okay, I found one other posting, from a guy who gave up his foreign key constraints (and wept) because they were too hard to use with fixtures. But most people in the comments of that post seems to think the problem there is not foreign key constraints, but fixtures, and that dropping the reliance on fixtures would be the smarter thing to do. Or fixing the fixtures, or whatever.
DHH has nothing to say on the matter that I could find. In AWDR, Dave Thomas explicitly advocates the use of foreign key constraints (2nd Edition, p. 324). Mostly what I found on the web about rails and foreign key constraints was a bunch of people talking about how they do use them and you’d be crazy and irresponsible not to. Yes, people differ on when in the development process they put them in (in fact, right this minute I have a development database with a near-complete lack of foreign key constraints, my rather pathetic excuse being that the client’s requirements are so changeable right now that we can hardly keep up with the foreign keys themselves…), how they use them with fixtures, and other details, but I really found very little evidence that anyone in the rails world seriously advocates putting into production web applications backed by databases without foreign key constraints. Relational database technology is mature, it’s well-tested, and it’s logical. I trust it much more than I trust either my own code or DHH’s. Database constraints are easy to use and good for you, just like flossing. And that appears to be the majority view.
So the evidence wasn’t there, and I had to rethink this post entirely. And so it’s become, in part, a post about stereotypes, and about culture, and about the ways that people confuse technologies, creators, fans, and users.
Rails is a technology. The technology exists in the context of a culture. The culture is greatly influenced by the fact that a single, very opinionated, um, strong personality developed the technology. Certain kinds of people are attracted to the opinionated personality, and become involved in the technology and its culture because of that. This is great for adoption of the technology. But then you get the fanaticism: rabid pro-Rails trolls who jump down the throats of people they perceive to be deviating from the One True Way of DHH. And equally rabid anti-rails trolls, screaming “Twitter”!
Now, is all this clash of personalities and hue and cry integral to the development of the technology, or is it epiphenomenal? (Is that a word?) I’m not sure. The anthropologist in me says it is, and that the culture of rails in some sense IS rails — drives its development, ensures or prevents its success, etc. The Marxist in me thinks perhaps the structure of rails itself is responsible for the culture surrounding it: the culture reifies the framework. And the poststructuralist in me suggests that, however determined things appear to be, however narrow and defined and boundaried and opinionated and one-true-wayed things appear, there’s always space for something else to arise.
There’s the One True Way of DHH. There are rabid fanboys. We talk of drinking the kool-aid, and we laugh at video advertisements comparing the separation of concerns, database-agnosticism, and ease-of-use of Rails to PHP, Java, et. al. “With rails, I can build a blog in 10 minutes,” we say. With rails, we never have to code again! Let’s just go to the beach instead! There was the Twitter developer scaling scandal, and the CDBaby switched-back-to-php-from-rails scandal, and a bunch of scandals I haven’t even heard of, no doubt. There’s the rails bandwagon, the rails hype, rails lets crappy developers wreak havoc quickly, rails is too slow, and rails is not ruby.
And that’s all fine and part of the fun, and part of the DHH Is Opinionated and So We Are Opinionated - ness of Rails culture.
But then there’s the technology, and lots of quiet, not-so-opinionated, flexible people who are using Rails because it’s a pretty good, pretty easy framework that helps them get their work done. There’s plenty of that too. And there’s no need to decry the partisan atmosphere of rails culture with a great big rending of garments about how the culture really has to change if it’s going to achieve more popularity, and it’s scaring people off because it seems too hyped, and badly executed rails projects are giving rails a bad name and how can we police that, and so on.
Let’s just all get on with our work, using rails, or not, as the work dictates. And in a mild-mannered matz-y way, talk about what we are doing, and why, and how, and what we like, or don’t, about it.
For me, rails is a web framework, not a religion. I know that not everyone feels or acts that way, and that’s fine for them. They can wave their hands and argue about what constitute a ’scale’ for the purposes of determining if a fish is kosher, or if one should use foreign key constraints. Me, I’ve got to get dinner on the table.
* Max would like it noted that he thinks there’s something very trite about the expression “partner-in-crime”. He’s right, of course, but I think I’ll leave it in anyway, to annoy him.
Installing Ruby 1.8.6 on Ubuntu Feisty Fawn (7.04)
Ubuntu seems to be the big distro these days. (Remember all of those other “it” distros? Slackware? The original Red Hat? Mandrake? I am vaguely tired of the trendiness of distros.)
Anyway, there is no package yet for Ruby 1.8.6 on Ubuntu Feisty Fawn (7.04), which is unfortunate, since mongrel_cluster doesn’t work properly under Ruby 1.8.5.
The install steps I got at Urban Puddle (here) were nice, but Rails still wasn’t happy: I kept getting that awful `require’: no such file to load – rubygems (LoadError) error.
Here’s what I did to fix it. YMMV.
Building Ruby (from Urban Puddle):
tar xjvf ruby-1.8.6.tar.bz2 cd ruby-1.8.6 apt-get build-dep ruby1.8 ./configure --prefix=/usr make sudo make install
Next, to fix it:
cd /usr/src/rubygems/rubygems-0.9.4 sudo ruby setup.rb
Et voilà :
max@somehost:~ $ irb irb(main):001:0> require 'rubygems' => true
I’m not quite sure why the Ruby source doesn’t ship with the rubygems source. Is it because rubygems is still a < 1.0 release?
Annals of Idiotic Bugs
I’ve decided I like bugs. Not in production code, of course, but in development code, yay for bugs. Fixing my code teaches me far more than writing it did. Perhaps that’s because, with example code and snippets and tutorials all over the internet, much of the code that I write I don’t really write. I copy something I saw from something else and modify it to suit my own needs, or I look it up in a recipe book, or I see someone else’s solution on a mailing list… When you’re new to a language, you often use code that you don’t quite understand. I’m curious, so I try to understand it, but I don’t always have the time.
But then you get the bugs. And to fix the bug, you have to understand the code. (no, I know, that’s not really true. you can fiddle around with bug fixes just like regular code, and find someone else’s fix and implement it and it works and you’re in a hurry so you don’t care why it works, just that it does…)
Anyway, most normal developer bugs are stupid. I suppose there are great developers out there whose bugs are subtle and interesting. Most of mine, anyway, are quite stupid.
Here are some of my stupid bugs:
1) Implemented a slideshow. Stored stuff in the session to use during the slideshow. At end of slideshow, remembered to clear the slideshow stuff out of the session. Yay for me! Oops, child calling, check in code!
Max: “Um, Amy, how come playing a slideshow deletes all the photos in the slideshow?”
Me: “Dunno, maybe it has something to do with clearing the session? Why would deleting a thing from a session destroy it?”
Here’s what I had to clear the slideshow out of the session:
session[:slideshow].clear
Here’s what I should have had:
session[:slideshow] = nil
Oh, and here’s what was in the slideshow:
slideshow = domain_object.photos
So it’s not like my slideshow was just an array of any old ActiveRecord objects. It was a particular other ActiveRecord object’s personal array: i.e., an ActiveRecord AssociationCollection. AssociationCollections have a method called clear. Clear removes all the objects from the collection, like delete_all. Except delete_all doesn’t, according to the doc, destroy records, it just deletes them. And assoc_collect_.clear definitely destroys them, because not only did calling it kill the database records for my photos, it also killed the actual photos on the filesystem. So are clear and destroy_all the same thing? The doc is thin, so I went to the source:
# File vendor/rails/activerecord/lib/active_record/associations/association_collection.rb, line 67 67: def clear 68: return self if length.zero? # forces load_target if hasn't happened already 69: 70: if @reflection.options[:dependent] && @reflection.options[:dependent] == :delete_all 71: destroy_all 72: else 73: delete_all 74: end 75: 76: self 77: end
So, domain_object.association_collection.clear does to the collection what domain_object.destroy would do, which is either to delete or destroy the associated records depending on what options you set in your call to has_many:
:dependent - if set to :destroy all the associated objects are destroyed alongside this object by calling their destroy method. If set to :delete_all all associated objects are deleted without calling their destroy method. If set to :nullify all associated objects’ foreign keys are set to NULL without calling their save callbacks.
I’d set :dependent => :destroy_all, so that’s what calling clear did. Oopsie!
Why did I use .clear anyway? Apparently I was thinking of my rake task rake db:sessions:clear.
In any case I didn’t want to be storing whole photo objects in my session anyway. I just wanted IDs: session[:slideshow] = domain_object.photos.collect { |p| p.id }
2) Wrote some boilerplate code for a create action. On failed validation, Rails complains there’s no create template to render. Why are you trying to render a create template, Rails, when I clearly ask you to render new upon failed validations:
render :action => new
Uh, because I told rails to render :action => nil. So rails defaulted to its standard "render the template whose name is the same as the action invoked" and went looking for a create template. What I needed to be saying was:
render :action => 'new'
Problem fixed. That one took me way too long to track down. I wish Ruby would complain to me about things that look like local variables but don’t seem to have any values attached to them. I’m not quite used to bug fixing a dynamic language, without the crutch of the compiler.
Right, what else?
3) If I want, temporarily, a list of all the photos in both a & b, where a & b are two different ActiveRecord objects, I should not do the following to get the list:
list = a.photos << b.photos
This moves all the photos in b over to a, permanently, in the database. This is one of the pitfalls of the syntactic sugar of methods that look like plain old operators. They’re not, really. ActiveRecord sometimes does more stuff than you want or expect it to, behind the scenes. Not a save or update in that code to warn me that I’m calling the db, but I am.
4) Oh, and the stupidest thing of all:
if x = y
#do stuff
else
# do some other stuff
end
How come the ‘other stuff’ is never getting done!??
Duh, because X will always equal y if you assign it to y instead of checking to see if it == y!
Conclusion
This concludes the first edition of: Amy reports dumb things she did in Ruby code so you don’t have to do them too. C’mon, be original, and come up with your own bugs! I do not release my bugs under a Creative Commons license. I want royalties on all software including these particular bugs. I am going to implement DRM on these bugs. Don’t you dare steal my buggy code! It’s mine, mine, all mine!
Rails Ninjas We Are Not
The other day I responded to an ad looking for Rails Ninjas. A very nice guy called me up to talk about his startup. He asked me to talk about our rails skills. Would I describe myself or Max as a rails superstar? I said “look, we’ve been using rails since March. We are not rails superstars.”
Why did I respond to an ad asking for Rails superstars when I make no claims to be one? Because there are many ads looking for Rails superstars and there are not enough to go around. There certainly aren’t undiscovered rails superstars around. We’re not talking supermodels here. You don’t take an ordinary Romanian peasant and turn her into a rails superstar overnight with a nice haircut and a manicure . Rails superstars have blogs and open source projects and debates about the importance of symbols on the rails-core mailing list. They have histories.
Me and Max, we don’t yet have a history with Rails. We are not superstars.
And yet, we are not script kiddies. Rails is full of amazing magic. How do instance variables set in the controller end up as instance variables in the view? Who knows? And who cares? Script kiddies don’t care. It’s automagically terrific, and that’s all they need to know.
If you look at the source code, though, you fall down a rabbit hole. You discover that Ruby itself has a method called instance_variable_set (be sure to check out the documentation on that!), that you can call on _any_ ruby class. How utterly transgressive! You can just shove whatever you feel like in anyone’s class at any damn time you please. You can make brand-new methods on the fly, when you need them, by using method_missing to make a new method whenever you call one that doesn’t yet exist. Amazing feats! And not implemented in secret or in C or something that isn’t any fun to look at and that there’s little hope of your ever being able (or particularly wanting) to do similar things yourself. All the magic is just hanging right out there for everyone to see. And it’s all just part of Ruby, a cute little language that’s fun to code.
And you think, yes, I can do this! Someday I too may tackle the continuation koans.
But not just yet.
Testing in Rails: Way More Trouble Than Flossing
So the other day Max and I had a joint interview for a Rails job, and the hiring manager obviously felt that our knowledge of testing in rails left something to be desired. Too true, too true. But he also told us that he thought that learning to test in rails, and learning TDD in general, was basically straightforward and simple. As in, “you are idiots that you flubbed your answers to my questions about it.” I am sure we are idiots for some other reasons, but not completely grokking TDD should not be one of them. If TDD were easy to grok and easy to do, there wouldn’t be so much evangelizing around it. There wouldn’t be courses and lectures and demos and new articles every day about why you might want to bother doing it. Here’s Gregory Brown, just a couple weeks ago, still having to argue that rails testing is Not Just for the Paranoid.” :
The real issue most people have with testing is not that they think it’s a bad idea, but that it often means a whole lot more configuration, a whole lot more to learn, and lots of things that smell like extra work. Folks who have been in that crowd will be pleasantly surprised when working with Rails.
Thanks Gregory, but no, they really won’t be pleasantly surprised. Or at least, not immediately. We’ve been working with rails testing since March, and it still smells like more stuff to learn and more work to do. I’m sure it’ll start seeming easy in the future, but right now, not so much.
First off, there’s fixtures. Apparently everyone important agrees that rails fixtures suck. But mostly no one tells you this when you’re first learning to write tests. They reload before every damn method, which would be useful, except that they slow your testing down amazingly. I was feeling very proud of myself for using a Rails Recipe for erb in my fixture files to generate lots and lots of test data for very little effort, and wow, did it show in test slowness, not so much on my machine, but on Max’s, which is older and slower. Then there’s that whole weird transactional fixtures flag that Max wrote about, that no one tells you about but that can cause your db not to look anything like what you expect at the end of a test method. Lots of people refuse to use fixtures at all, or only use them to, hmm, load data directly into the test db, not for testing. Other people point out that fixtures are a pain to keep updated when you make changes to your db, so every time your model changes, all your tests may break because your fixtures no longer work properly. So then a model change involves: change your model. Make a db migration. Change your fixtures. Change your test code. Someone has written a nice little fixture migration task, but at this point, I think we’ll just change our testing strategy to not involve much in the way of fixtures.
Then there’s the TDD/BDD and third-party testing tools thing. Do we invest our efforts in TDD even though BDD is the new big thing, so should we just skip straight to RSpec? Do we learn Test::Unit really well before we switch over to ZenTest’s Test::Rails? What about MonkeyTest? And rcov?
Oh, and how about assert_select? I turned around the other day and suddenly I was knee-deep in the DOM. All I wanted to do was check to make sure that when my user was viewing an item that belonged to him, he also saw two buttons, ‘edit’ and ‘delete’. And that when he wasn’t, he didn’t. It wasn’t obvious how to do it, and it turns out that if I want to make it easier to use assert_select, I probably need to be putting way more ids in my html tags. And then, I added a new feature, and a new button, and my tests broke.
Of course, tests are always breaking. I understand that it is a feature, not a bug, to be forced to understand all the implications of new code. Still, it’s frustrating.
Finally, and this is, perhaps, the root of the problem, there’s all the additional decision-making overhead imposed by the very act of testing. Not all this overhead is ‘good’ overhead — that is, not all of it ultimately contributes to the quality of your code. Most of it is just one niggly decision after another. How do I organize my test code? What do I test? How many tests are enough? What should be its own test method, and what should just be a couple of lines in some other test method? Should I use setup or not? Fixtures or not? Which frameworks? There are fifteen different assert methods that will do what I need them to do, in slightly different ways: which one should I use? Oh wait, is that one deprecated? How come this assert method doesn’t work? Oh, because it’s a Test::Rails method, and I’m not actually using Test::Rails, I just saw it somewhere. All those decisions are exhausting.
Bitch. Bitch. Bitch. I realize I may now have destroyed all my credibility as a test-driven-developer by complaining about all the things I don’t get and don’t like about TDD in rails. But I think it’s annoying to be struggling with something and read nothing on the internet about it other than “it’s easy and awesome”. I have drunk the TDD kool-aid, obviously, because if I hadn’t I wouldn’t bother with it since it obviously causes me a fair amount of pain. And maybe in six months I too will say “hey, yeah, testing in rails is easy and fun!” But right now, it’s neither easy nor fun. But right now, today, I am saying it loud and saying it proud, to you, the internets, to you, other struggling Rails developers, to you, the world: TDD is good for you, like flossing, but it is much, much harder.
The moral of this story is that every night as you floss your teeth, you should thank your lucky stars that something so good for you is also so easy to do. I know I will.
Transactional fixtures in Rails: a head-banger
Amy and I were banging our heads today over some model unit tests we were running in Rails. Why on earth did the following updates not show up in the database after the test suite ran? The assertions all behaved as expected.
item.postal_code = "02138" assert item.valid? assert item.save
I mean, consarn it, we saved the record! Shouldn’t it be in the database?
Well, the answer turned out to be fairly simple. ActiveRecord’s fixtures, will, by default, rollback everything that was done on the database during the method in question, unless you set
self.use_transactional_fixtures = false
in your test class. I had strongly been under the impression that the fixtures were loaded once at the beginning of each method within a test class.
Now that we know that the logic is actually behaving as expected, we are back to the default behavior (i.e., using transactional fixtures.)
Reference here.
Meta-object-class-thingies in Ruby
Today I read RubyFleebie on the Ruby Object Model :
Objects are instances of Classes, which are, of course, also objects. Object methods are stored inside the instance of their Class, but Class methods are stored inside something called a meta-class. The superclass of a meta-class is a meta-object-class. Or something like that.
Or just say, like the famous (to parents of preschoolers, anyway)three singing pigs: “la, la, la, everything’s an object!” and file it under “huh?!” along with dependency injection.
Anyway, the most important takeaway from this blog post (and yes, Max, I did use the term “takeaway” just to annoy you!) is that in Ruby even things that do not look anything like objects are objects. Unless they’re methods, even when they don’t look like methods. Which is why you can use the simply gorgeous construction 5.times do { #some stuff }. Look ma, no primitives!
quack. quack.
Capistrano and its gotchas
I did my first successful Capistrano deployment last night. The rubyonrails manual is pretty nice, though it is a bit out of date, and uses rake migrations, which are now deprecated in Capistrano. What really was a tremendous help for me was Coda Hale’s article *Time For A Grown-Up Server: Rails, Mongrel, Apache, Capistrano and You*, which not only convinced me of the superiority of a Mongrel cluster proxied via Apache’s mod\_proxy\_balancer to anything using FastCGI, but which also provided a fantastically useful walkthrough.
I was flummoxed for a bit by my failed deployment, when it turned out that all I had wrong was that the :repository variable in config/deploy.rb was set to something slightly wrong, so the remote Subversion client was unable to check out the code. And I even thought that I saw the activity appearing correctly in the Subversion server’s Apache logs. Once that was fixed, “cap cold_deploy” worked like a charm. The error was a bit inscrutable (to me) for a while. See the dumb syntax error? My “prj” abbreviation for “project” was what killed me. (That’s not the real project name; I have anonymized the thingy.)
my-host:~/project max$ cap cold_deploy
* executing task cold_deploy
* executing task update
** transaction: start
* executing task update_code
* querying latest revision…
svn: REPORT request failed on ‘/repos/!svn/bc/40/prj/trunk’
svn: ‘/repos/!svn/bc/40/prj/trunk’ path not found
*** [update_code] transaction: rollback
* [update_code] rolling back
* executing “rm -rf /u/apps/project/releases/20070601032656″
servers: [”www.project.com”]
Password:
[www.project.com] executing command
command finished
/usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/scm/subversion.rb:24:in `latest_revision’: Could not determine latest revision (RuntimeError)
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/configuration.rb:62:in `initialize’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/configuration.rb:89:in `call’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/configuration.rb:89:in `[]’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/configuration.rb:236:in `method_missing’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/scm/subversion.rb:63:in `checkout’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/recipes/standard.rb:80:in `load’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/actor.rb:159:in `instance_eval’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/actor.rb:159:in `update_code’
… 13 levels…
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/cli.rb:12:in `execute!’
from /usr/local/lib/ruby/gems/1.8/gems/capistrano-1.4.1/bin/cap:11
from /usr/local/bin/cap:16:in `load’
from /usr/local/bin/cap:16
Look out: Capistrano 2 is *just* about to come out, and migrating from 1.4 -> 2.0 will be somewhat involved.
I am profoundly disappointed that previous family commitments are going to keep me from attending this month’s Boston Ruby meeting, which includes a presentation by the delightfully acerbic Zed Shaw, the author of Mongrel.
