Author: Sharad Jain

Optimizing has_role? in acl9

acl9 is a an authorization library for rails applications. It is one of the widely used library if not the most widely used now. Our experience with acl9 shows that it might be heavy weight if your authorization needs are simpler (which most projects are) but could be useful for other projects.

If you've used acegi/spring-security for authorization in your java apps, you know that acl9 is very similar in principle and hence very powerful. In addition to primary roles, it provides object level permissions which are stored in a generic way separately from the objects being controlled, all without the need for handcoding/distributing your authorization columns in each authorization-object tables.

One place where acl9 differs from acegi is how it doesn't differentiate between a role and a permission. Acegi signifies roles as global permission level which allows you to do certain things (some action on any object of a given class). Where as, a "permission" controls whether your can take that action on a certain object of a class or not. Acl9 calls them all "roles" (primary-roles and object-roles). As you can imagine, a given user may have a few roles in system but end up with lot and lots of permissions in system depending on how many objects user owns etc. This may seem like good idea at first but it presents a unique problem which is not apparent at first. Since roles and permissions are not conceptually separate in acl9 - and that a user can have lots of them (few roles and lots of permissions) - prevents us from loading and caching them in memory. Why do we need to keep them in memory? Because you are querying user's primary roles most often in your rendering of pages.

For example, consider navigation-bar which is common in most applications. Different users are presented with different tabs in navigation-bar and this bar gets rendered on each request/response cycle. Whether to render a particular tab is conditional to whether a user has certain role (primary role in particular) or not. Since acl9 cannot keep all roles (and permissions) in memory, it has to perform database query every time it has to find whether a user has_role?(admin) or not. Given that there can be only a few primary-roles that the user will have in any system, it seems in-efficient to not cache them and go to database each time.

The solution would be to separate these primary-roles from permission-roles and cache them for each request. In acl9 this means overriding User.has_role? and user.has_role!.

class User
  def has_role?(role, object = nil)
    if object || !Role.primary?(role)
      super
    else
      primary_roles.collect(&:name).include?(role.to_s)
    end
  end

  def has_role!(role, object = nil)
    super
    @primary_roles = extract_primary_roles if(Role.primary?(role))
  end

  def primary_roles
    @primary_roles ||= extract_primary_roles
  end

  def extract_primary_roles
     self.role_objects.select { |r| r.primary? }
  end
  private :extract_primary_roles
end

That does it. You cache the primary-roles and leverage those for has_role? queries.

Unit Testing Sphinx

Sphinx (and its rails plugin thinking-sphinx) is my choice of search engine on ruby/rails project. It is powerful yet super easy to setup.

However, testing Sphinx code is not easy at first. Since Sphinx works by leverging database commit hooks, it cannot be tested within the bounds of unit testing framework that rails provides. This is understandable because, in rails testing, a transaction is started before each test that is bound to rollback after the test is finished. Since the test data is never committed, sphinx doesn't get a chance to index anything and cannot be tested.

The documentation for sphinx testing suggests using cucumber for integration testing. To me, cucumber test are still miles away from the smallest piece of sphinx code (inside Model) to be tested. So, I turned to how transactional code is tested in rails framework for some cue.

Here is what I ended up with:

 
class TransactionalUserTest < ActiveSupport::TestCase
  // any transactional test needs to have this
  self.use_transactional_fixtures = false
 
  context "with no users in database" do
    setup do
      // clear the existing data for our test - not sure if this affects other test but we use machinist instead of fixture files, so we should be good here.
      User.destroy_all
      UserProfile.destroy_all
    end
 
    context "with a few users created" do
      setup do
        @john = @david = nil
        // any data for sphinx test should be wrapped in transaction so sphinx can see these changes
        User.transaction do
          @john = User.make(:first_name => "John")
          @david = User.make(:first_name => "David")
        end
      end
      should "find user with first name john" do
        // start sphinx server
        ThinkingSphinx::Test.run do
          // give sphinx an opportunity to index newly added data (required before calling search)
          ThinkingSphinx::Test.index
          assert_equal([@john], User.search("john").collect)
          assert_equal([@david], User.search("david").collect)
          assert_equal([],User.search("cheese").collect)
        end
      end
    end
  end
end
 

Isn't it nicer to be able to test sphinx code in isolation :-)

Ruby/Rails: Loading Seed Data for Tests


Fixtures are notorious in rails. To get around issues like brittleness and multiple file flipping to understand single test, there have been better approaches using gems like fixture_replacement, machinist and factory_girl. No complains there. In my experience, fixture are still great for one thing: loading seed data. This is because seed data is often used by many many tests and they don't change often and hence won't cause tests to be brittle. Another great advantage of fixtures is that any fixture data is loaded once and only once for the entire test run.

Rails 2.3.4 includes a new rake task for loading seed data called db:seed. It suggests keeping all seed data as a ruby code inside of db/seeds.rb file. The issue with this is this is not DRY. You have duplicate set of representation for seed data: one side of seeds.rb and one in fixture files (.yml). Keeping them in sync is a pain and all the other disadvantages that come with not having single source of truth.

Problem

To have single source of seed data and be able to load that seed data once and only once for the entire test run.

Continue reading »

Authlogic: after the initial hype

d i g b e t h # 5
Creative Commons License photo credit: sammy may

On my rails projects, I've used restful_authentication before and I am using authlogic now. Even though I have passed the initial hesitation phase with authlogic, I can't say that I am totally sold.

What I like about authlogic is it refrains from providing any controller/view level support and handles model layer better. Instead, it provides a solid model functionality that is similar in principle to ActiveRecord and provides lots of how-to examples on how you might code your controllers/views/workflows. It does it well. Although authlogic is complemented for refraining from too much code generation, Authlogic still does a lot of magical stuff. You encounter this readily with tests. Instantiating and persisting a user will log you in! It is hard to test your User model from console since authlogic will fail if you try to instantiate User object in console. You have to jump thru hoops (include Authlogic, set proper controller reference) to get it to work. Continue reading »

Does your project have Code Ownership Culture?

Open Source Code Ownership Code Ownership is a well known term in software development. Depending on how you define it, it may be a good thing or bad. When a developer sees code-ownership as him/her owning a piece of codebase that only he/she understands enough to make changes, it is generally a bad thing. It is only when everybody is free to modify the code with a sense of responsibility that he/she should leave the code cleaner than how they found it, it is a good thing. In my view, code-ownership is a good thing when viewed as a responsibilty as opposed to a right. I view it as a Collective Code Ownership where code is not owned by a single person or pair but is owned by an entire team.

So, the question is: How to determine if your project/organization has that collective code ownership culture. And what team members (including managers :-) ) can do to create/encourage it.

Does your project have collective code ownership?
Here are few things you may want to ask yourself to determine if your organization/project has collective ownership culture.

Continue reading »

What should a good iteration contain

Yes, by now, we all know that agile works and what an agile project feels like. It has a set of guidelines like individuals over processes, embrace change and working software. It also recommends process tools like scrum, iteration planning, retrospective. And for developers it is manifested as a set of tools like pair-programming, continuous integration, TDD etc.

I have been on about 10 different agile projects in last 2 years. As a hands on developer, the one area that is of special interest to me is what constitutes an iteration, what deliverables and progress metrics it contains? Sure they all contain a set of stories to be delivered and a working software in the end. However, the risk for over promising and under delivering or vice-versa always exists.

The goal is to promise enough (not under) and deliver on it while still taking on a few unknown. Or put it another way, minimize risk somehow. A quick search on internet couldn't deliver a convincing set of traits that would do the same and I believe this area can use some refinement.
Continue reading »

Topics:

How to learn a new programming language or framework

bunny_tutorial.jpgWhile never untrue, it is more of a necessity now, that a programmer should know more than just one language or framework. After being a focussed Java/J2EE developer for a long time since college, in the last couple of years, I plunged into .NET, Ruby/Rails and then Javascript/prototype/jQuery etc and now onto groovy/grails. With name like Erlang, Scala, Compass, git, blueprint, flex flying around us everywhere, it can be overwhelming and we need a plan to pick, peruse, acquire them. Here is a list of things I do when learning a new skill.

Continue reading »

Stick with ERB or move to Haml

