---
title: Code Cowboy
teaser:
tags: web,rails,open source
author: Dan Croak
published_on: 2009-10-12
---

I've written before about [lightweight access
control](https://thoughtbot.com/blog/post/161233418/analysis-paralysis-access-control)
using Inherited Resource's `begin_of_association_chain` and raising
a 404.

I still prefer this approach in the vast majority of apps I work on, but it
doesn't work in the case where there is no relationship between a user and an
object other than access control.

![gunshot](https://thoughtbot-training.s3.amazonaws.com/images/high_noon_strut.png)

## custom

Last week, I had a need to differentiate access control to some controller
actions based on whether a signed in user was a `teacher` or `student`.

This is a simple need, and I'm loathe to introduce a large gem into the app for
what could just be a custom `before_filter`:

    class CoursesController < InheritedResources::Base
      actions :new, :show, :index

      before_filter :authenticate
      before_filter :deny_student, :only => [:new]

      protected

      def deny_student
        deny_access if current_user.student?
      end
    end

However, I recently saw [acl9](http://github.com/be9/acl9) mentioned on a
mailing list and really liked the DSL. Couldn't we have the best of both
worlds?

So, Josh Clayton and I wrote up a sub-set of acl9's DSL that would meet my
needs.

```ruby
module AccessControl
  def self.included(controller)
    controller.extend(ClassMethods)
    controller.send(:include, InstanceMethods)
  end

  module ClassMethods
    def access_control(options = {}, &block)
      before_filter(options) do |controller|
        controller.authenticate
      end

      before_filter(options) do |controller|
        controller.instance_eval(&block)
      end
    end
  end

  module InstanceMethods
    def allow(role, opts = {})
      if opts[:to].nil? || opts[:to].include?(action_name.to_sym)
        unless current_user.send("#{role}?")
          deny_access(opts[:flash])
        end
      end
    end

    def deny(role, opts = {})
      if opts[:from].nil? || opts[:from].include?(action_name.to_sym)
        if current_user.send("#{role}?")
          deny_access(opts[:flash])
        end
      end
    end
  end
end

ActionController::Base.send :include, AccessControl
```

![Gunshot](https://thoughtbot-training.s3.amazonaws.com/images/high_noon_saddlery.png)

## the DSL

In action:

```ruby
class CoursesController < InheritedResources::Base
  actions :new, :show, :index

  access_control do
    allow :teacher, to: [:new]
  end
end
```

Very expressive. Nice work, Oleg Dashevskii!

![strut](https://thoughtbot-training.s3.amazonaws.com/images/high_noon_gunshot.png)

## features we cared about

* optional flash mesage
* natural language (allow/to and deny/from)
* role is just a boolean on `User`

## opinions we could have

This will usually be included when most actions require a signed in user.
Therefore, we call `authenticate` and allow an ugly override for edge cases:

```ruby
class CoursesController < InheritedResources::Base
  actions :new, :show, :index

  access_control(:except => :show) do
    allow :teacher, :to => [:new]
  end
end
```

This is used with [Clearance](http://github.com/thoughtbot/clearance) and can
therefore rely on `authenticate`, `current_user`, and `deny_access`.

## `instance_eval`

Writing code with a pretty DSL in mind is exceedingly fun. The one downside
seems to be that scope can become confusing.

Yesterday I was messing with Rails app templates and read the source for the
[2.3 template
runner](http://github.com/rails/rails/blob/2-3-stable/railties/lib/rails_generator/generators/applications/app/template_runner.rb#L26).
It, like this custom access control DSL, also uses `instance_eval` as the key
line to make things work.

In the app template example, it was hard to figure out how to get the file path
of the original template.

I simply wanted to `require 'helper'`, a separate file in the app template, but
because of the scope within which it was `instance_eval`'d, `helper` could not
be found.

```ruby
in_root { self.instance_eval(code) }
```

The solution in that case was to take advantage of other public methods and
mess with the load path, which would probably an atrocious solution for a
vendored gem in a Rails app, but acceptable for a one-off script to generate a
Rails app:

```ruby
here = File.expand_path(File.dirname(template), File.join(root,'..'))
$LOAD_PATH << here
require 'helper'
```

In the access control example, it was hard to figure out how to have access to
`flash`, `redirect_to`, etc. from a class-level scope.

Similar to the `require 'helper'` example, your tests will fail if:

* `deny` and `access` are defined at the class level
* `instance_eval` is not used to delay evaluation until runtime
* you don't use `before_filter`'s block

The solution is to use blocks and lazy evaluation to control scope, but it can
be confusing to get there:

```ruby
before_filter(options) do |controller|
  controller.authenticate
end

before_filter(options) do |controller|
  controller.instance_eval(&block)
end
```

## not a code cowboy

Every time you decide to roll your own, remind yourself that you may waste time
getting lost in something like a scope problem you haven't seen before. Then,
once you get the rhythm down, be careful of a thought like "it won't take me
that long to write." Re-inventing the wheel has to be balanced with a specific
reason in addition to, "it will be fun for me."

The third-party ecosystem of gems and plugins is one reason why Rails is
awesome. However, writing custom code every now and again is worth it for
programmer pleasure, fewer lines of code and dependencies, and staying focused
on only what you need.

Ruby makes great DSLs, though, so don't be afraid to take inspiration from
existing code and try your hand at making beautiful code for a specific
purpose.

Visit our [Open Source page](https://thoughtbot.com/open-source) to learn more about our team's contributions.
