assigns_has_many_through_relations 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +20 -5
- data/app/assets/.DS_Store +0 -0
- data/app/assets/javascripts/assigns_has_many_through_relations/plugins.js +59 -0
- data/app/assets/stylesheets/.DS_Store +0 -0
- data/app/assets/stylesheets/assigns_has_many_through_relations/application.css.scss +38 -0
- data/app/views/_assigns_has_many_through_relations.html.erb +18 -15
- data/lib/assigns_has_many_through_relations.rb +14 -0
- data/lib/assigns_has_many_through_relations/configuration.rb +10 -0
- data/lib/assigns_has_many_through_relations/controller_concern.rb +2 -0
- data/lib/assigns_has_many_through_relations/version.rb +1 -1
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6dcecc6ee346ff60b3d5c0a6ad374a84f301c2c8
|
4
|
+
data.tar.gz: 60c2dbbeb838b89b3227a825d8d090fea409f6de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f6d1da9e0651b8cec30fab4e4c74579e3559ea83b2d5c972afe8f09b849cdc62e03872c4827821e97340a89246113e1d61b2eb1e31e71614fa40a84c425e458
|
7
|
+
data.tar.gz: 1dab5c419ac3dfbb844c4077712175076fc863223d2a26ee0d530522a35c1ca2fd740ce1f4d1ffb6dfd38ccadd666d6d1910de935540468675acf5972810e723
|
data/README.md
CHANGED
@@ -4,10 +4,12 @@ Rails Engine that provides a management UI to assign models to each other in the
|
|
4
4
|
|
5
5
|
For example, given a pair of models `Location` and `User`, we will consider `Location` to be the left side relation and `User` to be the right side relation. This UI provides a 3 column Bootstrap view where the left most column displays all `Location`s where the user can select one from the list. The 2 other columns are the Assigned and Unnassigned columns. These display `User`s that either have a join model with the selected `Location` or not, respectively. The user can then select `User`s from the Unnassigned column and the form PUT will create the join models necessary to move the Unnassigned `User`s to the middle Assigned column, effectively associating the selected `User`s from the right most column to the selected `Location`.
|
6
6
|
|
7
|
-
##
|
7
|
+
## What You Get
|
8
8
|

|
9
9
|
|
10
|
-
In the above example, clicking on "Assign Selected" will move the selected `User`s to the middle column by creating the `locations_user` join model between them and the selected `Location` "Home".
|
10
|
+
In the above example, clicking on "Assign Selected" will move the selected `User`s to the middle column by creating the `locations_user` join model between them and the selected `Location` "Home".
|
11
|
+
|
12
|
+
You'll notice there's a Filter text input, this will filter the corresponding list as you type. Hitting ESC will clear the text field.
|
11
13
|
|
12
14
|
## Installation
|
13
15
|
|
@@ -25,6 +27,11 @@ Or install it yourself as:
|
|
25
27
|
|
26
28
|
$ gem install assigns_has_many_through_relations
|
27
29
|
|
30
|
+
## Dependencies
|
31
|
+
|
32
|
+
1. [Twitter Bootstrap](http://getbootstrap.com) (if you want the UI to be pre-styled).
|
33
|
+
2. [jQuery](http://jquery.com/download) (for the list Filter).
|
34
|
+
|
28
35
|
## Usage
|
29
36
|
|
30
37
|
Declare the routes:
|
@@ -70,11 +77,19 @@ Finally, render the management UI partial in a view template in `app/views/locat
|
|
70
77
|
|
71
78
|
You'll have to provide the user with a link to `locations_users_path`. And that's it. Now you'll be able to assign and unassign `User`s to `Location`s.
|
72
79
|
|
80
|
+
You can configure the engine to run a controller authorization method as you would a controller macro e.g like [Cancan's](https://github.com/CanCanCommunity/cancancan/wiki/Authorizing-Controller-Actions) `load_and_authorize_resource`:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
# config/initializers/assigns_has_many_through_relations.rb
|
84
|
+
|
85
|
+
AHMTR.configure do
|
86
|
+
auth_filter :load_and_authorize_resource
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
73
90
|
## Todo
|
74
91
|
|
75
|
-
1.
|
76
|
-
2. Write specs.
|
77
|
-
3. Clean up css classes and ids in the partial.
|
92
|
+
1. Write specs.
|
78
93
|
|
79
94
|
## Contributing
|
80
95
|
|
Binary file
|
@@ -0,0 +1,59 @@
|
|
1
|
+
// Call this jQuery plugin on a text input field used to filter a ul as the user types
|
2
|
+
$.fn.quickListFilter = function(options) {
|
3
|
+
options = $.extend({
|
4
|
+
item: 'li'
|
5
|
+
}, options);
|
6
|
+
|
7
|
+
return this.each(function() {
|
8
|
+
var filter = $(this),
|
9
|
+
target = filter.data('target'),
|
10
|
+
items = $(target).find(options.item);
|
11
|
+
|
12
|
+
function filterList() {
|
13
|
+
items.each(function() {
|
14
|
+
var regex = new RegExp(filter.val(), 'i'),
|
15
|
+
li = $(this).parent('li');
|
16
|
+
|
17
|
+
if (regex.test(this.innerText)) {
|
18
|
+
li.slideDown(200);
|
19
|
+
} else {
|
20
|
+
li.slideUp(200);
|
21
|
+
}
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
filter.on('keyup', function(e) {
|
26
|
+
if (e.which === 27) { filter.val(null); }
|
27
|
+
filterList();
|
28
|
+
});
|
29
|
+
});
|
30
|
+
}
|
31
|
+
|
32
|
+
// Call this jQuery plugin on an element that you want to show
|
33
|
+
// when the target element has scrollbars, and hide if no scrollbars.
|
34
|
+
// Useful for a down arrow scroll indicator.
|
35
|
+
$.fn.hideWhenNoScrollBars = function() {
|
36
|
+
return this.each(function() {
|
37
|
+
var el = $(this),
|
38
|
+
target = $(el.data('target'));
|
39
|
+
|
40
|
+
function hideWhenNoScrollbars(target, el) {
|
41
|
+
if (target.scrollHeight > target.clientHeight) { // has vertical scrollbars
|
42
|
+
el.show();
|
43
|
+
} else {
|
44
|
+
el.hide();
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
$(window).on('resize', function() {
|
49
|
+
hideWhenNoScrollbars(target[0], el);
|
50
|
+
});
|
51
|
+
|
52
|
+
hideWhenNoScrollbars(target[0], el);
|
53
|
+
});
|
54
|
+
}
|
55
|
+
|
56
|
+
$(function() {
|
57
|
+
$('.quick-filter').quickListFilter({ item: 'li label, li a' });
|
58
|
+
$('.hide-when-no-scrollbars').hideWhenNoScrollBars();
|
59
|
+
});
|
Binary file
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#ahmtr_wrap {
|
2
|
+
.nav {
|
3
|
+
font-size: 80%;
|
4
|
+
|
5
|
+
.active {
|
6
|
+
background-color: #ebebeb;
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
.fix-height {
|
11
|
+
max-height: 60vh;
|
12
|
+
overflow-y: scroll;
|
13
|
+
}
|
14
|
+
|
15
|
+
input[type="text"] {
|
16
|
+
width: 100%;
|
17
|
+
}
|
18
|
+
|
19
|
+
li {
|
20
|
+
overflow: hidden;
|
21
|
+
|
22
|
+
&:hover {
|
23
|
+
background-color: #ebebeb;
|
24
|
+
}
|
25
|
+
|
26
|
+
label {
|
27
|
+
padding: 5px 7px;
|
28
|
+
cursor: pointer;
|
29
|
+
display: inline-block;
|
30
|
+
width: 95%;
|
31
|
+
}
|
32
|
+
|
33
|
+
input[type="checkbox"] {
|
34
|
+
width: auto;
|
35
|
+
cursor: pointer;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
@@ -1,14 +1,17 @@
|
|
1
1
|
<div class="flash-messages row">
|
2
2
|
<div class="col-sm-12">
|
3
3
|
<% flash.each do |key, message| %>
|
4
|
-
<div class="alert alert-<%= AssignsHasManyThroughRelations::BOOTSTRAP_FLASH_MAP[key] %>" role="alert">
|
5
|
-
|
4
|
+
<div class="alert alert-<%= AssignsHasManyThroughRelations::BOOTSTRAP_FLASH_MAP[key] %> alert-dismissible" role="alert">
|
5
|
+
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
6
|
+
<span aria-hidden="true">×</span>
|
7
|
+
</button>
|
8
|
+
<p><%= message %></p>
|
6
9
|
</div>
|
7
10
|
<% end %>
|
8
11
|
</div>
|
9
12
|
</div>
|
10
13
|
|
11
|
-
<div id="
|
14
|
+
<div id="ahmtr_wrap" class="row">
|
12
15
|
<div class="col-sm-3">
|
13
16
|
<div class="panel panel-info">
|
14
17
|
<div class="panel-heading">
|
@@ -44,15 +47,15 @@
|
|
44
47
|
<div class="col-sm-9">
|
45
48
|
<div class="row">
|
46
49
|
<div class="col-sm-6">
|
47
|
-
<div class="panel panel-primary
|
50
|
+
<div class="panel panel-primary pull-left">
|
48
51
|
<div class="panel-heading">
|
49
52
|
<%= pluralize @selected_right_side_models.size, "#{@selected_left_side_model.name} User" %>
|
50
53
|
</div>
|
51
54
|
|
52
55
|
<div class="panel-body">
|
53
|
-
<%= render 'shared/quick_list_filter', target: '#selected-
|
56
|
+
<%= render 'shared/quick_list_filter', target: '#selected-right-side' %>
|
54
57
|
|
55
|
-
<ul id="selected-
|
58
|
+
<ul id="selected-right-side" class="list-unstyled fix-height">
|
56
59
|
<% @selected_right_side_models.each do |model| %>
|
57
60
|
<li>
|
58
61
|
<%= f.fields_for join_name, @selected_left_side_model.get_join_model_for(model) do |ruf| %>
|
@@ -64,28 +67,28 @@
|
|
64
67
|
<% end %>
|
65
68
|
</ul>
|
66
69
|
|
67
|
-
<div class="text-center hide-when-no-scrollbars" data-target="#selected-
|
70
|
+
<div class="text-center hide-when-no-scrollbars" data-target="#selected-right-side">
|
68
71
|
<span class="glyphicon glyphicon-chevron-down disabled"></span>
|
69
72
|
</div>
|
70
73
|
</div>
|
71
74
|
|
72
75
|
<div class="panel-footer">
|
73
|
-
<%= f.submit 'Unassign Selected', class: 'btn btn-
|
74
|
-
<%= f.submit 'Unassign All', class: 'btn btn-
|
76
|
+
<%= f.submit 'Unassign Selected', class: 'btn btn-primary btn-xs' %>
|
77
|
+
<%= f.submit 'Unassign All', class: 'btn btn-primary btn-xs check-all-boxes', data: { target: '#selected-right-side :checkbox', confirm: "Are you sure you want to Unassign all Users from the \"#{@selected_left_side_model.name}\" #{@selected_left_side_model.class}?" } %>
|
75
78
|
</div>
|
76
79
|
</div>
|
77
80
|
</div>
|
78
81
|
|
79
82
|
<div class="col-sm-6">
|
80
|
-
<div class="panel panel-danger
|
83
|
+
<div class="panel panel-danger pull-left">
|
81
84
|
<div class="panel-heading">
|
82
85
|
<%= pluralize @available_right_side_models.size, "Non #{@selected_left_side_model.name} User" %>
|
83
86
|
</div>
|
84
87
|
|
85
88
|
<div class="panel-body">
|
86
|
-
<%= render 'shared/quick_list_filter', target: '#available-
|
89
|
+
<%= render 'shared/quick_list_filter', target: '#available-right-side' %>
|
87
90
|
|
88
|
-
<ul id="available-
|
91
|
+
<ul id="available-right-side" class="list-unstyled fix-height">
|
89
92
|
<% @available_right_side_models.each do |model| %>
|
90
93
|
<li>
|
91
94
|
<%= f.fields_for join_name, model.send(join_name).build do |ruf| %>
|
@@ -96,14 +99,14 @@
|
|
96
99
|
<% end %>
|
97
100
|
</ul>
|
98
101
|
|
99
|
-
<div class="text-center hide-when-no-scrollbars" data-target="#available-
|
102
|
+
<div class="text-center hide-when-no-scrollbars" data-target="#available-right-side">
|
100
103
|
<span class="glyphicon glyphicon-chevron-down disabled"></span>
|
101
104
|
</div>
|
102
105
|
</div>
|
103
106
|
|
104
107
|
<div class="panel-footer">
|
105
|
-
<%= f.submit 'Assign Selected', class: 'btn btn-
|
106
|
-
<%= f.submit 'Assign All', class: 'btn btn-primary btn-
|
108
|
+
<%= f.submit 'Assign Selected', class: 'btn btn-primary btn-xs' %>
|
109
|
+
<%= f.submit 'Assign All', class: 'btn btn-primary btn-xs check-all-boxes', data: { target: '#available-right-side :checkbox', confirm: "Are you sure you want to Assign all Users to the \"#{@selected_left_side_model.name}\" #{@selected_left_side_model.class}?" } %>
|
107
110
|
</div>
|
108
111
|
</div>
|
109
112
|
</div>
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "assigns_has_many_through_relations/version"
|
2
2
|
require "assigns_has_many_through_relations/engine"
|
3
|
+
require "assigns_has_many_through_relations/configuration"
|
3
4
|
|
4
5
|
module AssignsHasManyThroughRelations
|
5
6
|
BOOTSTRAP_FLASH_MAP = {
|
@@ -11,6 +12,16 @@ module AssignsHasManyThroughRelations
|
|
11
12
|
autoload :ControllerConcern, 'assigns_has_many_through_relations/controller_concern'
|
12
13
|
autoload :ModelConcern, 'assigns_has_many_through_relations/model_concern'
|
13
14
|
|
15
|
+
class << self
|
16
|
+
attr_reader :config
|
17
|
+
delegate :auth_filter, to: :config
|
18
|
+
|
19
|
+
def configure(&block)
|
20
|
+
@config ||= Configuration.new
|
21
|
+
@config.instance_exec &block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
14
25
|
module_function
|
15
26
|
|
16
27
|
def join_name_for(left_relation, right_relation)
|
@@ -26,3 +37,6 @@ module AssignsHasManyThroughRelations
|
|
26
37
|
routes.put "/#{left_name}/#{right_name}/:id", to: "#{name}#update", as: "assign_#{name}"
|
27
38
|
end
|
28
39
|
end
|
40
|
+
|
41
|
+
AHMTR = AssignsHasManyThroughRelations
|
42
|
+
AHMTR.configure {} # so that @config is never nil
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module AssignsHasManyThroughRelations
|
2
|
+
class Configuration
|
3
|
+
# Assign the name of a controller class method that you want to run for authorization
|
4
|
+
# e.g. Cancan's :load_and_authorize_resource, or a custom method you define
|
5
|
+
# in your ApplicationController
|
6
|
+
def auth_filter(val = nil)
|
7
|
+
@auth_filter ||= val
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -9,6 +9,8 @@ module AssignsHasManyThroughRelations
|
|
9
9
|
|
10
10
|
include AssignsHasManyThroughRelations::ControllerInstanceMethods
|
11
11
|
helper_method :left_relation_class_name, :join_name
|
12
|
+
|
13
|
+
send AHMTR.auth_filter if AHMTR.auth_filter
|
12
14
|
end
|
13
15
|
|
14
16
|
def left_relation_param_name; @left_relation_param_name end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: assigns_has_many_through_relations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Diego Salazar
|
@@ -64,10 +64,15 @@ files:
|
|
64
64
|
- LICENSE.txt
|
65
65
|
- README.md
|
66
66
|
- Rakefile
|
67
|
+
- app/assets/.DS_Store
|
68
|
+
- app/assets/javascripts/assigns_has_many_through_relations/plugins.js
|
69
|
+
- app/assets/stylesheets/.DS_Store
|
70
|
+
- app/assets/stylesheets/assigns_has_many_through_relations/application.css.scss
|
67
71
|
- app/views/.DS_Store
|
68
72
|
- app/views/_assigns_has_many_through_relations.html.erb
|
69
73
|
- assigns_has_many_through_relations.gemspec
|
70
74
|
- lib/assigns_has_many_through_relations.rb
|
75
|
+
- lib/assigns_has_many_through_relations/configuration.rb
|
71
76
|
- lib/assigns_has_many_through_relations/controller_concern.rb
|
72
77
|
- lib/assigns_has_many_through_relations/engine.rb
|
73
78
|
- lib/assigns_has_many_through_relations/model_concern.rb
|