Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Monthly Archives: July 2007

Pivotal Labs

Access Control & Permissions in Rails

Pivotal Labs
Thursday, July 26, 2007

Access Control is a simple idea. We want company employees to be able to delete inappropriate content; but random Users cannot. Here I propose one way to implement Access Control that has the particular advantage of being very general, very concise, and unlikely to be violated. I call it RESTful Access Control.

What is RESTful Access Control?

When we model RESTfully the Application Interface (i.e., the HTTP interface), we construe Resources as responding to a simple set of Verbs: Get, Put, Post, Delete. To the extent that our entire application is designed this way, we can Control all Access to our Application with perfect granularity: as being a set of Permissions to perform these four Verbs on a corresponding Resource. Let’s start with an example.

Suppose a User can add Members to a Group. How do we determine if this or that User can create a Membership? This logic doesn’t belong in the controller — call me a prig, but Business Logic belongs in the Model. Anything else is unbecoming. Therefore, we have a Controller like:

class MembershipsController < ApplicationController
  before_filter :load_group

  def create
    membership = @group.memberships.build(params[:membership])
    raise SecurityTransgression unless current_user.can_create?(membership)
    ...
  end

  def load_group
    @group = Group.find(params[:group_id])
  end
end

Let’s implement the can_create? method. Despite the above Formulaic code, the User Class isn’t really the proper place for the Logic: different kinds of resources are likely to have different rules. Thus, we implement the Logic in the Model being created:

class Membership < ActiveRecord::Base
  def can_be_created_by?(user)
    ...
  end
end

I call the above “the Passive Voice.” I prefer, for various reasons, to use the “Active Voice”, and therefore we implement a simple Proxy in the User Class:

class User < ActiveRecord::Base
  def can_create?(resource)
    resource.can_be_created_by?(self)
  end
end

Of course, this “Active Voice” implementation requires that we follow the Null Object Pattern for Users who are not Logged In, otherwise we’ll produce Errors when we ask if a Logged Out User has Permission to do something:

class AnonymousUser < User
  ...
end

Why we Always Create An Instance Before Checking Permission

In our Controller Action above, we first build an instance of a Model in memory, then ask for Permission.

membership = @group.memberships.build(params[:membership])
raise SecurityTransgression unless current_user.can_create?(membership)

But why even create the Model in memory it shall not be persisted? Well, for some advanced Access Control Rules, we need all of the data available to an Instance in order to proceed. Suppose, for example, that only the Owner of a Group can create Memberships. The simplest way to enforce this rule is to reference the Group Owner in the can_be_created_by? method:

class Membership
  belongs_to :group

  def can_be_created_by?(user)
    group.owner == user
  end
end

Similarly, can_be_destroyed_by?, can_be_updated_by?, and can_be_read_by? all must be instance methods. This provides the maximum flexibility and a consistent Interface.

This is a robust Pattern for Access Control. It extends brilliantly to User Roles:

def can_be_destroyed_by?(user)
  user.admin? or ...
end

Even a per-user Access Control scheme where we grant individual Users permission to manipulate individual objects can elegantly fit in. Consider something like the following:

class Permission
  belongs_to :user
  belongs_to :resource, :polymorphic => true
end

class CreatePermission < Permission
end

class Membership
  has_many :create_permissions, :as => :resource

  def can_be_created_by?(user)
    create_permissions.find_by_user_id(user)
  end
end

Handling Access Control in the Views

Access Control has View consequences as well. For example, we shouldn’t show a destroy button if the User lacks permission to perform that Action. Given the above implementation, this is simple enough:

 <%= link_to_unless current_user.can_destroy?(resource), 'destroy', ... %>

Why Exceptions?

Above, I’ve proposed using Exceptions to handle Security Transgressions. (At Pivotal, we call these Exceptions SecurityTransgressions because it has a more romantic air than the banal AccessDenied). Normally, these Transgressions cannot happen: in your Templates you will not even display links to modify an object if the User lacks Permission. So Transgressions occur only when a User is fiddling about with nefarious intent. So we can handle misbehavior consistently across the site, by (for example) rendering a HTTP 403 Forbidden Response. Exceptions are a neat way to do this, because Rails gives us a systematic way to handle exceptions with rescue_action:

 class SecurityTransgression < StandardError; end

 def create
   raise SecurityTransgression unless ...
 end

class ApplicationController < ActionController::Base
  def rescue_action(e)
    case e
    when SecurityTransgression
      head :forbidden
    end
  end
end

Ensuring Programmers Remember to do Access Control And How to Avoid Over-Engineering

The biggest danger with Access Control rules is the possibility that a careless Programmer might forget to implement them. Having a consistent, terse pattern for Access Control goes some way towards mitigating this problem. When all Access Control is as simple as adding a can_create? check to your Actions, Access Control is unlikely to be overlooked.

The Second biggest danger in Access Control is over-engineering. Suppose we want to enforce Access Control logic. Rails gives us some tools to do this. Well, Rails gives us just enough rope to hang ourselves. There are some serious disadvantages to the approach I am going to propose now, but we’ll get to that shortly.

Rails has something called an Around Filter. An Around Filter, like a Before and After Filter, is a Filter applied to every Action. But this Around filter is like the Heavenly Union of the Before and After Filters: both great tasting and less filling, it can do work before and after invoking the Action.

class ApplicationController
  around_filter :ensure_permission_to_create, :only => :create

  def ensure_permission_to_create
    class_name = ModelsController.to_s.demodulize.gsub(/Controller$/,'').singularize
param_name = class_name.downcase
    instance_variable_name = "@#{class_name.downcase}"

    instance_variable_set instance_variable_name, class_name.constantize.new(params[param_name])
    if current_user.can_create?(instance_variable_get instance_variable_name)
      yield # the create acction is invoked here.
    else
      head :forbidden
    end
  end
end

Whew. In the above implementation, control is yielded to the Action only if the User has permission. The instance of the Model is also built for us automatically; so, our Formulaic create Action becomes:

def create
  if @model.save
    ...
  end
end

