Skip to content

Instantly share code, notes, and snippets.

@ahawkins
Created July 20, 2012 11:44
Show Gist options
  • Save ahawkins/3150306 to your computer and use it in GitHub Desktop.
Save ahawkins/3150306 to your computer and use it in GitHub Desktop.
class ApplicationPermitter
class PermittedAttribute < Struct.new(:name, :options) ; end
delegate :authorize!, :to => :ability
class_attribute :permitted_attributes
self.permitted_attributes = []
class << self
def permit(*args)
options = args.extract_options!
args.each do |name|
self.permitted_attributes += [PermittedAttribute.new(name, options)]
end
end
def scope(name)
with_options :scope => name do |nested|
yield nested
end
end
end
def initialize(params, user, ability = nil)
@params, @user, @ablity = params, user, ability
end
def permitted_params
authorize_params!
filtered_params
end
def resource_name
self.class.to_s.match(/(.+)Permitter/)[1].underscore.to_sym
end
private
def authorize_params!
needing_authorization = permitted_attributes.select { |a| a.options[:authorize] }
needing_authorization.each do |attribute|
if attribute.options[:scope]
values = Array.wrap(filtered_params[attribute.options[:scope]]).collect do |hash|
hash[attribute.name]
end.compact
else
values = Array.wrap filtered_params[attribute.name]
end
klass = (attribute.options[:as].try(:to_s) || attribute.name.to_s.split(/(.+)_ids?/)[1]).classify.constantize
values.each do |record_id|
record = klass.find record_id
permission = attribute.options[:authorize].to_sym || :read
authorize! permission, record
end
end
end
def filtered_params
scopes = {}
unscoped_attributes = []
permitted_attributes.each do |attribute|
if attribute.options[:scope]
key = attribute.options[:scope]
scopes[key] ||= []
scopes[key] << attribute.name
else
unscoped_attributes << attribute.name
end
end
@filtered_params ||= params.require(resource_name).permit(*unscoped_attributes, scopes)
end
def params
@params
end
def user
@user
end
def ability
@ability ||= Ability.new user
end
end
class DealPermitter < ApplicationPermitter
# No premissions reuqired to set this
permit :name, :description, :close_by, :state
# can pass `:authorize` with a permission:
# This line allows user_id if the user can read the user specified
# by the user_id. This only happens if it's present
permit :user_id, :authorize => :read
# same thing but automatically handles arrays of ids as well.
# This line allows the attachment_ids if the user can manage all
# the specified attachments
permit :attachment_ids, :authorize => :manage
# same thing as before but scopes this it to the
# hash inside the line_items_attributes array
#
# line_items_attributes is permitted if every item in the array
# is allowed.
#
# This also only allows line items if the user can manage the parent
scope :line_items_attributes, :manage => true do |line_item|
# So you cannot manipulate line items outside the parent
line_item.permit :id, :authorize => :manage
line_item.permit :name, :quantity, :price, :currency, :notes
line_item.permit :product_id, :authorize => :read
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment