# In view code, for example... link_to "Edit Widget", edit_widget_path if current_user.can_edit?(widget) # which calls this method class User def can_edit?(resource) resource.editable_by?(self) end end # ... which in turn calls this method class Widget def editable_by?(user) # whatever logic makes sense in this particular app end end
I first saw this approach a couple of years ago, when I was new to Rails and found Nick Kallen's post about from 2007. John Nunemaker has since created the Canable gem to make this even easier.
Defining these methods yourself is not that hard. But because they are all so similar, you might be tempted to use metaprogramming to shorten the code and make it more DRY.
This is a rare example where sacrificing a little bit of DRY can make the code a lot more readable and maintainable: readable because your eyes don't have to bounce around as much, and maintainable because you can edit each method separately.
class User # Metaprogramming way { :create => 'creatable', :read => 'readable', :edit => 'editable', :delete => 'deletable', :assign => 'assignable' }.each do |verb, adjective| define_method "can_#{verb}?".to_sym do |resource| resource.send("#{adjective}_by?", self) end end # Long-form way: less DRY but easier # to understand at a glance def can_create?(resource) resource.creatable_by?(self) end def can_read?(resource) resource.readable_by?(self) end def can_edit?(resource) resource.editable_by?(self) end def can_delete?(resource) resource.deletable_by?(self) end def can_assign?(resource) resource.assignable_by?(self) end end