= Adhocracy {
}[http://badge.fury.io/rb/adhocracy] {
}[https://travis-ci.org/timothycommoner/adhocracy] {
}[https://coveralls.io/r/timothycommoner/adhocracy] {
}[https://codeclimate.com/github/timothycommoner/adhocracy]
A group management engine for Rails.
== Compatibility
Adhocracy is a Rails Engine, which means it plays best with Rails applications. So far, it's only been tested with Rails 4.
== Usage
=== Installation
1. Add Adhocracy to your gemfile: `gem 'adhocracy'`
2. Run bundler: `bundle install`
3. Run this in your app folder: `rake adhocracy:install:migrations`
4. Run your migrations: `rake db:migrate`
5. Add `acts_as_group` to the models you want to have group functionality
6. Add `acts_as_member` to the models you want to have member functionality
=== Creating Groups and Members
Scenario: You want your Club model to have group functionality. Ideally, it'll accept members from both the Student and Teacher model.
First, add `acts_as_group` to your Club model:
class Club < ActiveRecord::Base
acts_as_group
end
Then, add 'acts_as_member' to your Student and Teacher models:
class Student < ActiveRecord::Base
acts_as_member
end
class Teacher < ActiveRecord::Base
acts_as_member
end
After that, you can add members to your Club by:
@club.add_member(@student)
@student.join_group(@club)
@teacher.join_group(@club)
List the current members:
@club.members # => returns an array with @student and @teacher in it
Or list the groups a member is a part of:
@student.groups # => returns an array with only @club
Check for membership:
@student.member_of?(@club) # => true
@club.has_member?(@teacher) # => true
And destroy memberships
@student.leave_group(@club)
@group.remove_member(@teacher)
=== Officers
Scenario: You want a special class of membership that has the privilege to edit the group and accept/invite new members.
Adhocracy allows for administrative members called officers. You can create a new officer with:
@club.add_officer(@student)
# or
@student.promote(@club)
Later, you can strip an officer of her title with:
@club.demote_officer(@student)
# or
@student.demote(@club)
You can check if a member is an officer with:
@club.has_officer?(@member)
# or
@member.officer_of?(@club)
Or get a full list of officers:
@club.officers
# or of administered groups
@member.administrations
=== Inviting Members
Scenario: You want your users to have control over which groups they join.
Groups can send invitations to users:
@club.invite_member(@student)
@student.groups # => does not yet include @club
@student.group_invitations # => array including @club
The user can either accept or decline:
@invitation = @student.membership_invitations.first
@invitation.accept
- or -
@invitation.decline
If they accept, then they become a member of the group.
Invitations can be queried for their state of acceptance:
@invitation.pending?
@invitation.accepted?
@invitation.declined?
You can also check to see if an invitation is already sent:
@student.invited_to?(@club)
@club.invited?(@student)
These checks can include the state of the invitation:
@student.invited_to?(@club, { pending: true })
@student.invited_to?(@club, { accepted: false })
@student.invited_to?(@club, { declined: false })
=== Requesting Membership
Scenario: You want your groups to have control over which users join them.
Interested users can send membership requests to groups:
@student.request_membership_in(@club)
@club.members # => does not yet include @student
@club.membership_requests # => array including @student
The group can either accept or decline:
@request = @club.membership_requests.first
@request.accept
- or -
@request.decline
Requests can be queried for their state of acceptance:
@request.pending?
@request.accepted?
@request.declined?
You can also check to see if a request is already sent:
@student.requested_membership_in?(@club)
@club.recieved_request_from?(@student)
These checks can include the state of the request:
@student.requested_membership_in?(@club, { pending: true })
@student.requested_membership_in?(@club, { accepted: false })
@student.requested_membership_in?(@club, { declined: false })
=== Nesting Groups
Scenario: You want your Company model to have many subsidiary companies.
Create a model that both `acts_as_group` and `acts_as_member`:
class Company < ActiveRecord::Base
acts_as_group
acts_as_member
end
You can then nest companies like you would any other member:
@company.add_member(@child_company)
@child_company.add_member(@grand_child_company)
== Limitations
Unfortunately, Rails does not support `has_many through` relationships that pass through a polymorphic join table, which we do in Adhocracy. In order to work around this limitation, we've created pseudo-associations, such as `@club.members` and `@user.groups`. These pseudo-associations return a simple array, rather than the feature-packed associations Rails typically uses. This means you can't chain in scopes or use commands like `@user.groups.create`. If you know of a way we can reincorporate Rails associations without losing our ability to join groups and members polymorphically, please share your thoughts!
== Issues
Adhocracy is still very young, and both its functionality and its documentation are bound to be lacking. If you're having trouble with something, feel free to open an issue.
== Contributing
Feel free to send us a pull request. Public methods, callbacks, and validations should have Rspec tests to back them up.
=== Contributors
Timothy Baron
== License
Released under the MIT license.