haml.jpg Haml is gaining popularity in Rails community. It claims higher productivity compared to defacto ERB templating. Not everybody agrees though. I see 2 short-term problem with haml.

  1. ERB is similar to it pre-decessor and hence easier to learn. Compared to JSP etc. ERB is similar, you still see lots of HTML tag with interleaved ruby (or Java). Although verbose, it is closer to how your HTML would finally look like.
  2. If your team has a dedicated HTML programmer (Designer as we may call them). These folks are very good at plain HTML and don't want the trouble of converting files and having all the plumbing around when working. It is not efficient for them.

Despite this, I see Haml as valid alternative for following reasons:

Continue reading »

Topics: , , ,

What makes Ruby/Rails Development Fun

I have been a full-time Ruby programmer for about a year now. I used ruby/rails before then but I didn't really "get it". Considering that I was a Java/J2EE guy before and never worked with dynamic languages, it wasn't surprising. Now that it has been a transformation and a worthy evolution, it is about time to review what makes ruby development fun. Yes, Ruby is known for its dynamism, expressiveness, malleability. But today I hope to list a few tools, techniques, concepts that make my programming experience fun these days. Here they are:

Continue reading »

Oracle and Sun: What it may mean for Open Source Landscape

The recent acquisition of Sun by Oracle, and not IBM, took the community by surprise. Open source Java developers have benefited immensely from Sun's Java and IBM's contribution to Java space. IBM has a generally favorable view from open source community since IBM has few significant open-source contributions including those to Apache software foundation and Eclipse. When I heard about IBM's talk of acquiring Sun, I was certainly bothered by the demise of Sun as a company but nevertheless hoped that whatever happens, Java and MySQL, and the strong community behind it, should stay largely intact. And I felt comfortable with Java landing in IBM's lap considering its largest contribution to Java community by any corporate vendor. Oracle is a strong and focussed company but its contribution to open source world is minimal. As open source developer or company, you are also concerned about the fate of mysql. Like everybody, I am trying to make sense of what this will mean for the open source developers.

Continue reading »

Topics: , ,

Remain Static or Go Dynamic?

The age old debate between static and dynamic languages has only become more prominent with the advent and wider adoption of languages like Ruby, Groovy. Recently, Pathfinder was approached by a client for an unbiased opinion on what technology stack would be suitable for their next endeavour, which is a re-write of their 10 year old existing application. Looking at their existing system, which had no traces of unit tests and code coverage, I felt uncomfortable suggesting Ruby/Rails. Why? a dynamic language (like Ruby/Rails) requires more disciplined approach to software development and can become unmaintainable for large projects if not managed properly with right tools and processes. Yes, that is one big statement. While I may have found a few supporters in static-language tent, I held doubt about it myself. To say the least, it is not proven. So, I set out to find what others have to say about these assumptions:

Continue reading »

activerecord tests: modify activerecord logging without tripping rollback convenience

When writing unit tests for model classes, it helps to print database queries on the STDOUT console. We can achieve this on a global level however I normally don't like to muck with defaults to achieve my local convenience so I came up with the following:
Continue reading »

ubuntu + firefox 3.0 + http://localhost = cookies won’t work

If you are a web-developer who recently switched to linux, you are likely to encounter this bug sooner rather than later. In summary, when using firefox on ubuntu to test against local web-app, be ware that this bug prevents cookies from being saved and send back to server properly. The work-around is to use 127.0.0.1 instead of localhost.

deprec is good, but needs taming.

I recently had to work on some deployment tasks and used deprec gem to check out how it can help. deprec is one of the most admired gem outside of pure rails application deployment arena. It is one of the most successful attempts at demonstrating how capistrano can be used as a more generic deployment tool and not just for deploying rails apps.

However, there are a few design choices that I think warrants more thought if I were to continue to use it successfully for all my deployment needs.
Continue reading »

handling CRLF in git

If you use git on windows or cygwin, I am sure you've encountered this.

$ git add dir/newfile
fatal: LF would be replaced by CRLF in dir/newfile

While there is much confusion/discussion around how to handle this using core.autocrlf and core.safecrlf config attributes, I have lately settled with this recommendation:
Continue reading »

Topics: , ,

Launch: Pathfinder Newsletter

    Get a monthly update on best practices for delivering successful software.

    Subscribe via email


    Subscribe via RSS      RSS icon

Topics

Search

WordPress

Comments about this site: info@pathf.com