Created
June 28, 2017 14:39
-
-
Save soynog/39a8457718a4d8709e875d521296f59f to your computer and use it in GitHub Desktop.
Roles Helpers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.form-group | |
%label.col-xs-2.control-label Roles | |
.col-xs-10 | |
.form-inline | |
.panel.roles-wrapper.panel-default | |
.row.panel-body | |
.col-sm-12 | |
%span.roles-container | |
.btn.add-role | |
%span.text-muted add role | |
%span.text-muted.glyphicon.glyphicon-plus | |
-# var rh = new RoleHelper( | |
-# '#{user_roles.to_json.html_safe}', | |
-# $('.roles-container'), | |
-# '#{escape_javascript render partial: "admin/users/role_form", locals: {f: f, role: @new_role}}' | |
-# ); | |
-# | |
-# // Click handler for adding new roles | |
-# $('.add-role').click(function() { | |
-# rh.addRole().trigger('change'); | |
-# }); | |
-# | |
-# // Have the FormHandler watch the roles for changes, plus trigger change event for the new role | |
-# fh.watch($('.roles-wrapper')); | |
-# | |
-# // Reset the schedule divs on form reset | |
-# fh.onReset(function() { | |
-# rh.reset(); | |
-# }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-puts "ROLES FORM", can?(:manage, Role) | |
=f.simple_fields_for :roles, role, | |
wrapper: :inline_input_group, | |
include_id: false do |role_form| | |
.role-body | |
=role_form.input :name, | |
collection: current_user.accessible_role_names, | |
wrapper_html: {class: 'role-form-group'}, | |
required: true, | |
include_blank: "role", | |
input_html: {name: input_name(f, :roles, :name), class: 'role-input name'} | |
%span.role-fields.hidden{ data: { role: "admin"} } | |
%span.role-fields.hidden{ data: {role: "staff"} } | |
for | |
=role_form.input :resource_id, | |
collection: current_user.accessible_agencies, | |
wrapper_html: {class: 'role-form-group'}, | |
required: true, | |
include_blank: 'select an agency', | |
input_html: { name: input_name(f, :roles, :resource_id), class: 'role-input resource-id' } | |
=role_form.input :resource_type, | |
wrapper_html: {class: 'hidden'}, | |
input_html: { name: input_name(f, :roles, :resource_type), | |
class: 'resource-type' } | |
=role_form.input :id, | |
wrapper_html: {class: 'hidden'}, | |
input_html: {name: input_name(f, :roles, :id), class: 'id'} | |
=role_form.input :_destroy, | |
wrapper_html: {class: 'hidden'}, | |
input_html: {class: 'destroy', name: input_name(f, :roles, :_destroy), value: false} | |
.btn.btn-link.delete-role | |
%span.glyphicon.glyphicon-remove |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Module to extend users, etc. with role helper functions | |
module RoleHelper | |
### SCOPES & CLASS METHODS ### | |
def self.included(base) | |
base.extend(ClassMethods) | |
# SCOPES | |
base.scope :admins, -> { base.querify(base.with_role(:admin, :any)) } | |
base.scope :any_role, -> do | |
base.querify(base.with_any_role( | |
{name: :admin, resource: :any}, | |
{name: :staff, resource: :any} | |
)) | |
end | |
base.scope :guests, -> { base.travelers.where(GuestUserHelper.new.query_str) } | |
base.scope :registered, -> { base.where.not(GuestUserHelper.new.query_str) } | |
base.scope :registered_travelers, -> { base.travelers.registered } | |
base.scope :staff, -> { base.querify(base.with_role(:staff, :any)) } | |
base.scope :travelers, -> { base.where.not(id: base.any_role.pluck(:id)) } | |
base.scope :staff_for, -> (agency) { base.with_role(:staff, agency) } | |
base.scope :staff_for_any, -> (agencies) do # Returns staff for any of the agencies in the passed collection | |
base.querify( base.with_any_role(*agencies.map{|ag| { :name => :staff, :resource => ag }}) ) | |
end | |
base.scope :except_user, -> (user) { where.not(id: user.id) } | |
# ASSOCIATIONS | |
base.has_many :transportation_agencies, | |
through: :roles, | |
source: :resource, | |
source_type: "TransportationAgency" | |
base.has_many :partner_agencies, | |
through: :roles, | |
source: :resource, | |
source_type: "PartnerAgency" | |
# base.accepts_nested_attributes_for :roles, allow_destroy: true | |
end | |
# CLASS METHOD DEFINITIONS | |
module ClassMethods | |
end | |
### INSTANCE METHODS ### | |
def has_no_roles? | |
!has_any_role? | |
end | |
# Check to see if the user is an Admin, any scope | |
def admin? | |
has_role? :admin, :any | |
end | |
# Check to see if the user is a guest (i.e. not registered) | |
def guest? | |
GuestUserHelper.new.is_guest_email?(email) | |
end | |
# Check to see if the user registered (i.e. not a guest) | |
def registered? | |
!guest? | |
end | |
# Check to see if the user is a registered traveler (i.e. not a guest, no roles) | |
def registered_traveler? | |
registered? && traveler? | |
end | |
# Check to see if the user is a staff, any scope | |
def staff? | |
has_role? :staff, :any | |
end | |
# Check to see if the user is a TransportationAgency staff | |
def transportation_staff? | |
staff? && agencies.any? { |a| a.transportation? } | |
end | |
# Check to see if the user is a PartnerAgency staff | |
def partner_staff? | |
staff? && agencies.any? { |a| a.partner? } | |
end | |
# Check to see if the user is a traveler (i.e. has no roles) | |
def traveler? | |
has_no_roles? | |
end | |
# Returns the agencies that the user is staff for | |
def agencies | |
Agency.where(id: transportation_agencies.pluck(:id) + partner_agencies.pluck(:id)) | |
end | |
# Returns the last of the user's staffing agencies (of which there are hopefully just one) | |
def staff_agency | |
agencies.last | |
end | |
# Returns a collection of the user's transportation agency's services | |
def services | |
Service.where(transportation_agency: transportation_agencies) | |
end | |
# Replaces the user's staff agency role with the passed agency | |
# wraps in a transaction so changes will be rolled back on error | |
def set_staff_role(agency) | |
self.class.transaction do | |
self.remove_role(:staff) | |
self.add_role(:staff, agency) if agency | |
end | |
end | |
# Adds or removes the user's admin permissions based on passed boolean | |
# wraps in a transaction so changes will be rolled back on error | |
def set_admin(bool) | |
self.class.transaction do | |
bool ? self.add_role(:admin) : self.remove_role(:admin) | |
end | |
end | |
# Replaces all roles with the passed roles, wrapping it in a transaction | |
# and rolling back to the original roles if there's an error | |
def update_roles(roles) | |
self.class.transaction do | |
self.roles.destroy_all | |
self.add_roles(roles) | |
end | |
end | |
# Takes a collection of roles objects or an array of roles attributes hashes, | |
# and adds those roles to the rolified object | |
def add_roles(roles) | |
roles.each do |role| | |
self.add_role(role[:name], find_resource(role[:resource_type], role[:resource_id])) | |
end | |
end | |
# Finds a resource based on type and id, allowing for nil params | |
def find_resource(type, id) | |
if type.present? && id.present? | |
resource_id = id.to_i | |
base_resource_class = type.constantize.base_class | |
return base_resource_class.find(resource_id) | |
else | |
return nil | |
end | |
end | |
# Returns the role names that the user may manage | |
def accessible_role_names | |
ability = Ability.new(self) | |
Role::ROLES.select { |role| ability.can?(:manage, role) } | |
end | |
# Returns the agencies that the user may manage | |
def accessible_agencies | |
Agency.accessible_by(Ability.new(self)) | |
end | |
# Returns a list of users who are staff for any of the agencies this user is staff for | |
def fellow_staff | |
User.staff_for_any(agencies) | |
end | |
# Returns a list of the staff that the user has permissions to access | |
def accessible_staff | |
return User.any_role if admin? | |
return fellow_staff if staff? | |
return User.none | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Helper for Rendering User Role Forms | |
// Takes JSON of the roles, a JQuery reference to the containing div, and HTML for a blank role | |
function RoleHelper(rolesJSON, containerDiv, roleTemplate, options) { | |
this.originalRoles = JSON.parse(rolesJSON); | |
this.container = containerDiv; | |
this.template = roleTemplate; | |
this.options = options || {}; | |
this.defaultRole = this.options.defaultRole || { | |
resource_type: "Agency" | |
}; | |
this._init(); | |
} | |
RoleHelper.prototype = { | |
// Renders all roles as divs | |
_init: function() { | |
var rh = this; | |
this.originalRoles.forEach(function(role) { | |
rh._render(role); | |
}); | |
}, | |
// Clears all roles | |
_clear: function() { | |
this.container.empty(); | |
}, | |
// Renders a role object in its appropriate container. | |
// Returns a JQuery reference to the new role. | |
_render: function(role) { | |
// Render the a role template into the roles container | |
this.container.append(this.template); | |
// Update it with appropriate values | |
var roleDiv = this.container.find('.role-body').last(); | |
roleDiv.find('select.name').val(role.name); | |
roleDiv.find('select.resource-id').val(role.resource_id); | |
roleDiv.find('input.resource-type').val(role.resource_type); | |
roleDiv.find('input.id').val(role.id); | |
// Set it up with click handlers | |
roleDiv.find('.delete-role').click(this.deleteRole); | |
roleDiv.find('.role-input.name').change(this.updateResourceSelectCallback()); | |
this.updateResourceSelect(roleDiv); | |
return roleDiv; | |
}, | |
// Delete role method for click handlers. | |
// Hides the div and sets "_destroy" value to true | |
deleteRole: function() { | |
var parent = $(this).parents('.role-body'); | |
parent.find('input.destroy').val(true).trigger('change'); | |
parent.addClass('hidden'); | |
}, | |
// Adds a new schedule to the passed day, and populates it with default values | |
addRole: function() { | |
var rh = this; | |
return this._render(rh.defaultRole); | |
}, | |
// Resets the roles form by clearing out the containers and rebuilding from the original roles JSON | |
reset: function() { | |
this._clear(); | |
this._init(); | |
}, | |
// Updates appropriate Resource (i.e. agency) selection field based on the role | |
updateResourceSelect: function(parentDiv) { | |
// Identify the new role name | |
var role = parentDiv.find(':input.name').val(); | |
// Hide and disable all selectors | |
parentDiv.find('.role-fields').addClass('hidden') | |
parentDiv.find(':input.resource-id').prop('disabled', true); | |
// Show and enable the appropriate one | |
parentDiv.find(".role-fields[data-role='" + role + "']").removeClass('hidden') | |
.find(":input.resource-id").prop('disabled', false); | |
return parentDiv; | |
}, | |
// Returns a callback function to update the resource selection field | |
updateResourceSelectCallback: function() { | |
var rh = this; | |
return function() { | |
rh.updateResourceSelect($(this).parents('.role-body')); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment