groupify 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +90 -0
- data/Gemfile +1 -1
- data/README.md +87 -49
- data/gemfiles/rails_3.2.gemfile +1 -1
- data/gemfiles/rails_4.0.gemfile +1 -1
- data/gemfiles/rails_4.1.gemfile +1 -1
- data/gemfiles/rails_4.2.gemfile +1 -1
- data/groupify.gemspec +3 -1
- data/lib/generators/groupify/active_record/initializer/initializer_generator.rb +11 -0
- data/lib/generators/groupify/active_record/initializer/templates/initializer.rb +9 -0
- data/lib/generators/groupify/active_record/install/install_generator.rb +12 -0
- data/lib/generators/groupify/active_record/migration/migration_generator.rb +22 -0
- data/lib/generators/groupify/active_record/migration/templates/migration.rb +20 -0
- data/lib/generators/groupify/active_record/model/model_generator.rb +15 -0
- data/lib/generators/groupify/active_record/model/templates/group.rb +3 -0
- data/lib/generators/groupify/active_record/model/templates/group_membership.rb +3 -0
- data/lib/generators/groupify/active_record/next_migration_version.rb +16 -0
- data/lib/generators/groupify/active_record/upgrade/templates/upgrade_migration.rb +7 -0
- data/lib/generators/groupify/active_record/upgrade/upgrade_generator.rb +22 -0
- data/lib/generators/groupify/mongoid/initializer/initializer_generator.rb +11 -0
- data/lib/generators/groupify/mongoid/initializer/templates/initializer.rb +5 -0
- data/lib/generators/groupify/mongoid/install/install_generator.rb +12 -0
- data/lib/generators/groupify/mongoid/model/model_generator.rb +11 -0
- data/lib/generators/groupify/mongoid/model/templates/group.rb +5 -0
- data/lib/groupify.rb +13 -1
- data/lib/groupify/adapter/active_record/group.rb +19 -6
- data/lib/groupify/adapter/active_record/group_member.rb +20 -10
- data/lib/groupify/adapter/active_record/group_membership.rb +3 -3
- data/lib/groupify/adapter/active_record/model.rb +1 -1
- data/lib/groupify/adapter/active_record/named_group_member.rb +7 -3
- data/lib/groupify/adapter/mongoid/group.rb +2 -2
- data/lib/groupify/adapter/mongoid/group_member.rb +0 -3
- data/lib/groupify/adapter/mongoid/model.rb +1 -1
- data/lib/groupify/version.rb +1 -1
- data/spec/active_record_spec.rb +98 -30
- data/spec/db/schema.rb +28 -4
- data/spec/mongoid_spec.rb +4 -4
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d570dee72597e96ba6684917ba35f43d4d90809
|
4
|
+
data.tar.gz: eae9072357349dae48d23634ecda81e6a95d0447
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62eb907fb6744685f4d799b8d51611fdf91539e1cce0d5207d05a7f3470a485d8fe443520e11c507b40548c05e7af5a585577275660fbe13c087eb26a0d87f0f
|
7
|
+
data.tar.gz: 3f16c4a4941e7d86eeed9ab62b764be8cb236eb4dd390a0a3e6c745b29914e22ef210f016e66a8169f730150b339279e84d3ab31bdb991dbed2808d7a7b0e30c
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## [v0.6.3](https://github.com/dwbutler/groupify/tree/v0.6.3) (2015-08-24)
|
4
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.6.2...v0.6.3)
|
5
|
+
|
6
|
+
**Fixed bugs:**
|
7
|
+
|
8
|
+
- ActiveRecord Statement Invalid for Group queries [\#30](https://github.com/dwbutler/groupify/issues/30)
|
9
|
+
|
10
|
+
**Merged pull requests:**
|
11
|
+
|
12
|
+
- Test against mysql and postgresql [\#31](https://github.com/dwbutler/groupify/pull/31) ([dwbutler](https://github.com/dwbutler))
|
13
|
+
|
14
|
+
## [v0.6.2](https://github.com/dwbutler/groupify/tree/v0.6.2) (2015-05-28)
|
15
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.6.1...v0.6.2)
|
16
|
+
|
17
|
+
**Closed issues:**
|
18
|
+
|
19
|
+
- can't complete migration [\#27](https://github.com/dwbutler/groupify/issues/27)
|
20
|
+
- NameError: uninitialized constant User::GroupMembership [\#25](https://github.com/dwbutler/groupify/issues/25)
|
21
|
+
|
22
|
+
**Merged pull requests:**
|
23
|
+
|
24
|
+
- fix association name in mongoid adapter [\#29](https://github.com/dwbutler/groupify/pull/29) ([samuelebistoletti](https://github.com/samuelebistoletti))
|
25
|
+
|
26
|
+
## [v0.6.1](https://github.com/dwbutler/groupify/tree/v0.6.1) (2015-01-16)
|
27
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.6.0...v0.6.1)
|
28
|
+
|
29
|
+
**Closed issues:**
|
30
|
+
|
31
|
+
- Groupify support unique groups scoped to user? [\#18](https://github.com/dwbutler/groupify/issues/18)
|
32
|
+
- Double Membership [\#14](https://github.com/dwbutler/groupify/issues/14)
|
33
|
+
- Getting uninitialized constant Assignment [\#8](https://github.com/dwbutler/groupify/issues/8)
|
34
|
+
|
35
|
+
**Merged pull requests:**
|
36
|
+
|
37
|
+
- Fixed bug that occurs when using namespaced Models [\#24](https://github.com/dwbutler/groupify/pull/24) ([byronduenas](https://github.com/byronduenas))
|
38
|
+
|
39
|
+
## [v0.6.0](https://github.com/dwbutler/groupify/tree/v0.6.0) (2014-08-27)
|
40
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.6.0.rc2...v0.6.0)
|
41
|
+
|
42
|
+
## [v0.6.0.rc2](https://github.com/dwbutler/groupify/tree/v0.6.0.rc2) (2014-08-21)
|
43
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.6.0.rc1...v0.6.0.rc2)
|
44
|
+
|
45
|
+
**Closed issues:**
|
46
|
+
|
47
|
+
- NoMethodError: undefined method `groups' for {:as=\>"manager"}:Hash [\#12](https://github.com/dwbutler/groupify/issues/12)
|
48
|
+
- Count functions [\#10](https://github.com/dwbutler/groupify/issues/10)
|
49
|
+
- Named Groups to be a Group [\#7](https://github.com/dwbutler/groupify/issues/7)
|
50
|
+
|
51
|
+
**Merged pull requests:**
|
52
|
+
|
53
|
+
- Active Record adapter typo fix [\#13](https://github.com/dwbutler/groupify/pull/13) ([fourfour](https://github.com/fourfour))
|
54
|
+
|
55
|
+
## [v0.6.0.rc1](https://github.com/dwbutler/groupify/tree/v0.6.0.rc1) (2014-06-18)
|
56
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.5.1...v0.6.0.rc1)
|
57
|
+
|
58
|
+
**Closed issues:**
|
59
|
+
|
60
|
+
- Change the name of the group\_membership [\#9](https://github.com/dwbutler/groupify/issues/9)
|
61
|
+
- Extend to deal with group managers/leaders? [\#3](https://github.com/dwbutler/groupify/issues/3)
|
62
|
+
|
63
|
+
**Merged pull requests:**
|
64
|
+
|
65
|
+
- Membership types [\#6](https://github.com/dwbutler/groupify/pull/6) ([dwbutler](https://github.com/dwbutler))
|
66
|
+
|
67
|
+
## [v0.5.1](https://github.com/dwbutler/groupify/tree/v0.5.1) (2014-03-28)
|
68
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.5.0...v0.5.1)
|
69
|
+
|
70
|
+
**Merged pull requests:**
|
71
|
+
|
72
|
+
- Allow model instances to access other models with names matching Groupify modules [\#5](https://github.com/dwbutler/groupify/pull/5) ([reed](https://github.com/reed))
|
73
|
+
|
74
|
+
## [v0.5.0](https://github.com/dwbutler/groupify/tree/v0.5.0) (2014-03-24)
|
75
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.4.2...v0.5.0)
|
76
|
+
|
77
|
+
**Closed issues:**
|
78
|
+
|
79
|
+
- New Group \(Unsaved\) has members somehow [\#2](https://github.com/dwbutler/groupify/issues/2)
|
80
|
+
|
81
|
+
## [v0.4.2](https://github.com/dwbutler/groupify/tree/v0.4.2) (2013-07-02)
|
82
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.4.1...v0.4.2)
|
83
|
+
|
84
|
+
## [v0.4.1](https://github.com/dwbutler/groupify/tree/v0.4.1) (2013-07-02)
|
85
|
+
[Full Changelog](https://github.com/dwbutler/groupify/compare/v0.4.0...v0.4.1)
|
86
|
+
|
87
|
+
## [v0.4.0](https://github.com/dwbutler/groupify/tree/v0.4.0) (2013-07-01)
|
88
|
+
|
89
|
+
|
90
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# Groupify
|
2
|
-
[![Build Status](https://
|
2
|
+
[![Build Status](https://travis-ci.org/dwbutler/groupify.svg?branch=master)](https://travis-ci.org/dwbutler/groupify) [![Coverage Status](https://coveralls.io/repos/dwbutler/groupify/badge.svg?branch=master&service=github)](https://coveralls.io/github/dwbutler/groupify?branch=master) [![Code Climate](https://codeclimate.com/github/dwbutler/groupify/badges/gpa.svg)](https://codeclimate.com/github/dwbutler/groupify) [![Inline docs](http://inch-ci.org/github/dwbutler/groupify.svg?branch=master)](http://inch-ci.org/github/dwbutler/groupify)
|
3
3
|
|
4
4
|
Adds group and membership functionality to Rails models. Defines a polymorphic
|
5
5
|
relationship between a Group model and any member model. Don't need a Group
|
6
6
|
model? Use named groups instead to add members to named groups such as
|
7
7
|
`:admin` or `"Team Rocketpants"`.
|
8
8
|
|
9
|
+
## Compatibility
|
10
|
+
|
9
11
|
The following ORMs are supported:
|
10
12
|
* ActiveRecord 3.2, 4.1.x, 4.2.x
|
11
13
|
* Mongoid 3.1, 4.0
|
@@ -34,40 +36,21 @@ Or install it yourself as:
|
|
34
36
|
|
35
37
|
$ gem install groupify
|
36
38
|
|
37
|
-
###
|
38
|
-
Add a migration similar to the following:
|
39
|
+
### Setup
|
39
40
|
|
40
|
-
|
41
|
-
class CreateGroups < ActiveRecord::Migration
|
42
|
-
def change
|
43
|
-
create_table :groups do |t|
|
44
|
-
t.string :type # Only needed if using single table inheritance
|
45
|
-
end
|
46
|
-
|
47
|
-
create_table :group_memberships do |t|
|
48
|
-
t.string :member_type # Necessary to make polymorphic members work
|
49
|
-
t.integer :member_id # The id of the member that belongs to this group
|
50
|
-
t.integer :group_id # The group to which the member belongs
|
51
|
-
t.string :group_name # The named group to which a member belongs (if using)
|
52
|
-
t.string :membership_type # The type of membership the member belongs with
|
53
|
-
end
|
41
|
+
#### Active Record
|
54
42
|
|
55
|
-
|
56
|
-
add_index :group_memberships, :group_id
|
57
|
-
add_index :group_memberships, :group_name
|
58
|
-
end
|
59
|
-
end
|
60
|
-
```
|
43
|
+
Execute:
|
61
44
|
|
62
|
-
|
45
|
+
$ rails generate groupify:active_record:install
|
63
46
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
47
|
+
This will generate an initializer, `Group` model, `GroupMembership` model, and migrations.
|
48
|
+
|
49
|
+
Modify the models and migrations as needed, then run the migration:
|
50
|
+
|
51
|
+
$ rake db:migrate
|
69
52
|
|
70
|
-
|
53
|
+
Set up your member models:
|
71
54
|
|
72
55
|
```ruby
|
73
56
|
class User < ActiveRecord::Base
|
@@ -80,37 +63,79 @@ class Assignment < ActiveRecord::Base
|
|
80
63
|
end
|
81
64
|
```
|
82
65
|
|
83
|
-
|
66
|
+
#### Mongoid
|
67
|
+
|
68
|
+
Execute:
|
69
|
+
|
70
|
+
$ rails generate groupify:mongoid:install
|
71
|
+
|
72
|
+
Set up your member models:
|
84
73
|
|
85
74
|
```ruby
|
86
|
-
class
|
87
|
-
|
75
|
+
class User
|
76
|
+
include Mongoid::Document
|
77
|
+
|
78
|
+
groupify :group_member
|
79
|
+
groupify :named_group_member
|
88
80
|
end
|
89
81
|
```
|
90
82
|
|
91
|
-
|
92
|
-
|
83
|
+
#### Advanced Configuration
|
84
|
+
|
85
|
+
##### Groupify Model Names
|
86
|
+
|
87
|
+
The default model names for groups and group memberships are configurable. Add the following
|
88
|
+
configuration in `config/initializers/groupify.rb` to change the model names for all classes:
|
93
89
|
|
94
90
|
```ruby
|
95
|
-
|
96
|
-
|
91
|
+
Groupify.configure do |config|
|
92
|
+
config.group_class_name = 'MyCustomGroup'
|
93
|
+
# ActiveRecord only
|
94
|
+
config.group_membership_class_name = 'MyCustomGroupMembership'
|
95
|
+
end
|
96
|
+
```
|
97
97
|
|
98
|
-
|
98
|
+
The group name can also be set on a model-by-model basis for each group member by passing
|
99
|
+
the `group_class_name` option:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
class Member < ActiveRecord::Base
|
103
|
+
groupify :group_member, group_class_name: 'MyOtherCustomGroup'
|
99
104
|
end
|
100
105
|
```
|
101
106
|
|
102
|
-
|
107
|
+
Note that each member model can only belong to a single type of group (or child classes
|
108
|
+
of that group).
|
109
|
+
|
110
|
+
##### Member Associations on Group
|
111
|
+
|
112
|
+
Your group class can be configured to create associations for each expected member type.
|
113
|
+
For example, let's say that your group class will have users and assignments as members.
|
114
|
+
The following configuration adds `users` and `assignments` associations on the group model:
|
103
115
|
|
104
116
|
```ruby
|
105
|
-
class
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
117
|
+
class Group < ActiveRecord::Base
|
118
|
+
groupify :group, members: [:users, :assignments], default_members: :users
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
The `default_members` option sets the model type when accessing the `members` association.
|
123
|
+
In the example above, `group.members` would return the users who are members of this group.
|
124
|
+
|
125
|
+
If you are using single table inheritance, child classes inherit the member associations
|
126
|
+
of the parent. If your child class needs to add more members, use the `has_members` method.
|
127
|
+
|
128
|
+
Example:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
class Organization < Group
|
132
|
+
has_members [:offices, :equipment]
|
110
133
|
end
|
111
134
|
```
|
112
135
|
|
113
|
-
|
136
|
+
Mongoid works the same way by creating Mongoid relations.
|
137
|
+
|
138
|
+
## Usage
|
114
139
|
|
115
140
|
### Create groups and add members
|
116
141
|
|
@@ -245,10 +270,6 @@ employee.in_group?(group) # => false
|
|
245
270
|
employee.in_group?(group, as: 'employee') # => false
|
246
271
|
```
|
247
272
|
|
248
|
-
## But wait, there's more!
|
249
|
-
|
250
|
-
Check the specs for a complete list of methods and scopes provided by Groupify.
|
251
|
-
|
252
273
|
## Using for Authorization
|
253
274
|
Groupify was originally created to help implement user authorization, although it can be used
|
254
275
|
generically for much more than that. Here are some examples of how to do it.
|
@@ -336,6 +357,23 @@ class PostPolicy < Struct.new(:user, :post)
|
|
336
357
|
end
|
337
358
|
```
|
338
359
|
|
360
|
+
## Upgrading
|
361
|
+
|
362
|
+
### 0.7+ - Polymorphic Groups (ActiveRecord only)
|
363
|
+
Groupify < 0.7 required a single `Group` model used for all group memberships.
|
364
|
+
Groupify 0.7+ supports using multiple models as groups by implementing polymorphic associations.
|
365
|
+
Upgrading requires adding a new `group_type` column to the `group_memberships` table and
|
366
|
+
populating that column with the class name of the group. Create the migration by executing:
|
367
|
+
|
368
|
+
$ rails generate groupify:active_record:upgrade
|
369
|
+
|
370
|
+
And then run the migration:
|
371
|
+
|
372
|
+
$ rake db:migrate
|
373
|
+
|
374
|
+
Please note that this migration may block writes in MySQL if your `group_memberships`
|
375
|
+
table is large.
|
376
|
+
|
339
377
|
## Contributing
|
340
378
|
|
341
379
|
1. Fork it
|
data/gemfiles/rails_3.2.gemfile
CHANGED
data/gemfiles/rails_4.0.gemfile
CHANGED
data/gemfiles/rails_4.1.gemfile
CHANGED
data/gemfiles/rails_4.2.gemfile
CHANGED
data/groupify.gemspec
CHANGED
@@ -24,6 +24,8 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_development_dependency "rspec", ">= 3"
|
25
25
|
|
26
26
|
gem.add_development_dependency "database_cleaner", "~> 1.3.0"
|
27
|
-
gem.add_development_dependency
|
27
|
+
gem.add_development_dependency "combustion"
|
28
28
|
gem.add_development_dependency "appraisal"
|
29
|
+
|
30
|
+
gem.add_development_dependency "github_changelog_generator"
|
29
31
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Groupify
|
2
|
+
module ActiveRecord
|
3
|
+
class InitializerGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_initializer
|
7
|
+
copy_file "initializer.rb", "config/initializers/groupify.rb"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Groupify.configure do |config|
|
2
|
+
# Configure the default group class name.
|
3
|
+
# Defaults to 'Group'
|
4
|
+
# config.group_class_name = 'Group'
|
5
|
+
|
6
|
+
# Configure the default group membership class name.
|
7
|
+
# Defaults to 'GroupMembership'
|
8
|
+
# config.group_membership_class_name = 'GroupMembership'
|
9
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "rails/generators/migration"
|
2
|
+
require "rails/generators/active_record"
|
3
|
+
require "generators/groupify/active_record/next_migration_version"
|
4
|
+
|
5
|
+
module Groupify
|
6
|
+
module ActiveRecord
|
7
|
+
class MigrationGenerator < Rails::Generators::Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
extend NextMigrationVersion
|
10
|
+
|
11
|
+
source_root File.expand_path("../templates", __FILE__)
|
12
|
+
|
13
|
+
def create_migration_file
|
14
|
+
migration_template "migration.rb", "db/migrate/groupify_migration.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.next_migration_number(dirname)
|
18
|
+
::ActiveRecord::Generators::Base.next_migration_number dirname
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class GroupifyMigration < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :groups do |t|
|
4
|
+
t.string :type
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table :group_memberships do |t|
|
8
|
+
t.references :member, polymorphic: true, index: true
|
9
|
+
t.references :group, polymorphic: true, index: true
|
10
|
+
|
11
|
+
# The named group to which a member belongs (if using)
|
12
|
+
t.string :group_name, index: true
|
13
|
+
|
14
|
+
# The membership type the member belongs with
|
15
|
+
t.string :membership_type
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Groupify
|
2
|
+
module ActiveRecord
|
3
|
+
class ModelGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_group_model_file
|
7
|
+
copy_file "group.rb", "app/models/group.rb"
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy_group_membership_model_file
|
11
|
+
copy_file "group_membership.rb", "app/models/group_membership.rb"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Groupify
|
2
|
+
module ActiveRecord
|
3
|
+
module NextMigrationVersion
|
4
|
+
# while methods have moved around this has been the implementation
|
5
|
+
# since ActiveRecord 3.0
|
6
|
+
def next_migration_number(dirname)
|
7
|
+
next_migration_number = current_migration_number(dirname) + 1
|
8
|
+
if ActiveRecord::Base.timestamped_migrations
|
9
|
+
[Time.now.utc.strftime("%Y%m%d%H%M%S"), format("%.14d", next_migration_number)].max
|
10
|
+
else
|
11
|
+
format("%.3d", next_migration_number)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "rails/generators/migration"
|
2
|
+
require "rails/generators/active_record"
|
3
|
+
require "generators/groupify/active_record/next_migration_version"
|
4
|
+
|
5
|
+
module Groupify
|
6
|
+
module ActiveRecord
|
7
|
+
class UpgradeGenerator < Rails::Generators::Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
extend NextMigrationVersion
|
10
|
+
|
11
|
+
source_root File.expand_path("../templates", __FILE__)
|
12
|
+
|
13
|
+
def create_migration_file
|
14
|
+
migration_template "upgrade_migration.rb", "db/migrate/add_group_type_to_group_memberships.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.next_migration_number(dirname)
|
18
|
+
::ActiveRecord::Generators::Base.next_migration_number dirname
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Groupify
|
2
|
+
module Mongoid
|
3
|
+
class InitializerGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
def copy_initializer
|
7
|
+
copy_file "initializer.rb", "config/initializers/groupify.rb"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/groupify.rb
CHANGED
@@ -1,3 +1,15 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
|
3
|
-
|
3
|
+
module Groupify
|
4
|
+
mattr_accessor :group_membership_class_name,
|
5
|
+
:group_class_name
|
6
|
+
|
7
|
+
self.group_class_name = 'Group'
|
8
|
+
self.group_membership_class_name = 'GroupMembership'
|
9
|
+
|
10
|
+
def self.configure
|
11
|
+
yield self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'groupify/railtie' if defined?(Rails)
|
@@ -3,7 +3,7 @@ module Groupify
|
|
3
3
|
|
4
4
|
# Usage:
|
5
5
|
# class Group < ActiveRecord::Base
|
6
|
-
#
|
6
|
+
# groupify :group, members: [:users]
|
7
7
|
# ...
|
8
8
|
# end
|
9
9
|
#
|
@@ -15,7 +15,10 @@ module Groupify
|
|
15
15
|
included do
|
16
16
|
@default_member_class = nil
|
17
17
|
@member_klasses ||= Set.new
|
18
|
-
has_many :group_memberships,
|
18
|
+
has_many :group_memberships,
|
19
|
+
dependent: :destroy,
|
20
|
+
class_name: Groupify.group_membership_class_name
|
21
|
+
|
19
22
|
end
|
20
23
|
|
21
24
|
def member_classes
|
@@ -31,9 +34,9 @@ module Groupify
|
|
31
34
|
clear_association_cache
|
32
35
|
|
33
36
|
members.each do |member|
|
34
|
-
member.
|
37
|
+
member.groups << self unless member.groups.include?(self)
|
35
38
|
if membership_type
|
36
|
-
member.group_memberships.where(group_id: self.
|
39
|
+
member.group_memberships.where(group_id: id, group_type: self.class.model_name.to_s, membership_type: membership_type).first_or_create!
|
37
40
|
end
|
38
41
|
member.clear_association_cache
|
39
42
|
end
|
@@ -142,9 +145,19 @@ module Groupify
|
|
142
145
|
source_type = member_klass.base_class
|
143
146
|
|
144
147
|
if ActiveSupport::VERSION::MAJOR > 3
|
145
|
-
has_many association_name,
|
148
|
+
has_many association_name,
|
149
|
+
->{ uniq },
|
150
|
+
through: :group_memberships,
|
151
|
+
source: :member,
|
152
|
+
source_type: source_type,
|
153
|
+
extend: MemberAssociationExtensions
|
146
154
|
else
|
147
|
-
has_many association_name,
|
155
|
+
has_many association_name,
|
156
|
+
uniq: true,
|
157
|
+
through: :group_memberships,
|
158
|
+
source: :member,
|
159
|
+
source_type: source_type,
|
160
|
+
extend: MemberAssociationExtensions
|
148
161
|
end
|
149
162
|
|
150
163
|
define_method(association_name) do |*args|
|
@@ -3,7 +3,7 @@ module Groupify
|
|
3
3
|
|
4
4
|
# Usage:
|
5
5
|
# class User < ActiveRecord::Base
|
6
|
-
#
|
6
|
+
# groupify :group_member
|
7
7
|
# ...
|
8
8
|
# end
|
9
9
|
#
|
@@ -14,13 +14,26 @@ module Groupify
|
|
14
14
|
|
15
15
|
included do
|
16
16
|
unless respond_to?(:group_memberships)
|
17
|
-
has_many :group_memberships,
|
17
|
+
has_many :group_memberships,
|
18
|
+
as: :member,
|
19
|
+
autosave: true,
|
20
|
+
dependent: :destroy,
|
21
|
+
class_name: Groupify.group_membership_class_name
|
18
22
|
end
|
19
23
|
|
20
24
|
if ActiveSupport::VERSION::MAJOR > 3
|
21
|
-
has_many :groups, ->{ uniq },
|
25
|
+
has_many :groups, ->{ uniq },
|
26
|
+
through: :group_memberships,
|
27
|
+
as: :group,
|
28
|
+
source_type: @group_class_name,
|
29
|
+
extend: GroupAssociationExtensions
|
22
30
|
else
|
23
|
-
has_many :groups,
|
31
|
+
has_many :groups,
|
32
|
+
uniq: true,
|
33
|
+
through: :group_memberships,
|
34
|
+
as: :group,
|
35
|
+
source_type: @group_class_name,
|
36
|
+
extend: GroupAssociationExtensions
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
@@ -92,9 +105,6 @@ module Groupify
|
|
92
105
|
end
|
93
106
|
|
94
107
|
module ClassMethods
|
95
|
-
def group_class_name; @group_class_name ||= 'Group'; end
|
96
|
-
def group_class_name=(klass); @group_class_name = klass; end
|
97
|
-
|
98
108
|
def as(membership_type)
|
99
109
|
joins(:group_memberships).where(group_memberships: { membership_type: membership_type })
|
100
110
|
end
|
@@ -118,8 +128,8 @@ module Groupify
|
|
118
128
|
|
119
129
|
joins(:group_memberships).
|
120
130
|
group("#{quoted_table_name}.#{connection.quote_column_name('id')}").
|
121
|
-
where(:
|
122
|
-
having("COUNT(group_memberships.group_id) =
|
131
|
+
where(group_memberships: {group_id: groups.map(&:id)}).
|
132
|
+
having("COUNT(#{reflect_on_association(:group_memberships).klass.quoted_table_name}.#{connection.quote_column_name('group_id')}) = ?", groups.count).
|
123
133
|
uniq
|
124
134
|
end
|
125
135
|
|
@@ -129,7 +139,7 @@ module Groupify
|
|
129
139
|
|
130
140
|
joins(:group_memberships).
|
131
141
|
group("#{quoted_table_name}.#{connection.quote_column_name('id')}").
|
132
|
-
having("COUNT(DISTINCT group_memberships.group_id) =
|
142
|
+
having("COUNT(DISTINCT #{reflect_on_association(:group_memberships).klass.quoted_table_name}.#{connection.quote_column_name('group_id')}) = ?", groups.count).
|
133
143
|
uniq
|
134
144
|
end
|
135
145
|
|
@@ -5,7 +5,7 @@ module Groupify
|
|
5
5
|
#
|
6
6
|
# Usage:
|
7
7
|
# class GroupMembership < ActiveRecord::Base
|
8
|
-
#
|
8
|
+
# groupify :group_membership
|
9
9
|
# ...
|
10
10
|
# end
|
11
11
|
#
|
@@ -15,8 +15,8 @@ module Groupify
|
|
15
15
|
included do
|
16
16
|
attr_accessible(:member, :group, :group_name, :membership_type, :as) if ActiveSupport::VERSION::MAJOR < 4
|
17
17
|
|
18
|
-
belongs_to :member, :
|
19
|
-
belongs_to :group
|
18
|
+
belongs_to :member, polymorphic: true
|
19
|
+
belongs_to :group, polymorphic: true
|
20
20
|
end
|
21
21
|
|
22
22
|
def membership_type=(membership_type)
|
@@ -14,7 +14,11 @@ module Groupify
|
|
14
14
|
|
15
15
|
included do
|
16
16
|
unless respond_to?(:group_memberships)
|
17
|
-
has_many :group_memberships,
|
17
|
+
has_many :group_memberships,
|
18
|
+
as: :member,
|
19
|
+
autosave: true,
|
20
|
+
dependent: :destroy,
|
21
|
+
class_name: Groupify.group_membership_class_name
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
@@ -82,7 +86,7 @@ module Groupify
|
|
82
86
|
joins(:group_memberships).
|
83
87
|
group("#{quoted_table_name}.#{connection.quote_column_name('id')}").
|
84
88
|
where(:group_memberships => {:group_name => named_groups}).
|
85
|
-
having("COUNT(DISTINCT group_memberships.group_name) =
|
89
|
+
having("COUNT(DISTINCT #{reflect_on_association(:group_memberships).klass.quoted_table_name}.#{connection.quote_column_name('group_name')}) = ?", named_groups.count).
|
86
90
|
uniq
|
87
91
|
end
|
88
92
|
|
@@ -92,7 +96,7 @@ module Groupify
|
|
92
96
|
|
93
97
|
joins(:group_memberships).
|
94
98
|
group("#{quoted_table_name}.#{connection.quote_column_name('id')}").
|
95
|
-
having("COUNT(DISTINCT group_memberships.group_name) =
|
99
|
+
having("COUNT(DISTINCT #{reflect_on_association(:group_memberships).klass.quoted_table_name}.#{connection.quote_column_name('group_name')}) = ?", named_groups.count).
|
96
100
|
uniq
|
97
101
|
end
|
98
102
|
|
@@ -5,7 +5,7 @@ module Groupify
|
|
5
5
|
# class Group
|
6
6
|
# include Mongoid::Document
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# groupify :group, members: [:users]
|
9
9
|
# ...
|
10
10
|
# end
|
11
11
|
#
|
@@ -136,7 +136,7 @@ module Groupify
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def associate_member_class(member_klass)
|
139
|
-
|
139
|
+
association_name ||= member_klass.model_name.plural.to_sym
|
140
140
|
|
141
141
|
has_many association_name, class_name: member_klass.to_s, dependent: :nullify, foreign_key: 'group_ids', extend: MemberAssociationExtensions
|
142
142
|
|
@@ -103,9 +103,6 @@ module Groupify
|
|
103
103
|
end
|
104
104
|
|
105
105
|
module ClassMethods
|
106
|
-
def group_class_name; @group_class_name ||= 'Group'; end
|
107
|
-
def group_class_name=(klass); @group_class_name = klass; end
|
108
|
-
|
109
106
|
def in_group(group)
|
110
107
|
group.present? ? self.in(group_ids: group.id) : none
|
111
108
|
end
|
data/lib/groupify/version.rb
CHANGED
data/spec/active_record_spec.rb
CHANGED
@@ -70,6 +70,10 @@ class GroupMembership < ActiveRecord::Base
|
|
70
70
|
groupify :group_membership
|
71
71
|
end
|
72
72
|
|
73
|
+
class Classroom < ActiveRecord::Base
|
74
|
+
groupify :group
|
75
|
+
end
|
76
|
+
|
73
77
|
describe Group do
|
74
78
|
it { should respond_to :members}
|
75
79
|
it { should respond_to :add }
|
@@ -88,11 +92,63 @@ if DEBUG
|
|
88
92
|
end
|
89
93
|
|
90
94
|
describe Groupify::ActiveRecord do
|
91
|
-
let
|
92
|
-
let
|
95
|
+
let(:user) { User.create! }
|
96
|
+
let(:group) { Group.create! }
|
93
97
|
let(:widget) { Widget.create! }
|
94
98
|
let(:namespaced_member) { Namespaced::Member.create! }
|
95
99
|
|
100
|
+
describe "configuration" do
|
101
|
+
context "globally configured group and group membership models" do
|
102
|
+
before do
|
103
|
+
Groupify.configure do |config|
|
104
|
+
config.group_class_name = 'CustomGroup'
|
105
|
+
config.group_membership_class_name = 'CustomGroupMembership'
|
106
|
+
end
|
107
|
+
|
108
|
+
class CustomGroupMembership < ActiveRecord::Base
|
109
|
+
groupify :group_membership
|
110
|
+
end
|
111
|
+
|
112
|
+
class CustomUser < ActiveRecord::Base
|
113
|
+
groupify :group_member
|
114
|
+
end
|
115
|
+
|
116
|
+
class CustomGroup < ActiveRecord::Base
|
117
|
+
groupify :group
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
after do
|
122
|
+
Groupify.configure do |config|
|
123
|
+
config.group_class_name = 'Group'
|
124
|
+
config.group_membership_class_name = 'GroupMembership'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "uses the custom models to store groups and group memberships" do
|
129
|
+
custom_user = CustomUser.create!
|
130
|
+
custom_group = CustomGroup.create!
|
131
|
+
custom_user.groups << custom_group
|
132
|
+
expect(GroupMembership.count).to eq(0)
|
133
|
+
expect(CustomGroupMembership.count).to eq(1)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "member with custom group model" do
|
138
|
+
before do
|
139
|
+
class ProjectMember < ActiveRecord::Base
|
140
|
+
groupify :group_member, group_class_name: 'Project'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "overrides the default group name on a per-model basis" do
|
145
|
+
member = ProjectMember.create!
|
146
|
+
member.groups.create!
|
147
|
+
expect(member.groups.first).to be_a Project
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
96
152
|
context 'when using groups' do
|
97
153
|
it "members and groups are empty when initialized" do
|
98
154
|
expect(user.groups).to be_empty
|
@@ -101,37 +157,51 @@ describe Groupify::ActiveRecord do
|
|
101
157
|
expect(Group.new.members).to be_empty
|
102
158
|
expect(group.members).to be_empty
|
103
159
|
end
|
104
|
-
|
105
|
-
it "adds a group to a member" do
|
106
|
-
user.groups << group
|
107
|
-
expect(user.groups).to include(group)
|
108
|
-
expect(group.members).to include(user)
|
109
|
-
expect(group.users).to include(user)
|
110
|
-
end
|
111
|
-
|
112
|
-
it "adds a member to a group" do
|
113
|
-
expect(user.groups).to be_empty
|
114
|
-
group.add user
|
115
|
-
expect(user.groups).to include(group)
|
116
|
-
expect(group.members).to include(user)
|
117
|
-
end
|
118
160
|
|
119
|
-
|
120
|
-
group
|
121
|
-
|
122
|
-
|
161
|
+
context "when adding" do
|
162
|
+
it "adds a group to a member" do
|
163
|
+
user.groups << group
|
164
|
+
expect(user.groups).to include(group)
|
165
|
+
expect(group.members).to include(user)
|
166
|
+
expect(group.users).to include(user)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "adds a member to a group" do
|
170
|
+
expect(user.groups).to be_empty
|
171
|
+
group.add user
|
172
|
+
expect(user.groups).to include(group)
|
173
|
+
expect(group.members).to include(user)
|
174
|
+
end
|
123
175
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
176
|
+
it "only adds a member to a group once" do
|
177
|
+
group.add user
|
178
|
+
group.add user
|
179
|
+
expect(user.group_memberships.count).to eq(1)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "adds a namespaced member to a group" do
|
183
|
+
group.add(namespaced_member)
|
184
|
+
expect(group.namespaced_members).to include(namespaced_member)
|
185
|
+
end
|
128
186
|
|
129
|
-
|
130
|
-
|
131
|
-
|
187
|
+
it "adds multiple members to a group" do
|
188
|
+
group.add(user, widget)
|
189
|
+
expect(group.users).to include(user)
|
190
|
+
expect(group.widgets).to include(widget)
|
191
|
+
|
192
|
+
users = [User.create!, User.create!]
|
193
|
+
group.add(users)
|
194
|
+
expect(group.users).to include(*users)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "only allows members to be added to their configured group type" do
|
198
|
+
classroom = Classroom.create!
|
199
|
+
expect { classroom.add(user) }.to raise_error(ActiveRecord::AssociationTypeMismatch)
|
200
|
+
expect { user.groups << classroom }.to raise_error(ActiveRecord::AssociationTypeMismatch)
|
201
|
+
end
|
132
202
|
end
|
133
203
|
|
134
|
-
it
|
204
|
+
it "lists which member classes can belong to this group" do
|
135
205
|
expect(group.class.member_classes).to include(User, Widget)
|
136
206
|
expect(group.member_classes).to include(User, Widget)
|
137
207
|
|
@@ -590,6 +660,4 @@ describe Groupify::ActiveRecord do
|
|
590
660
|
end
|
591
661
|
end
|
592
662
|
end
|
593
|
-
|
594
|
-
|
595
663
|
end
|
data/spec/db/schema.rb
CHANGED
@@ -5,10 +5,9 @@ ActiveRecord::Schema.define(version: 0) do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
create_table :group_memberships do |t|
|
8
|
-
t.
|
9
|
-
t.
|
10
|
-
t.
|
11
|
-
t.string :group_name
|
8
|
+
t.references :member, polymorphic: true, index: true
|
9
|
+
t.references :group, polymorphic: true, index: true
|
10
|
+
t.string :group_name, index: true
|
12
11
|
t.string :membership_type
|
13
12
|
end
|
14
13
|
|
@@ -32,4 +31,29 @@ ActiveRecord::Schema.define(version: 0) do
|
|
32
31
|
create_table :members do |t|
|
33
32
|
t.string :name
|
34
33
|
end
|
34
|
+
|
35
|
+
create_table :classrooms do |t|
|
36
|
+
t.string :name
|
37
|
+
end
|
38
|
+
|
39
|
+
create_table :custom_group_memberships do |t|
|
40
|
+
t.references :member, polymorphic: true, index: true
|
41
|
+
t.references :group, polymorphic: true, index: true
|
42
|
+
t.string :group_name, index: true
|
43
|
+
t.string :membership_type
|
44
|
+
end
|
45
|
+
|
46
|
+
create_table :custom_groups do |t|
|
47
|
+
t.string :name
|
48
|
+
t.string :type
|
49
|
+
end
|
50
|
+
|
51
|
+
create_table :custom_users do |t|
|
52
|
+
t.string :name
|
53
|
+
t.string :type
|
54
|
+
end
|
55
|
+
|
56
|
+
create_table :project_members do |t|
|
57
|
+
t.string :name
|
58
|
+
end
|
35
59
|
end
|
data/spec/mongoid_spec.rb
CHANGED
@@ -35,7 +35,7 @@ require 'groupify/adapter/mongoid'
|
|
35
35
|
class MongoidUser
|
36
36
|
include Mongoid::Document
|
37
37
|
|
38
|
-
groupify :group_member,
|
38
|
+
groupify :group_member, group_class_name: 'MongoidGroup'
|
39
39
|
groupify :named_group_member
|
40
40
|
end
|
41
41
|
|
@@ -44,19 +44,19 @@ end
|
|
44
44
|
|
45
45
|
class MongoidWidget
|
46
46
|
include Mongoid::Document
|
47
|
-
groupify :group_member,
|
47
|
+
groupify :group_member, group_class_name: 'MongoidGroup'
|
48
48
|
end
|
49
49
|
|
50
50
|
class MongoidTask
|
51
51
|
include Mongoid::Document
|
52
52
|
|
53
|
-
groupify :group_member,
|
53
|
+
groupify :group_member, group_class_name: 'MongoidGroup'
|
54
54
|
end
|
55
55
|
|
56
56
|
class MongoidIssue
|
57
57
|
include Mongoid::Document
|
58
58
|
|
59
|
-
groupify :group_member,
|
59
|
+
groupify :group_member, group_class_name: 'MongoidProject'
|
60
60
|
end
|
61
61
|
|
62
62
|
class MongoidGroup
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: groupify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dwbutler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongoid
|
@@ -100,6 +100,20 @@ dependencies:
|
|
100
100
|
- - ">="
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: github_changelog_generator
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
103
117
|
description: Adds group and membership functionality to Rails models
|
104
118
|
email:
|
105
119
|
- dwbutler@ucla.edu
|
@@ -112,6 +126,7 @@ files:
|
|
112
126
|
- ".rspec"
|
113
127
|
- ".travis.yml"
|
114
128
|
- Appraisals
|
129
|
+
- CHANGELOG.md
|
115
130
|
- Gemfile
|
116
131
|
- LICENSE
|
117
132
|
- README.md
|
@@ -121,6 +136,22 @@ files:
|
|
121
136
|
- gemfiles/rails_4.1.gemfile
|
122
137
|
- gemfiles/rails_4.2.gemfile
|
123
138
|
- groupify.gemspec
|
139
|
+
- lib/generators/groupify/active_record/initializer/initializer_generator.rb
|
140
|
+
- lib/generators/groupify/active_record/initializer/templates/initializer.rb
|
141
|
+
- lib/generators/groupify/active_record/install/install_generator.rb
|
142
|
+
- lib/generators/groupify/active_record/migration/migration_generator.rb
|
143
|
+
- lib/generators/groupify/active_record/migration/templates/migration.rb
|
144
|
+
- lib/generators/groupify/active_record/model/model_generator.rb
|
145
|
+
- lib/generators/groupify/active_record/model/templates/group.rb
|
146
|
+
- lib/generators/groupify/active_record/model/templates/group_membership.rb
|
147
|
+
- lib/generators/groupify/active_record/next_migration_version.rb
|
148
|
+
- lib/generators/groupify/active_record/upgrade/templates/upgrade_migration.rb
|
149
|
+
- lib/generators/groupify/active_record/upgrade/upgrade_generator.rb
|
150
|
+
- lib/generators/groupify/mongoid/initializer/initializer_generator.rb
|
151
|
+
- lib/generators/groupify/mongoid/initializer/templates/initializer.rb
|
152
|
+
- lib/generators/groupify/mongoid/install/install_generator.rb
|
153
|
+
- lib/generators/groupify/mongoid/model/model_generator.rb
|
154
|
+
- lib/generators/groupify/mongoid/model/templates/group.rb
|
124
155
|
- lib/groupify.rb
|
125
156
|
- lib/groupify/adapter/active_record.rb
|
126
157
|
- lib/groupify/adapter/active_record/group.rb
|