Fun Facts about Rails: nil.blank?

Posted by amy on September 02, 2007

$ script/console
Loading development environment.
>> nil.blank?
=> true
>> ''.blank?
=> true
>> [].blank?
=> true

That’s useful, but I had either never read it, or had read it and forgotten it. Apparently I’m not the only one.

Popularity: 15% [?]

Annals of Idiotic Bugs

Posted by amy on August 21, 2007

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!

Popularity: 13% [?]

12 Steps to Testing in Rails

Posted by amy on August 17, 2007

We’ve several times complained about testing in rails. It’s difficult. It’s confusing. It’s time-consuming. No one really shows you how to do it well. There are too many choices for methods. You feel inadequate. Still, we soldier on. Or at least, in theory we soldiered on. In practice, our test code languished.

Until. A major refactoring was required on an app. Tried to convince client that feature requiring refactoring was not really that important. Oh, yes it is, says client. Okay, says I, and go in with a sledgehammer.

Well duh, I broke everything. I managed to implement the feature, and broke practically everything else in the process. And I couldn’t run my tests, which I’d been avoiding since long before the sledgehammer got involved, so they were in no shape to tell me what I’d broken anyway. And so Max just kept sending me Trac notifications from the other room, and I fell into despair when I realized that I had turned the code base into a steaming pile of putrid excrement. I don’t deserve to call myself a programmer, I thought. If only I had been diligently testing, this would never have happened.

So that was my ‘hit-bottom’ moment, when I realized that I had no control over my code and that I was ready to give my code over to the higher power of test-driven-development. I just had to figure out how to do it.

A lot of things were holding me back from making the transition to TDD. The biggest one, I discovered, was perfectionism and overwhelm. So many different ways to test. So many different things to test. So many different rails luminaries talking about their favored testing methods. So many different testing plugins, add-ons, and approaches. Too many decisions. I would sit down to write tests and just be absolutely paralyzed.

Once I realized that my big problem was perfectionism, I thought immediately of FlyLady. FlyLady is the reason our household is no longer buried in laundry and our kitchen is no longer buried in dirty dishes. FlyLady has some really great hacks for getting housework done, and those hacks can be applied to writing test code too.

Here are the most important points that Flylady makes:

  • The goal is “progress, not perfection”.
  • Baby steps will get you there.
  • You can do anything for 15 minutes.

FlyLady counsels us to start with the tools we have on hand, not to try to do everything all at once, to put one habit in place before we start worrying about others. Most importantly, she constantly reminds us that housework done badly still, in her words, “blesses” your household. In the same way, testing done badly still blesses your application. Any testing is better than no testing. Ugly, non-DRY, simple, non-idiomatic, inefficient tests are still tests, and they’re getting you closer to where you want to be, testing-wise.

With these principles in mind, I’ve finally been making progress on developing the TDD habit. Here’s my very own 12-step program for testing in rails. I sincerely hope it helps other fledgling Rails TDD programmers, and I’ll keep everyone posted on my progress.

1) Admit that without tests, you have no real idea of what your code does. You have no control over your code.

2) Forgive yourself for all the untested code that you’ve written in the past.

3) Open up any one of the generated test files in any one of your rails projects, and write a test. Just one. Do not write fixtures. Do not decide you really need to be using RSpec instead and get distracted downloading and playing around with it. Do not spend a lot of time reading other peoples’ clever testing strategies. Don’t even think about mocks or stubs. Just write a test. Start with unit tests, they’re easiest.

4) When you’re done writing the test, applaud yourself.

5) Now open up the terminal, cd to your project dir, and type “rake test”.

6) When the test is done running, applaud yourself.

7) Now make the test pass.

8) Again, applause.

9) Do the whole thing again. And again. And again. Don’t do it for more than 15 minutes at a time. Set a timer, write 15 minutes of awful, non-idiomatic, stinky, not DRY, trivial test code, and when the timer rings, ‘rake test’ and give yourself a cookie.

I’m only at step 9. I think steps 10, 11, and 12 will be:

10) After a long time, testing will start to feel more natural. You can take a few minutes to fiddle with fixtures, if you want. You can branch out into assertions you haven’t used before. Go crazy with assert_select. No, now is not the time to check out rspec, rbehave, or cruisecontrol. Just keep writing tests.

11) By now, you’ve started to write your tests before writing your code. You don’t have to look up assertions. You’ve developed opinions about how to organize your test code, and you know what really bugs you about test code, what you wish it could do differently, what trips you up and slows you down. Now, and only now, are you ready to look into the various testing plugins, tools, and alternate testing theories.

12) You are now a testing master. Spread the TDD gospel far and wide.

Popularity: 17% [?]

Rails Ninjas We Are Not

Posted by amy on July 09, 2007

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.

Popularity: 11% [?]

What good is in_place_edit_for if it bypasses validations?

Posted by amy on July 07, 2007

I broke down and did some AJAX crap on our big rails app. Cool, I thought. I’ve got my drag-and-drop lists with acts_as_list and my in-place-edits. Don’t we look all sexy and modern? Except in_place_edit_for doesn’t bother validating changes to the model. Someone wrote a custom implementation which does do validation but I haven’t tried it out. I just yanked out my in-place-edits for the moment. I’m irritated. Gotchas everywhere. Oh, and I’m having routing issues today too.

On the plus side, I did solve some troubles I was having with Attachment_Fu’s thumbnailing. Though it’s choking now on destroy (thumbnail-delete troubles, I think I read about those somewhere). Full post on Attachment_Fu to come when we’ve ironed out all our weirdness with it.

Popularity: 9% [?]

“You know CSS, right?”

Posted by amy on June 29, 2007

Sure, I know CSS. Just like I know Javascript. But then your CSS does something weird, and you can’t figure out how to fix it, and you look online and you find stuff like this:

Be aware that most of the demos in this site employ the Holly hack to work correctly in IE, but now IE7 fails to read the old star-html hack which was the vehicle for feeding the Holly hack hasLayout fix. Further, IE7 cannot be shown a small height to trigger hasLayout as has been customary.

Or this:

Liquid layouts have their own problems in the wide screens, stretching both text lines and designs beyond belief in some cases. Besides the obvious, Explorer for Windows can also have very nasty bugs in liquid layouts when rigid content that shares space with floats happens to “lock up” the page width. When that happens, the bad old 3px bug induces content dropping, and the only cure is to use min-width to stop the shrinkage before lockup happens.

Unfortunately, IE does not support min-width as well as it supports the 3px bug, so a JavaScript is then needed to coerce compliance in IE. It’s a big pain in the you know where.

Really?That’s a big pain? You’re kidding me.

Anyway, all I want is for my footer to stay at the damn foot. This is only possible, apparently, if I can tell you in advance which one of three columns will be the longest. Or maybe there are some weird hacks that no longer work in IE7 that I could use. I’m not quite sure, because it turns out that CSS is not, as I’d previously believed, a mere aid to ensuring that your design is consistent across web pages and your html not too big, but an arcane alchemical pursuit, complete with footnotes.

More thoughts on this, but it’s my birthday, and apparently my son has bought a cupcake to share with me, that must be shared RIGHT NOW!

Popularity: 9% [?]

Testing in Rails: Way More Trouble Than Flossing

Posted by amy on June 27, 2007

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.

Popularity: 12% [?]

Transactional fixtures in Rails: a head-banger

Posted by max on June 26, 2007

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.

Popularity: 12% [?]

Moved to WordPress

Posted by amy on June 17, 2007

So we’ve moved the site over to WordPress from Typo. We experimented with two rails-based blogging engines, Typo and Mephisto (which seems more popular in the rails world right now), but WordPress is a mature and widely adopted platform and in the end it made more sense to us to go with it. We’d rather not be solving software problems others have solved a million times over. (Which is why we also won’t be producing a to-do-list app any time soon. Online to-do lists! A billion to choose from, and yet somehow, none of them make my work get done. Though actually, I just bought a copy of the PDF book Flexible Rails, since I’ve decided to pick up AS3/Flex in my spare time, and the tutorial project in the book is, of course, an online to-do list.)

I’ve been delaying posting this notice because I keep looking for a blog post I read a month ago which convinced me I ought to think about WordPress, as it was an explanation for a rails blog running on WP, and a damn good explanation at that. But I can’t for the life of me find it again. I found several other people who moved to WP after experimenting with the rails blogging engines, but not the post I remember. The explanation was, basically: right tool for right job. WP is good tool for blogging. No need to reinvent. Etc. Except the post was more eloquent than my restatement. Oh well. Lost in the ether.

Also, Max had to run a cron job doing some voodoo the details of which I forget to keep the Typo instance in good shape. WordPress is faster, and, we hope, more stable. (No, I am not making a comment about the stability and speed of Ruby on Rails in general, just a statement about one instance of one app on one host. YMMV.)

Anyway, Max has a script for migrating the database from Typo to WP, and he’ll post it any second now.

Popularity: 9% [?]

Meta-object-class-thingies in Ruby

Posted by amy on June 08, 2007

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.

Popularity: 5% [?]