README.md in consul-0.6.1 vs README.md in consul-0.7.0

- old
+ new

@@ -57,18 +57,11 @@ power.notes? # => returns true if Power#notes returns a scope power.notes! # => raises Consul::Powerless unless Power#notes returns a scope power.note?(Note.last) # => returns whether the given Note is in the Power#notes scope. Caches the result for subsequent queries. power.note!(Note.last) # => raises Consul::Powerless unless the given Note is in the Power#notes scope -You can also write power checks like this: - power.include?(:notes) - power.include!(:notes) - power.include?(:notes, Note.last) - power.include!(:notes, Note.last) - - Boolean powers -------------- Boolean powers are useful to control access to stuff that doesn't live in the database: @@ -340,10 +333,117 @@ The `authorize_values_for` macro comes with many useful options and details best explained in the [assignable_values README](https://github.com/makandra/assignable_values), so head over there for more. The macro is basically a shortcut for this: assignable_values_for :field, :through => lambda { Power.current } +Dynamic power access +-------------------- + +Consul gives you a way to dynamically access and query powers for a given name, model class or record. +A common use case for this are generic helper methods, e.g. a method to display an "edit" link for any given record +if the user is authorized to change that record: + + module CrudHelper + + def edit_record_action(record) + if current_power.include_record?(:updatable, record) + link_to 'Edit', [:edit, record] + end + end + + end + +You can find a full list of available dynamic calls below: + +| Dynamic call | Equivalent | +|---------------------------------------------------------|--------------------------------------------| +| `Power.current.send(:notes)` | `Power.current.notes` | +| `Power.current.include?(:notes)` | `Power.current.notes?` | +| `Power.current.include!(:notes)` | `Power.current.notes!` | +| `Power.current.include?(:notes, Note.last)` | `Power.current.note?(Note.last)` | +| `Power.current.include!(:notes, Note.last)` | `Power.current.note!(Note.last)` | +| `Power.current.for_record(Note.last)` | `Power.current.notes` | +| `Power.current.for_record(:updatable, Note.last)` | `Power.current.updatable_notes` | +| `Power.current.for_model(Note)` | `Power.current.notes` | +| `Power.current.for_model(:updatable, Note)` | `Power.current.updatable_notes` | +| `Power.current.include_model?(Note)` | `Power.current.notes?` | +| `Power.current.include_model?(:updatable, Note)` | `Power.current.updatable_notes?` | +| `Power.current.include_model!(Note)` | `Power.current.notes!` | +| `Power.current.include_model!(:updatable, Note)` | `Power.current.updatable_notes!` | +| `Power.current.include_record?(Note.last)` | `Power.current.note?(Note.last)` | +| `Power.current.include_record?(:updatable, Note.last)` | `Power.current.updatable_note?(Note.last)` | +| `Power.current.include_record!(Note.last)` | `Power.current.note!(Note.last)` | +| `Power.current.include_record!(:updatable, Note.last)` | `Power.current.updatable_note!(Note.last)` | +| `Power.current.name_for_model(Note)` | `:notes` | +| `Power.current.name_for_model(:updatable, Note)` | `:updatable_notes` | +| `Power.current.name_for_record(Note.last)` | `:notes` | +| `Power.current.name_for_record(:updatable, Note.last)` | `:updatable_notes` | + + + +Querying a power that might be nil +---------------------------------- + +You will often want to access `Power.current` from another model, to e.g. iterate through the list of accessible users: + + class UserReport + + def data + Power.current.users.collect do |user| + [user.name, user.email, user.income] + end + end + + end + +Good practice is for your model to not crash when `Power.current` is `nil`. This is the case when your model isn't +called as part of processing a browser request, e.g. on the console, during tests and during batch processes. +In such cases your model should simply skip authorization and assume that all users are accessible: + + class UserReport + + def data + accessible_users = Power.current.present? Power.current.users || User + accessible_users.collect do |user| + [user.name, user.email, user.income] + end + end + + end + +Because this pattern is so common, the `Power` class comes with a number of class methods you can use to either query +`Power.current` or, if it is not set, just assume that everything is accessible: + + class UserReport + + def data + Power.for_model(user).collect do |user| + [user.name, user.email, user.income] + end + end + + end + +There is a long selection of class methods that behave neutrally in case `Power.current` is `nil`: + +| Call | Equivalent | +|----------------------------------------------------------|---------------------------------------------------------------------| +| `Power.for_model(Note)` | `Power.current.present? ? Power.current.notes : Note` | +| `Power.for_model(:updatable, Note)` | `Power.current.present? ? Power.current.updatable_notes : Note` | +| `Power.include_model?(Note)` | `Power.current.present? ? Power.notes? : true` | +| `Power.include_model?(:updatable, Note)` | `Power.current.present? ? Power.updatable_notes? : true` | +| `Power.include_model!(Note)` | `Power.notes! if Power.current.present?` | +| `Power.include_model!(:updatable, Note)` | `Power.updatable_notes! if Power.current.present?` | +| `Power.for_record(Note.last)` | `Power.current.present? ? Power.current.notes : Note` | +| `Power.for_record(:updatable, Note.last)` | `Power.current.present? ? Power.current.updatable_notes : Note` | +| `Power.include_record?(Note.last)` | `Power.current.present? ? Power.note?(Note.last) : true` | +| `Power.include_record?(:updatable, Note.last)` | `Power.current.present? ? Power.updatable_note?(Note.last?) : true` | +| `Power.include_record!(Note.last)` | `Power.note!(Note.last) if Power.current.present?` | +| `Power.include_record!(:updatable, Note.last)` | `Power.updatable_note!(Note.last) if Power.current.present?` | + + + Testing ------- This section Some hints for testing authorization with Consul. @@ -385,9 +485,13 @@ admin = User.new(:role => 'admin') Power.with_power(admin) do # run code that uses Power.current end + + + + Installation ------------