Friday, October 28, 2011

accepts_nested_attributes_for, belongs_to, and has_many#build

There's a self-explainatory code sample before.

Basically, if you have accepts_nested_attributes_for on a belongs_to relation, you can't use model.has_many_relationship.build params[:has_many_relationship] -- Rails bugs out.

This is because, AFAIK, model.has_many_relationship.build params[:has_many_relationship]

assigns params[:has_many_relationship] first, BEFORE assigning the foreign keys that link the relationship with the model.

Code:


class User < ActiveRecord::Base
has_many :papers
end

class Paper < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
end



class PagesController
def create
# The below line FAILS;
# current_user.papers.build params[:paper]
paper = current_user.papers.build
paper.attribute
end
end


"current_user.papers.build params[:paper]" does this under the hood:

# this triggers accepts_nested_attributes_for, when user_id is currently blank, so it will fail.
Paper.new params[:paper]
Paper.user_id = current_user.id # too little, too late!

Wednesday, August 10, 2011

"What do you think of Cloud9 IDE?"

I think it'll fail.

Cloud9 IDE is bills itself as "development-as-a-service", but it's really just a web-based editor with some built-in support for running Node.js applications. Don't get me wrong, it's a really good web-based editor, but alone isn't going to cut it.

I mean, sure, you can run Node.js... but what about Ruby? Python? PHP? Yeah, you can edit the files, but what good is that without being able to test those changes? Deploy them to a staging server? Production? Run your project's test suites?

Frankly, I think they're got the right idea but the wrong product.

I think they should be selling a "Cloud9 DE" -- a cloud-based development environment.

Let me tell you a story about an old, old Rails project I worked on. It was a popular site -- had millions of visitors a month -- but it was built using the 0.x series of Rails. Old as dirt. Development on it had started way before we got sweet things like Bundler, a more robust Rubygems, etc. And that was reflected in the codebase and some of the hand-written C libraries we had to use to hook into system libraries, etc.

In fact...

It was so damn old and brittle that we couldn't get a local copy running, for any of the developers. Instead, what Our Glorious Leader decided was that he would make copies of the actual production instance running on EC2, scrub the database, and then spin up an EC2 instance with these modified images for each developer.

We worked through SSH, mainly using Vim or Nano, but I actually got some "SSH filesystem" deal going on Ubuntu (can't remember, FUSE?) and could edit my files using Gedit and etc.

It was awful, fucking awful, let me tell you. A completely miserable experience. But if the code weren't such shit, and the concept had been fleshed out just a little more...

So, interlude over, and back to the topic at hand: Cloud9 IDE is the right idea, wrong product.

I think they should be selling remote development environments -- prepackaged Amazon EC2 images, spun up and down on demand, billed by the minute and ready to go for whenever you need to start hacking.

One click should get me a prepackaged EC2 instance ready for the latest Ruby on Rails development, and one more should get me a public (or private) Git repo checked out and ready for development on that EC2 instance.

You'll always get a clean system for every project. Don't run MySQL/etc in the background if this project doesn't need it.

You'll always have SSH access, so if you need to do some tooling around in that project's instance, no problem. Need to run tests, or some other custom shell command? No problem.

You'll always have access to your development machine, no matter where you are, via the Cloud9 IDE itself. Don't like the interface? Mount the filesystem using FUSE and hack the code with your favorite IDE.

Taking it one step further, let teams create their own prepackaged developer images so that getting a new developer set up is as simple as adding him to a team in the Cloud9 IDE. Now you're suddenly measuring developer set up time in minutes.

That's valuable. That's worth money.

A web-based editor for $14.99/mo? No.

Remote development environments like the one above ~$60/mo? Hell yes.

Thursday, May 26, 2011

oDesk WTFs

Applicants that:
  • Apply to a job, but state very clearly when asked that they have no experience in the relevant technology and have no intention of learning the required technology
  • Apply to a job, but state that they have no intention of finishing the project within the alloted budget
  • Apply to a job, beg for a chance, then completely ignore instructions and try to sell you some half-baked CMS they had developed for another client

Sunday, May 15, 2011

Ubuntu v. Fedora

WTF.

So many bugs in Ubuntu 11.04, all of them with Unity.

  • Crazy graphical errors that make it impossible to work (I mean that literally),
  • Unity steals title bars at random so I can't can't drag some title bars for dialogs or windows,
  • the global menu steals some (SOME) of the menu bars in Eclipse, but not others, leaving me in a fucked up wasteland of not being able to access functionality without knowing the keyboard shortcut,
  • Unity decides that no, it does not need to hide at the moment, and there's nothing you can do about it, so the leftmost 50ish pixels of my applications are completely inaccessible,
All this shit for a dock that doesn't do anything yet.

Fedora 15 works like a dream on my laptop, no weird errors or anything like what Unity's been boning me with. I'm looking into exactly what it would take to migrate my development machines from Ubuntu 11.04 to Fedora 15.

The only alternative is to wait 6 months and *hope* Unity stops being so goddamn buggy. I want to like it, but Unity seems less like a product and more of a promise of what could be.

Saturday, April 30, 2011

UJS drivers (rails.js / jquery-ujs.js) -- load them LAST.

Don't load your UJS driver (rails.js or jquery-ujs.js) before your application logic JavaScript.



Why? Because your UJS driver is going to hook into the submission events for ajax elements. If you need to run a validation (or anything like it) that has to be executed BEFORE form submission occurs, because it may cancel the submission event, you need to have that code hook into the submission events before your UJS driver does.

Therefore, load your UJS driver last.

Friday, April 08, 2011

Mint.com is pretty awful now.

Mint sucks. What happened? After Intuit bought them, they added support for one of my previously unlisted banks, but then almost immediately all four Bank of America accounts I had inputted stopped updating.

And just awhile ago, my Prosper account stopped updating.

So now I have:

* a PayPal account I get non-stop "low balance" warnings for, even though the balance hasn't changed in over a year,
* a car note account that doesn't show my remaining balance,
* An Ally CD,
* and one bank account.


The most hilarious moment of this has to be that today I got an email from Mint, claiming that they've improved their back-end so now they don't talk to a 3rd party any more to get your bank updates: they connect directly to the financial institutions instead. Too bad connecting directly with the banks is apparently less robust than connecting through that 3rd party, am-i-rite?

Runner up for most hilarious moment: Mint claims that you have to turn off all (ALL) of Bank of America's three-factor security mechanisms in order for Mint to work, because they're "unsupported." I have an account with another bank that updates perfectly fine via Mint, and it uses the same three-factor security that Bank of America does.

It's unfortunate that Wesabe and the rest of them died off so quickly; they probably could have used this moment to start picking up customers as they drop off of Mint.

There is no way I'm turning off any bank's additional security. I've already had my identity thiefed twice (caught by the bank both times before they did any real damage), I am not making it easier for someone to ninja my bank account, because, you know, there is MONEY IN THEM THERE ACCOUNTS.

Wednesday, April 06, 2011

Making Jammit jam with Heroku

So, you want to use Heroku and Jammit together, and you've come here of all places! I know, there's no good solution for this floating around The Interwebs, so I figured one out myself, and now I'm publishing so that you, YOU THE VIEWER, can be both shocked and amazed.

There's a nicely formatted gist right here, or you can read it inline below:





Yes, that large hack floating around in the middle is specifically for Heroku. If you're on another cloud service that is a little less wizardly, you can drop the class_eval block entirely and you should be good to go.

If you're wondering if the resultant files will be cached by Heroku's Varnish HTTP accelerator: yes. Rack::Static will return the fetched files as Rack::File objects, which Heroku caches.



UPDATE: if it's not obvious, this needs to go into config/initializers -- so it runs once on app start up.

Monday, March 21, 2011

Ubuntu --> openSuse --> Fedora --> Ubuntu

Last night:

Installed openSuse on my laptop, overwriting my Ubuntu Natty install. Installer is laggy. Doesn't have the firmware for my wireless. Can't get the gnome shell setup script to work without modification. Gnome Shell build fails anyway. Can't get wireless drivers installed. Give up.

Install Fedora 15. Install is clumsy and demands internet connection. It detects wireless, but won't activate it. Installer allows me to continue anyway. I end up at a strangely themed Gnome 2 desktop. I dig out a wireless USB adapter and start the install over. This time, I end up with Gnome Shell. Looks good. Nice performance. Oh, nice security update notification. Start installing updates. Screen suddenly fades as I'm surfing web. The screen is locked, asking for a password. Mouse works, keyboard doesn't. I let the updates go for an hour; when I come back, keyboard works again. I play around a little, then restart. Can't get past Fedora's boot splash.

Wait an hour, then install Ubuntu. Cant detect wireless at first. Nothing bad happens, and on first boot it asks if I want to enable my wireless. I do. It works. It rebooted fine.

All I wanted to do was use Gnome Shell, but if it isn't available for Ubuntu, its gonna be a problem.

Sunday, March 13, 2011

One way MongoDB will get you in trouble if you're not careful.

One way MongoDB will get you in trouble if you're not careful:

Storing everything in a single document.

An example I see a lot of is storing blog posts and the associated comments inside of a single MongoDB document. For instance, this presentation about scaling with MongoDB uses the following example schema:

{
_id: ObjectID('Incredibly Long, unfriendly GUID'),
author: 'roger',
date: 'Some random Date String',
text: 'This is the main body of the blog post.',
comments_count: 1,
comments: [
{ author: 'Gretchen',
date: 'Yesterday',
text: 'This is a spam comment; there are no real comments on the Internet.',
}
]
}

What's wrong with this schema? Like, 80 million things.

What happens when you want to collect every blog post author and show it somewhere on the blog, let's say as an "authors" sidebar?

When you want to show the site's most recent comments, by date?

Show a billboard of your blog's most prolific commenters and their highest rated comments?

You see where I'm going with this. Theoretically, you could write a map reduce function for all of the above queries -- theoretically. Looking at it from the perspective of a pragmatic programmer, though, do you really want to dip your feet into what are essentially SQL's Stored Procedures?

Make no mistake, the syntax is different, but once you start writing a map reduce function for any of the above queries, you have to maintain it -- whenever the schema changes, you have to update it, whenever the data moves, you have to update it. Poor schema modeling will turn the beauties of an efficient map reduce into a maintenance nightmare.

There's a right time to jam everything into one document, and there's a wrong time.

The wrong time: any valuable data you are going to want to isolate and iterate through, without having to load a possibly enormous parent document into memory first. These are the basics in relational models: the user model, the comment model, the blog post model. See above for the laundry list of reasons why.

The right time: miscellaneous data. Metadata. Any kind of data that won't fit cleanly into a relational model, or any kind of data that will be awkward to work with when its been detached from a document.

Too vague?

Let's say you want users of your site to be able to hide certain posts (blog posts OR comments) by certain authors ("it offends my eyes!"). You add an attribute to the User document, "hidden_authors," which is an array of ObjectIDs.

Why?

1) The attribute has no meaning outside of the User document.

