Skip to content

Instantly share code, notes, and snippets.

@rilian
Last active December 19, 2015 06:19
Show Gist options
  • Save rilian/5910802 to your computer and use it in GitHub Desktop.
Save rilian/5910802 to your computer and use it in GitHub Desktop.
## # Example of better (imho) way to authorize changes of objects #
ABILITY = {
simple_user => {
can => %w[name],
cannot => %w[type],
}
}
class User < ActiveRecord::Base
# ...
end
def update(user_id)
load_user(user_id)
# Now we have @user and this object is allowed for current_user to read
##
# Here we do whatever we want and update user with new params
# This may be service object or whatever
#
user_updated = @user.dup.update_attributes(params[:user])
# Now we have in @user_updated object with desired new attributes
@user = apply_params_by_ability(user_updated, :update)
# If we are here - all is fine and current_user can do these changes
@user.save!
end
private
def load_user(user_id)
##
# Based on current_user properties, we build a set of SQL "where" matchers
# to load only allowed user IDs
#
# id_by_ability(:read) returns them or updates "relation"
#
@user = Users.where(id: id_by_ability(:read))
##
# Now when we know which IDs accessible at all, we perform formal find
# which may return 404 or success
#
@user = @user.find(user_id)
end
##
# Adds apropriate search params to the query
#
def id_by_ability(ability)
# ...
end
##
# Just check if on the clone object all changed attributes are allowed to change
#
# Bonus: list if can/cannot change, to which values
#
def apply_params_by_ability(updated_object, ability)
updated_object.changed_attributes.each do |attr|
raise 401 if ABILITY[:simple_user][:cannot].includes?(attr)
raise 401 unless ABILITY[:simple_user][:can].includes?(attr)
@user[attr.to_sym] = updated_object[attr.to_sym]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment