An intro to CanCan and managing permissions, authorization

CanCan is our goto library for managing permissions in our applications. Like any library, you have to know how to use it. It comes with its own set of nuances and patterns. If you don't properly organize and manage it, you'll end up with a load of technical debt.

Before getting into details, you should understand a few key details about CanCan. These are details we've run into many times before and it always seems to trip up new people using the CanCan library. 

  1. check_authorization  If you're using CanCan, you'll want to be sure you are checking authorization. This happens in your controllers. Most of the time, it should be an exception if you skip authorization. Why would you define a bunch of permissions and then forget to authorize against them?
  2. load_and_authorize_resource:  Based on the permissions you've defined in your abilities file, CanCan can load and authorize your models in your controllers. For example, if you have a PostsController and you use the index action, CanCan will load all @posts which a user has access to. There are exceptions and loading your index action will fail if you use a block to define permissions.
  3. Ability precedence:  This is one of the most important gotchas and you may lose some time trying to debug this. Make sure you read about ability precedence and experiment with it. It's important to note that with CanCan, manage means any. If you can manage a post, you can perform any action on that post. The first permission you define takes precedent over any that follow.

Here's a block of code to help you understand the points above: 

With the introduction of strong_parameters in Rails 4 (also a great pattern you can use in your Rails 3 projects), you'll want to have a pattern for using it in unison with CanCan. CanCan doesn't natively support strong_parameters yet. CanCan attempts to load params before being filtered by strong_parameters; thus, strong_parameters raises an exception.

For us, we've started to use cancan_strong_parameters  which patches CanCan to allow strong_parameters. We'll try to update this post when CanCan begins to support strong_parameters.

How do you handle strong_parameters with CanCan? Let us know in the comments below. 

 

Software is not bricks

I've had a number of conversations lately with people who are building web products to either support an existing business, or to start a new business entirely. These conversations take place with existing clients, prospective clients, friends and family members. 

We make software, so we have these conversations frequently. But it seems now more than ever everyone has an idea for an app.

One theme that keeps coming up is that people will often compare a software project to some sort of other 'real world' project that they can relate to. This makes sense, because by relating their idea to something they have experience with it helps them to understand the process of building something.

Indeed, we'll often use brick and mortar analogies saying something like "we'll definitely want to clean that up later, but you don't start hanging the paintings before you put up the drywall" if we're explaining why it's not quite time to work on a new icon.

But there are very real and important ways to understand how 'software is not bricks'. If you're thinking of building an application of any kind, I think these are some good things to keep in mind.

Most People have a frame of reference for the cost of bricks, but not for software

Just about everyone pays a monthly rent or mortgage on a home. We also tend to have a general understanding that the city in which you live has an impact on your home. We know that a home in San Francisco is more expensive than Iowa or Nebraska. Because of this, we have a built in frame of reference for how much things cost. 

The exact opposite is true with software.

Most people interact only with software that has had tens of millions of dollars worth of design and development effort put into it, and most people have never used the first version of a beta product. Their frame of reference for how software should work are Facebook, Twitter, Square, iOS, and maybe something like Salesforce and some productivity suite from Microsoft. 

The kicker is that just about no one goes to Facebook and thinks to themselves, 'wow this is some nice software, I bet it cost a fortune to make.' But if you walked into a 4 bedroom single family house in San Francisco that looked over the golden gate bridge you would know it took some real money to purchase. 

The industry helps perpetuate this with stories of 'kids in hoodies' hacking all night and then selling it for a couple million dollars. The difficult work that comes for years after is treated like a footnote.

Value is based primarily on the number of people that use your product

If you spend a million dollars building an office complex and you don't rent it out to anyone, it still has some intrinsic value. It's highly unlikely that the value of the building will reach zero. Likewise, putting 100 people in a small apartment will do nothing to improve the value of the apartment.

Again, software is the opposite.

 You could spend a million dollars having the best development team in the world writing the cleanest code with the perfect design that you imagined. But if no one is using it, or if it's not solving a real problem or providing real entertainment value, then it really doesn't matter how much time or money you spent building the software. A million dollar investment in software could in fact be worth close to nothing.

Of course there's an opportunity here which is that if you can work like crazy to solve real problems and get users, the simple fact that you have customers can help you overcome a lot of other issues, even if your product isn't as robust as you want it to be.

Limitations on software are less obvious

If you were building a house and suddenly decided it might be sweet to have a swimming pool on the roof, you have a built in understanding that this change would require significant effort to accomplish. With software, the limitations are so much less obvious that you have to constrain yourself because you can do just about anything. 

It's possible to do so much, that you can actually do too much.

Software is not bricks

It's not a good or a bad thing that software is not bricks. But if you're thinking of starting a project make sure you're aware that both the risks and rewards are inherently different from those in the physical world, and this reality can work with you or against you.

Build wisely.

 

Do you write bad CSS?

CSS is so powerful because you can do so much with it. It's constantly improving. CSS3 is an amazing advancement for web developers. 

However, since you can write CSS however you'd like, a lot of people aren't very good at writing it - myself included. Over the past few months, I've challenged myself and our team to improve. Here's what I've learned: 

Don't style elements by ID

It's tempting. You can do it. But, you shouldn't. Avoid it at all costs. 

IDs are meant to be unique. If you style an ID tag, it means you're styling a unique element; therefore, you're not writing reusable CSS. Remember the DRY principle? Styling an ID is a blatant violation of the DRY principle. 

Avoid more than three levels of nesting

Deep nesting lends itself to CSS that isn't reusable. If you have more than three levels of nesting, you're probably styling elements based on their container. When you have many levels of nesting, the context of an element dictates its style. Most of the time deep nesting will cause problems.  Deep nesting should be the exception, and not a common pattern.

Naming is hard

Naming is notoriously difficult, and it's just as difficult while writing stylesheets. Try to describe the element you're styling in English. Don't skimp on naming in exchange for less typing, but don't use extremely long class names either. 

Do you want to understand your code in 6 months? Try hard to improve naming. 

Think of elements in terms of modules or components

If you start thinking in terms of modules and components, you'll start to write better CSS. Sometimes, context matters; and therefore, calls for you to do some nesting. More often than not, nesting is bad. 

Components should be reusable. If you want to put a component on a different page in a different context, it should still look the same. If it doesn't look the same, it's either a slight variation of the component or its a completely new component altogether. 

Split components into separate files

Have you ever worked on a project with one massive, ugly, disorganized stylesheet? I think we all have - and it's no fun. A good practice is organizing your stylesheets by component. Styling some tabs to be used throughout your application? Use tabs.css as a filename. What about a header component? Use header.css.

If you're worried about including many stylesheets in production, don't. You should be using stylesheet compilation. If you're using Rails, we have the asset pipeline to help us do this.  If you need a standalone solution, try YUI compressor.

 

This is fun: What it means to deploy

Releasing new code is extremely fun. Never take it for granted. The moment you're bored shipping new code is the moment you should consider finding a new gig.

Here's why: 

  1. Shipping new code means people can use and see it immediately.
  2. Each time you deploy, you're shipping a NEW VERSION. 
  3. You get emails thanking you. 
  4. People notice. 
  5. If you break something, you'll know. 

People thank you for your work.

This is motivation alone. Your entire team, the people that brainstormed, planned, designed, implemented, and shipped that new version - you get to be thanked by people who love what you do. Every day.

Never take that for granted. 

What else can you be doing where this happens? Garbage men don't get thanked every day (although they should). The mailman surely doesn't get thanked every day (although he should). 

Realize what you do is powerful. You're inspiring people. They care about what you do. 

You might be making their business better. Maybe, you're the entertainment in that person's life. You might even be helping them through a tough time. 

Just realize you're communicating to people. You may never meet them. You may never say a word to them. But they're thinking about you.  Trust me.

Handling subdomains for Rails in your development environment

We built Tula with subdomains from the beginning, so we needed a nice way to handle subdomains in our development environments. We used pow for some time, but that wasn't the perfect solution for me. That's because I wanted a few things out of a solution: 

  • Configure it once and forget about it
  • Know exactly when my server was started and stopped
  • Use whatever I wanted as an app server i.e. unicorn

It took us awhile to settle on this solution, so here it is. It uses a combination of Apache (or nginx) and dnsmasq which I've become a huge fan of. 

The first part is simple. You'll want to install and use dnsmasq. It's a nice, lightweight and local DNS provider that will run on your machine. You can serve the names of local machines which are not part of the global DNS. 

It's easy to install on both Linux and Mac. 

# On Ubuntu Linux
sudo apt-get install dnsmasq

# On Mac with Homebrew
brew install dnsmasq

Once installed, you'll want to add the following to your dnsmasq.conf file. This will resolve any domain with a TLD of .dev to your local machine. This is handy if you have a lot of projects (Rails or otherwise) in the same directory. 

Next, you'll want to configure Apache (or nginx) as the following. The key for Apache is VirtualDocumentRoot. It allows you to set the document root based on various parts of the domain name. In this case, I've taken the main part of the domain name as the document root. The domain name will resolve to a project in my Projects directory. This will always work if I continue to use my Projects directory for Rails projects.

If you set this up once for your Rails projects, you'll never have to worry about adding anything to your hosts file, nor will you have to worry about port numbers. It's all taken care of for you.  You can access your subdomains as you would normally. It's important to note that unicorn is running on port 5000 in this example.