Very DRY, But this is, again, just enough rope to hang ourselves with. Our Controllers need to be named exactly right, our parameters without an inconsistency, and so forth. This is not a problem in the World of Forms, but in Reality it may require some coding contortions. The tricky metaprogramming and impertinent assumptions in ensure_permision... only get nastier when we want to make a Nested Resource, and build our Model using a proxy (as in the previous example: @group.memberships.build(params([:membership])). Finally, where we have Controllers that do not map directly to ActiveRecords, we would need to introduce a Model layer that responded to the Interface defined in ensure_permission... We often want to do this, but not always. Being forced to might suck. So I offer this design strategy with much caution.

The Exception based approach, while a bit more verbose, is battle-tested and works in Practice. In any case, pushing the logic to the Model with can_be_created_by? will certainly work, regardless of whether you take the Around Filter approach or the Exception-Based one.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Nathan Wilmes

Til the End of Time (or Time.now)

Nathan Wilmes
Wednesday, July 18, 2007

Sooner or later, every test-driven developer discovers that they need a superpower – the power to control time. Let’s say you’re working on a scheduling system. You’re going to want to write tests that say, “Assume that it’s 2PM on January 3rd and this user does THIS. What happens as a result? What happens at 4PM on January 3rd as a result?”

One of the joys of writing in Rails is the sheer power you have to change your application universe at almost any level you choose. As a result, we’ve come up with a variety of ways to solve this problem. As it turns out, with great power comes great responsibility. (I’m not sure why I’m going all comic book right now, but let’s run with it).

Stubbing Time

One of the cooler features of the latest generation of mocking frameworks like FlexMock and Mocha is the ability to stub any method you choose and replace its functionality with a new one of your choosing.. and then the framework will clean up after you when the test is over!

This leads us to some intriguing possibilities such as the following:

def test_party
  Time.stubs(:now).returns(Time.local(1999, 'Jan', 1))
  people(:nathan).party
  assert people(:nathan).very_drunk?
end

and for the duration of the test, Rails will decide that it needs to party like it’s 1999. Sounds great, right?

Well, there’s just a teeny catch.

Let’s try benchmarking the test_party method.

Benchmark.measure do |b|
  ... test_party
end

And you’ll discover that this test takes -2000000 seconds to run!

Here’s another problem area:

def test_partying_in_selenium
  Time.stubs (:now).returns(Time.local(1999, 'Jan', 1))
  click "link=Party!"
  wait_for {get_text("id=sobriety") == "drunk"}
end

The issue with this method is that the wait_for method relies on Time.now to time out.. and Time has now been mocked out for the duration of the test. So we end up with a Selenium test that takes forever.

So doing a mass Time.now stub will work, but stubs out the test framework along with your application. Not a great solution.

How about this?

A Time wrapper for your application

The idea here is that we define a time wrapper class that we use for our application.. let’s call it Clock. The idea of the Clock object is that the application refers to the Clock every time it needs to know what time it is. Clock would have a very similar API to Time.. we can use Clock.now instead of Time.now, and switching over is as simple as a global search and replace.

Clock.now does exactly the same thing as Time.now… except when you’re running tests. When you run tests, you suddenly get access to clock-controlling methods, and can change what the application’s sense of ‘now’ is for the duration of a test.

Here’s a simple implementation of Clock:

in lib/clock.rb:

class Clock
  def self.now
     Time.now
  end
end

in mocks/test/lib/clock.rb:

class Clock
  def self.now
     @@now ||= Time.now
  end

  def self.now=(new_time)
     @@now = new_time
  end
end

To finish off, here’s example test code that uses this:

def test_party
  Clock.now = Time.local(1999, 'Jan', 1)
  people(:nathan).party
  assert people(:nathan).very_drunk?
end

def teardown
  Clock.now = Time.now
end

Some other benefits to this approach is that you have a handy place to add fancier setters to Clock. You can use methods like Clock.tick(2.hours), Clock.advance_to_midnight, et cetera. The actual implementations of these methods would be very simple, and I’ll leave them as an exercise for the reader who wants to use them.

Here’s some issues you’ll run into, though:

  • The implementation I wrote above doesn’t automatically tear down the Clock time override after your test is done. As a result, you’ll have to do this teardown yourself. If you don’t, later tests will think that Clock.now is whatever the previous tests say it is, and you may end up with fragile interactions between tests as a result. Very bad.
  • Rails has many lower-level methods that use Time.now directly, and these methods don’t easily switch over to Clock.now. Among the more interesting ones are the created_at and updated_at methods, and constructs like 3.days.from_now and 5.hours.ago. So, you’d need workarounds to test these methods.

Here’s a case that would work:

def Clock.ago(duration)
  Clock.now - duration
end

def Clock.from_now(duration)
  Clock.now + duration
end

Using stubs rather than a separate mock clock class

Why do we need to create an ‘Clock.now=XXX’ method, anyways? If we use stubs to override what AppTime.now returns, we can let the test framework clean up after itself when the test is complete. In addition, we can drop the mock definition entirely.. a very good thing indeed.

So in this universe, we’d end up with something like this:

Here’s a simple implementation of Clock:

in lib/clock.rb:

class Clock
  def self.now
     Time.now
  end
end

in mocks/test/lib/clock.rb: nothing!! this file doesn’t exist!

Test code:

def test_party
  Clock.stubs(:now).returns(Time.local(1999, 'Jan', 1))
  people(:nathan).party
  assert people(:nathan).very_drunk?
end

This approach has the advantage of reducing the number of ‘special’ test-only objects you have, and working more closely with the objects your application uses. The disadvantage is that you can no longer add lots of test-only helper functions to describe how you’re playing with the clock more clearly.. at least, not in the ‘Clock’ object.

Can we change Rails to use a settable clock?

The Rails code refers to Time.now in many, many places (just try a global search of your gems directory, and you’ll see what I mean.) At this point, the hooks are not in convenient places to allow for a settable clock.. you would have to copy entire method signatures and tweak some Time.now references, which ties your changes to a particular Rails install and creates unfortunate forks in your code. So, I would say that the answer for now is, sadly, “No”.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Creating Multiple Models in One Action

Pivotal Labs
Wednesday, July 18, 2007

One of the issues in my previous post The Controller Action that sparked some interest is the handling of the creation of multiple Models in one Action. In this post I shall elaborate on this problem in some detail, first considering the cases where in constructing the Dependent Object no data are needed from the querystring/params, and secondly where such data are necessary (and where we have a complicated nested Form). Let’s head right in to an example.

With No Extra Params to Worry About

Your site has Groups and Memberships. Our Business Rule is: when a user creates a Group, she should also be a Member of that Group. Following the Controller Formula, we know the solution in advance:

class GroupsController < ActionController::Base
  def create
    group = logged_in_user.groups.build(params[:group])
    raise SecurityTransgressionError.new unless logged_in_user.can_create?(group)
    if group.save
      ...
     end
  end
end

This leaves unresolved where to put our Business Rule…

Let’s just put it in the Model as a before_create:

class Group < ActiveRecord::Base
  belongs_to :creator, :class_name => 'User'
  has_many :memberships
  has_many :members, :through => :memberships

  before_create :create_first_member

  private
  def create_first_member
    memberships.build(:member => creator)
  end
end

Building the Membership as a before_create relies on the fact that objects built in a Proxy will be cascaded (i.e., saved) on creation.

Some Extra Params to Worry About

A more complicated example is where we have a Form that prompts the User for data for the creation of two Models, one Dependent upon the other. Let’s use the example where our Model is a Cyclops and the Dependent Model is an Eyeball. First we need a new Action:

def new
  @cyclops = Cyclops.new
end

Pretty Skinny, eh? Very Formulaic too. The corresponding View will look something like this:

<% form_for :cyclops do |c| %>
  ...
  <% fields_for 'cyclops[eyeball_attributes]', @cyclops.eyeball do |e| %>
    ...
  <% end %>
<% end %>

When the User submits this form, params come into our create Action looking like this:

{
  'cyclops' => {
    'name' => 'Polyphemus',
    'eyeball_attributes' => {'color' => 'grey'}
  }
}

So what should the create Action look like? Well, we don’t have to think about it, because we’re following the Controller Formula:

def create
  cyclops = Cyclops.new(params[:cyclops])
  ...
  if cyclops.save
    ...
  end
end

Two things now need to be implemented in the model. First, @cyclops.eyeball should not be nil even if the Cyclops is brand new. This is because we assume an Eyeball exists when we draw the new Form. A simple way of accomplishing this is the override the getter for eyeball so that it will build an eyeball if none exists:

class Cyclops < ...
  has_one :eyeball

  def eyeball
     @eyeball || build_eyeball
  end
end

This still leaves unresolved how to deal with setting the Dependent Model, the Eyeball. Given the way we drew the form above, we need merely implement eyeball_attributes=:

class Cyclops < ...
  ...
  def eyeball_attributes=(attrs)
      eyeball.attributes = attrs
  end
end

The eyeball_attribues= method will get called automatically when the create action passes in params[:cyclops] to the Cyclops initializer. (I wish we didn’t have to call this Attribute eyeball_attributes, but calling it just eyeball would require too much fancy footwork for my taste)

At this point, the only issue outstanding is how to deal with Validation. An invalid Dependent Model (which cannot be saved) will not make the Parent Model invalid by default when has_one is used (but it will validate by default when using has_many–there’s your Principle of Least Surprise for ya!). So it’s easy to imagine a scenario where the User inputs bad data for the Eyeball, good data for the Cyclops, and therefore Rails would save the Cyclops but not the Eyeball, and we’d have a sightless Cyclops with nary an error in sight. The only logical thing to do is add the following Business Rule: a Cyclops is invalid on creation if its Eyeball is invalid. This is simple enough:

class Cyclops < ...
  validates_associated :eyeball, :on => :create
end

I love Rails.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Sake for Gems Downloads List

Pivotal Labs
Tuesday, July 17, 2007

I have a few gems on Rubyforge and I want to track how many of them were downloaded. I found Firefox’s search tools lacking to find my gem rr.

To fix this issue, I made a sake task, named gems:downloads:list, that prints the gem downloads in text.

The source is on caboo.se.

You can install it by using:

sudo gem install sake
sake -i http://pastie.caboo.se/79547.txt gems:downloads:list
sake gems:downloads:list | less

This will give an output like:

------------------------------------------------
|                              Gem | Downloads |
------------------------------------------------
|                            rails |   1194471 |
|                     activerecord |   1121778 |
|                       actionpack |   1054718 |
|                    activesupport |    990851 |
|                     actionmailer |    960759 |
|                 actionwebservice |    948640 |
|                             rake |    860824 |
|                            mysql |    593476 |
|                             fcgi |    230394 |
|                          mongrel |    220370 |
|                          daemons |    167443 |
|                          rmagick |    164537 |
|                       gem_plugin |    153505 |
|                         RedCloth |    147182 |
|                  rubygems-update |    119615 |
|                          net-ssh |    114369 |
|                     sqlite3-ruby |    105796 |
|                       fastthread |     95534 |
|            cgi_multipart_eof_fix |     95399 |
|                           needle |     87718 |

Sake is way cool. It was just too easy to implement and deploy this. Have fun making your own sake tasks.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

The Controller Formula

Pivotal Labs
Monday, July 16, 2007

When I introduce a programmer to Rails I encourage them to read the article Skinny Controller, Fat Model. My only complaint about this article is that it applies the Skinny/Fat Pattern in a vague way, proceeding as if by intuition. I’ve found instead that there is a formulaic way to produce excellent Controller code–the Controller Formula

Skinny/Fat: Code Complexity vs. Abstraction Boundaries vs. The Formula

The Skinny/Fat pattern is typically stated in terms of Lines of Code. Your Controllers should have few Lines of Code; where there are many, move them to the Model. This rule has more exceptions than it has applications, so we can state the intent of the Pattern more precisely in terms of Abstraction Boundaries. Remove all Business Logic from your Controllers and put it in the model. Your Controllers are only responsible for mapping between URLs (including other HTTP Request data), coordinating with your Models and your Views, and channeling that back to an HTTP response. Along the way, Controllers may do Access Control, but little more. These instructions are precise, but following them requires intuition and subtle reasoning. The purpose of this post is to avoid subtle heuristics like Abstraction and Code Complexity. There is a Formula. Let’s see an example that follows the Formula:

def create
  model = Model.new(params[:model])
  raise SecurityTransgressionError.new unless logged_in_user.can_update?(model)
  if model.save
    render ...
  else
    ...
  end
end

What’s going on here? The Action channels user input to the model. It raises an Exception if the user lacks permission to perform this Action. Validation is performed by the model. Given the results, the Controller renders the appropriate Template to the HTTP Response.

Note a few things about this example. All of the access control rules (i.e., Business Logic) are specified in the Model (in this case, in the can_update? method on User). All data validation rules (again, Business Logic) are specified in the Model. There are three benefits to this approach: 1) the Logic in the Model is easier to test as it’s isolated. 2) Our Abstraction Boundaries are respected. 3) Our Controller is brief, i.e. Skinny. The resulting Controller some call anorexic. But I think it is like a conductor: all of the rhythm and melody comes from the players but the conductor keeps the whole orchestra in sync. But metaphors, testing strategies, and hoity-toity talk of Abstraction Boundaries aside, this example is good code because it follows the Formula.