2) In general if you need to access a User document's hidden_authors attribute you will have already loaded that document into memory. If you haven't, thanks to MongoDB's excellent querying you can query inside of the array, which covers most cases ("Is this author blocked by this user?") quite nicely.

3) It literally makes no sense as a separate document. As a separate document, it would end up being more unwieldy: not only would you need the hidden_authors attribute on this second document, but you'd also need an attribute to point to the related User document. What have you gained? Nothing. You've actually lost some flexibility, since now you're dealing with two documents. In a relational database like MySQL or Postgres, you've got no choice, but in MongoDB the easier way is also the better way in this case.

I know the whole "blog post + comments = single document" is the canonical example for everyone who discusses MongoDB, but I really wish people would just let it die and be replaced by something that makes more sense. If you've had your head deep enough in databases, when you see that example you see something very "brittle" and something that is going to give you some headaches in the near future.

Thursday, February 03, 2011

Rubymine is...

...fat, and slow, and a total resource hog...

But nothing beats it.

I just spent some time tonight doing the IDE dance -- every once in awhile you have to go through all the long forgotten development environment options to see if you're missing out -- and I'm still where I am 2 years ago when I first purchased RubyMine: there is nothing else like it.

Aptana Studio 3 still sucks (it finally got SCSS support, though), NetBeans is terrible as always (and is apparently being discontinued, no surprise there), and I still don't have the MANLY STEEL required to set up vim for Ruby/Rails and stick with it.

So, RubyMine for the win (again). In a few months I'll be purchasing my, what, third license for it? I hope they keep up the steady development pace.