Let’s consider a more sophisticated example.

Transactions and Compound Creations

Suppose that when creating a model of type Model, we always also want to create another type, DependentModel. We might be tempted to write something like:

def create
    model = Model.new(params[:model])
    dependent_model = model.dependents.build(params[:dependent_model])
    if model.save ...
end

Two Models created in one Action! This looks nothing like the Formula. Just push the creation of the DependentModel into Model and we have:

def create
    model = Model.new(params[:model])
    if model.save ...
end

Voila! The Formula.

How assigns fit into the Formula

Let’s consider another Action, one of the non-side-effecting persuasion.

def edit
  model = Model.find(params[:id])
  raise SecurityTransgressionError.new unless logged_in_user.can_update?(model)
  @colors =  Color.find :all
end

We can see the same access control pattern as in the previous example, but absent is any input validation as the user is not modifying anything. Something new here is the assignment of @colors. Typically, when we are displaying something to the user (in this case, an edit form), we will be listing various data; in this case, these data are the possible colors a model can be. Years ago, DHH issued a bull stating that “Thou Shalt Not Call Find in Thine Template”. This commandment is not without its problems, but that’s an issue for another blog post. This loading of the data is part of the Formula.

Push all your Find logic into the Model

Let’s take this edit action one step further. Suppose Users of type Admin can assign a certain set of colors to a Model, but other Users can select from a smaller set. Let’s rewrite edit to support these new business rules:

def edit
  model = Model.find(params[:id])
  raise SecurityTransgressionError.new unless logged_in_user.can_update?(model)
  @colors = logged_in_user.admin?? Color.fabulous_colors : Color.drab_colors
end

Something has gone wrong here: we’ve put Business Logic in the Controller, ack! But rather than appeal to some ethereal Abstraction Boundaries, just notice that it doesn’t follow the formula exemplified above–it’s got an extra conditional in the assignment of @colors. Let’s redesign this a bit, just aiming to adhere to the Formula:

def edit
  model = Model.find(params[:id])
  raise SecurityTransgressionError.new unless logged_in_user.can_update?(model)
  @colors = Color.find_by_user_role(logged_in_user.role)
end

Much better. We’ve put the rules of determining which color set to select based into the Model, and we have no more Control Flow than our original definition of edit above. This is Skinny as can be. We haven’t violated any Abstraction Boundaries. The color logic is easier to Unit Test. But these ends can be accomplished on auto-pilot just by following the Formula.

Let’s complexify this example one step further.

Conditional Logic Based on Session Data or other HTTP Request Data

def edit
  ...
  if logged_in_user.admin?
    render :action => 'edit_admin'
  else
    render :action => 'edit_normal'
  end
end

This is not Skinny at all. But, rendering different templates based on the User role is not Business Logic per-se. Rather, it is logic concerning what information is directed to the HTTP response. This properly belongs in the Controller. We could push this into the model:

render :action => model.edit_action_for_user_role(logged_in_user.role)

But this would make the model know about the View, which is unethical. We could use something like the Visitor Pattern to maintain abstraction boundaries but that is ridiculous overkill here. We could put our Fat edit action on a diet by breaking the two conditions into different edit actions on different Controllers. This approach is, perhaps, more RESTful in spirit:

class AdminModelsController
  ...
end

class UserModelsController
  ...
end

All of these concerns: violating Abstraction Boundaries, Lines of Code, the complexity of the Visitor Pattern, whether one approach is more RESTful than another… in the end it’s just a judgement-call between unappealing alternatives, and no two programmers will make the same choice, and I on any given day will choose variously. So just follow the Formula. Break it out into two controllers so we can have two edit actions, each well behaved.

The Full Formula

Let’s look at a ‘grammar’ for the Formula, and we’ll soon be done.

def non_side_effecting_action
  model = Model.find(params[:id])
  raise SecurityTransgressionError.new unless logged_in_user.can_action?(model)
  @assign1 = Foo.find :all
  ...
  @assignN = Bar.find_for_user(logged_in_user)
end

def side_effecting_action
  model = Model.new(params[:model])
  # or: model = Model.find(params[:id]); model.attributes = params[:model]
  raise SecurityTransgressionError.new unless logged_in_user.can_action?(model)
  if model.save
    @assign1 = Foo.find :all
    ...
    @assignN = Bar.find_for_user(logged_in_user)
    render :action => ... # or redirect_to ...
  else
    ...
  end
end

Some details are left out here… And obviously, there will be cases where the Formula needs to be elaborated. There might even be a few cases where the Formula needs to be abandoned. But I think you’ll find it useful most of the time.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Applying different error display styles

Pivotal Labs
Wednesday, July 11, 2007

Rails’ build-in view helpers (text_field, etc.) can automatically render errors. The default error display is easy to use and functional, but it only goes so far. Sometimes, it’s necessary to display errors in different ways in different parts of your application.

Rails provides a way of changing error rendering in “ActionView::Base.field_error_proc”. Unfortunately, the only way to change the error display is on a global basis, which makes the following code non-thread safe.

We wanted to apply different error styles to different views. A simple helper method, such as this one, will allow you to specify the error display you would like to use:

<code>
def with_error_proc(error_proc)
  pre = ActionView::Base.field_error_proc
  ActionView::Base.field_error_proc = error_proc
  yield
  ActionView::Base.field_error_proc = pre
end
</code>

To define different error display styles, we can use a hash that contains various error procs:

<code>
ERROR_PROCS = {}
ERROR_PROCS[:errors_below] = Proc.new do |html_tag, instance|
  html_tag+' error'
  # renders errors below the field
end
</code>

Finally, to use this in your controller, just wrap the render method with #with_error_proc. It’s also possible to use this directly in your view.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

Standup 06/28/2007

Chad Woolley
Thursday, July 5, 2007

Interesting Things

  • You can do single key presses in selenium with key-press. This is very useful in some scenarios – for example, predictive typing in search fields.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

Standup 06/27/2007

Chad Woolley
Thursday, July 5, 2007

Interesting Things

  • Don’t forget about the ‘net’ tab in the FireBug firefox extension. This can take the place of other separate plugins such as Live HTTP Headers.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

Standup 06/26/2007

Chad Woolley
Thursday, July 5, 2007

Interesting Things

  • RSpec global before/after: In addition to Behaviour-scoped before and after method forms, Rspec also has global prepend_before, prepend_after, append_before, append_after methods.

  • RSpec Custom Expectation Matchers: Remember that you can write your own Custom Expectation Matchers to make your specs as expressive as desired. For example: foo.should contain_text.

  • Self-Signed SSL Cert Gotcha: Firefox and IE hate it when your Certificate Authority and Server Certificate have the same Common Name.

  • RailMail: RailMail “gives you a persisted view of any mail your application has sent… With railmail there is no need to set up testing email accounts while developing your application; just send out mail to any address and Railmail will capture it.” Nice…

  • validates_presence_of in ActiveRecord calls blank?. This means you can use it check for dependent objects if you define blank?.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (86)
  • ruby on rails (71)
  • jobs (62)
  • javascript (59)
  • techtalk (44)
  • ironblogger (42)
  • rspec (39)
  • bloggerdome (34)
  • productivity (34)
  • activerecord (30)
  • rubymine (30)
  • git (29)
  • gogaruco (29)
  • nyc (27)
  • design (24)
  • mobile (23)
  • pivotal tracker (22)
  • process (21)
  • cucumber (21)
  • jasmine (19)
  • ios (18)
  • tracker ecosystem (17)
  • webos (17)
  • objective-c (17)
  • fun (16)
  • android (16)
  • palm (16)
  • ci (16)
  • "soft" ware (16)
  • bdd (15)
  • tdd (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • css (14)
  • gem (13)
  • mouse-free development (12)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • api (12)
  • keyboard (11)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
Subscribe to Community Feed
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >