effective_mergery 0.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +68 -0
- data/app/assets/javascripts/effective_mergery.js +2 -0
- data/app/assets/javascripts/effective_mergery/merge.js.coffee +20 -0
- data/app/assets/stylesheets/effective_mergery.scss +1 -0
- data/app/assets/stylesheets/effective_mergery/_merge.scss +5 -0
- data/app/controllers/admin/merge_controller.rb +63 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/app/models/effective/merge.rb +91 -0
- data/app/views/admin/merge/_attributes.html.haml +3 -0
- data/app/views/admin/merge/create.html.haml +11 -0
- data/app/views/admin/merge/index.html.haml +10 -0
- data/app/views/admin/merge/new.html.haml +29 -0
- data/config/effective_mergery.rb +48 -0
- data/config/routes.rb +11 -0
- data/lib/effective_mergery.rb +44 -0
- data/lib/effective_mergery/engine.rb +13 -0
- data/lib/effective_mergery/version.rb +3 -0
- data/lib/generators/effective_mergery/install_generator.rb +16 -0
- metadata +133 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 185eb0a320784bf5e9f6cc24b1db3296761469d8
|
|
4
|
+
data.tar.gz: 79ed4931f61a2c803e50e8b132d9bae2d0060c97
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 29c4448f5df36346b5567795a9548ed8f1bcef9d03d7e83142c479653a26027b3f940cc234b603ec54278988deb14ef1fdfeaf24caf654a3856d1998e04ffab1
|
|
7
|
+
data.tar.gz: bd52345540fcfd32a37751d8d25e70857158a9ccacd64332850f827988475aa28573dcbc9753b318a8c3eea8451f4c2630f47185baec4b958c049bf07cdea0e8
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2017 Code and Effect Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Effective Mergery
|
|
2
|
+
|
|
3
|
+
Merge any two Active Record objects, along with all associated objects, into one record.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'effective_mergery'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run the bundle command to install it:
|
|
14
|
+
|
|
15
|
+
```console
|
|
16
|
+
bundle install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Then run the generator:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
rails generate effective_mergery:install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The generator will install an initializer which describes all configuration options.
|
|
26
|
+
|
|
27
|
+
Require the javascript on the asset pipeline by adding the following to your application.js:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
//= require effective_mergery
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Require the stylesheet on the asset pipeline by adding the following to your application.css:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
*= require effective_mergery
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
Visit `/admin/merge` and select an object type to merge.
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
link_to 'Merge', effective_mergery.admin_merge_index_path
|
|
45
|
+
link_to 'Merge: User', effective_mergery.new_admin_merge_path(type: 'User')
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Permissions
|
|
49
|
+
|
|
50
|
+
Add the following permissions (using CanCan):
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
can :admin, :effective_mergery
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
|
|
59
|
+
|
|
60
|
+
## Contributing
|
|
61
|
+
|
|
62
|
+
1. Fork it
|
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
66
|
+
5. Bonus points for test coverage
|
|
67
|
+
6. Create new Pull Request
|
|
68
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
loadAttributes = (event) ->
|
|
2
|
+
$obj = $(event.currentTarget)
|
|
3
|
+
|
|
4
|
+
id = parseInt($obj.val())
|
|
5
|
+
type = $obj.closest('form').find("input[name='effective_merge[type]']").val()
|
|
6
|
+
|
|
7
|
+
selector = if ($obj.attr('name') == 'effective_merge[source_id]') then '.source' else '.target'
|
|
8
|
+
content = $obj.closest('form').find(selector).first()
|
|
9
|
+
|
|
10
|
+
url = "/admin/merge/attributes?id=#{id}&type=#{type}"
|
|
11
|
+
|
|
12
|
+
if id != undefined && id != NaN && id > 0 && type.length > 0
|
|
13
|
+
content.load(url, (response, status, xhr) =>
|
|
14
|
+
content.html('<p>This item is unavailable (ajax error)</p>') if status == 'error'
|
|
15
|
+
)
|
|
16
|
+
else
|
|
17
|
+
content.html('')
|
|
18
|
+
|
|
19
|
+
$(document).on 'change', "select[name='effective_merge[source_id]']", (event) -> loadAttributes(event)
|
|
20
|
+
$(document).on 'change', "select[name='effective_merge[target_id]']", (event) -> loadAttributes(event)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import 'effective_mergery/merge';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Admin
|
|
2
|
+
class MergeController < ApplicationController
|
|
3
|
+
before_action :authenticate_user! if defined?(Devise)
|
|
4
|
+
|
|
5
|
+
layout (EffectiveMergery.layout.kind_of?(Hash) ? EffectiveMergery.layout[:admin_merge] : EffectiveMergery.layout)
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
@page_title = 'Merges'
|
|
9
|
+
EffectiveMergery.authorized?(self, :admin, :effective_mergery)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def new
|
|
13
|
+
@page_title = 'New Merge'
|
|
14
|
+
EffectiveMergery.authorized?(self, :admin, :effective_mergery)
|
|
15
|
+
|
|
16
|
+
begin
|
|
17
|
+
@merge = Effective::Merge.new(type: params[:type])
|
|
18
|
+
@merge.validate_klass!
|
|
19
|
+
rescue => e
|
|
20
|
+
flash[:danger] = "An error occurred while loading #{@merge}: #{e.message}"
|
|
21
|
+
redirect_to effective_mergery.admin_merge_index_path
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create
|
|
26
|
+
EffectiveMergery.authorized?(self, :admin, :effective_mergery)
|
|
27
|
+
|
|
28
|
+
@merge = Effective::Merge.new(merge_params)
|
|
29
|
+
|
|
30
|
+
if @merge.save
|
|
31
|
+
@page_title = 'Successful Merge'
|
|
32
|
+
flash[:success] = "Successfully merged #{@merge}"
|
|
33
|
+
|
|
34
|
+
@merge.target = @merge.collection.find(@merge.target_id)
|
|
35
|
+
else
|
|
36
|
+
@page_title = 'New Merge'
|
|
37
|
+
flash.now[:danger] = "Unable to merge #{@merge}: #{@merge.errors.full_messages.to_sentence}"
|
|
38
|
+
|
|
39
|
+
render :new
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# This is the AJAX request for the object's attributes
|
|
44
|
+
def attributes
|
|
45
|
+
EffectiveMergery.authorized?(self, :admin, :effective_mergery)
|
|
46
|
+
|
|
47
|
+
object = Effective::Merge.new(type: params[:type]).collection.find(params[:id])
|
|
48
|
+
|
|
49
|
+
if object.present?
|
|
50
|
+
render partial: '/admin/merge/attributes', locals: { resource: object }
|
|
51
|
+
else
|
|
52
|
+
render body: '<p>None Available</p>'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def merge_params
|
|
59
|
+
params.require(:effective_merge).permit(:type, :source_id, :target_id)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
unless defined?(Effective::AccessDenied)
|
|
2
|
+
module Effective
|
|
3
|
+
class AccessDenied < StandardError
|
|
4
|
+
attr_reader :action, :subject
|
|
5
|
+
|
|
6
|
+
def initialize(message = nil, action = nil, subject = nil)
|
|
7
|
+
@message = message
|
|
8
|
+
@action = action
|
|
9
|
+
@subject = subject
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
@message || I18n.t(:'unauthorized.default', :default => 'Access Denied')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module Effective
|
|
2
|
+
class Merge
|
|
3
|
+
include ActiveModel::Model
|
|
4
|
+
|
|
5
|
+
attr_accessor :type, :source, :source_id, :target, :target_id
|
|
6
|
+
|
|
7
|
+
validate(if: -> { source_id.present? }) { @source ||= collection.find_by_id(source_id) }
|
|
8
|
+
validate(if: -> { target_id.present? }) { @target ||= collection.find_by_id(target_id) }
|
|
9
|
+
|
|
10
|
+
validates :type, presence: true, inclusion: { in: EffectiveMergery.mergables, message: 'must be a mergable type' }
|
|
11
|
+
validates :source_id, presence: true, unless: -> { source.present? }
|
|
12
|
+
validates :target_id, presence: true, unless: -> { target.present? }
|
|
13
|
+
|
|
14
|
+
validate(if: -> { source_id.present? && target_id.present? }) do
|
|
15
|
+
self.errors.add(:target_id, "can't be the same as source") if source_id == target_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
validates :source, presence: { message: 'invalid source id' }, if: -> { source_id.present? }
|
|
19
|
+
validates :target, presence: { message: 'invalid target id' }, if: -> { target_id.present? }
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
return 'New Merge' unless type
|
|
23
|
+
type.downcase
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def save(validate: true)
|
|
27
|
+
return false unless valid?
|
|
28
|
+
(merge!(validate: validate) rescue false)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def save!(validate: true)
|
|
32
|
+
raise 'is invalid' unless valid?
|
|
33
|
+
merge!(validate: validate)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def collection
|
|
37
|
+
@collection ||= (klass.respond_to?(:sorted) ? klass.sorted : klass.all)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def klass
|
|
41
|
+
@klass ||= type.safe_constantize
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# This is called on Admin::Merges#new
|
|
45
|
+
def validate_klass!
|
|
46
|
+
raise "type can't be blank" unless type.present?
|
|
47
|
+
raise 'type must be a mergable type' unless EffectiveMergery.mergables.include?(type)
|
|
48
|
+
raise "invalid ActiveRecord klass" unless klass
|
|
49
|
+
raise "invalid ActiveRecord collection" unless collection.kind_of?(ActiveRecord::Relation)
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def merge!(validate: true)
|
|
56
|
+
resource = Effective::Resource.new(source)
|
|
57
|
+
|
|
58
|
+
klass.transaction do
|
|
59
|
+
begin
|
|
60
|
+
|
|
61
|
+
# Merge associations
|
|
62
|
+
(resource.has_ones + resource.has_manys + resource.nested_resources).compact.each do |association|
|
|
63
|
+
next if association.options[:through].present?
|
|
64
|
+
|
|
65
|
+
Array(source.send(association.name)).each do |obj|
|
|
66
|
+
obj.assign_attributes(association.foreign_key => target.id)
|
|
67
|
+
|
|
68
|
+
unless obj.save(validate: validate)
|
|
69
|
+
raise "associated #{obj.class.name}<#{obj.to_param}> is invalid: #{obj.errors.full_messages.to_sentence}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
source.destroy!
|
|
75
|
+
|
|
76
|
+
unless target.save(validate: validate)
|
|
77
|
+
raise "merged #{target.class.name} is invalid: #{target.errors.full_messages.to_sentence}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
return true
|
|
81
|
+
rescue => e
|
|
82
|
+
self.errors.add(:base, e.message)
|
|
83
|
+
raise ActiveRecord::Rollback
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
%h1.effective-admin-heading= @page_title
|
|
2
|
+
|
|
3
|
+
.row
|
|
4
|
+
.col-sm-2
|
|
5
|
+
.col-sm-8
|
|
6
|
+
%p= @merge.target
|
|
7
|
+
= render partial: '/admin/merge/attributes', locals: { resource: @merge.target }
|
|
8
|
+
.col-sm-2
|
|
9
|
+
|
|
10
|
+
.text-center
|
|
11
|
+
%p= link_to "Merge Another #{@merge}", effective_mergery.new_admin_merge_path(type: @merge.type), class: 'btn btn-primary'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
%h1.effective-admin-heading= @page_title
|
|
2
|
+
|
|
3
|
+
%p Please select one of the following to merge:
|
|
4
|
+
|
|
5
|
+
- if EffectiveMergery.mergables.blank?
|
|
6
|
+
%p There is nothing available to merge.
|
|
7
|
+
- else
|
|
8
|
+
%ul
|
|
9
|
+
- EffectiveMergery.mergables.each do |name|
|
|
10
|
+
%li= link_to name, effective_mergery.new_admin_merge_path(type: name)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
%h1.effective-admin-heading= @page_title
|
|
2
|
+
|
|
3
|
+
%p Please select a source and target. The source record's associated data, but not its attributes, will be merged into the target. The source record will then be destroyed.
|
|
4
|
+
|
|
5
|
+
.effective-merge
|
|
6
|
+
= simple_form_for [:admin, @merge], (EffectiveOrders.admin_simple_form_options || {}).merge(url: effective_mergery.admin_merge_index_path) do |f|
|
|
7
|
+
= f.input :type, as: :hidden
|
|
8
|
+
|
|
9
|
+
.row
|
|
10
|
+
.col-sm-6
|
|
11
|
+
= f.input :source_id, as: (defined?(EffectiveFormInputs) ? :effective_select : :select),
|
|
12
|
+
collection: f.object.collection,
|
|
13
|
+
hint: 'This record will be destroyed'
|
|
14
|
+
.col-sm-6
|
|
15
|
+
= f.input :target_id, as: (defined?(EffectiveFormInputs) ? :effective_select : :select),
|
|
16
|
+
collection: f.object.collection,
|
|
17
|
+
hint: 'This record will be kept'
|
|
18
|
+
|
|
19
|
+
.row
|
|
20
|
+
.col-sm-6.source
|
|
21
|
+
- if f.object.source.present?
|
|
22
|
+
= render partial: '/admin/merge/attributes', locals: { resource: f.object.source }
|
|
23
|
+
|
|
24
|
+
.col-sm-6.target
|
|
25
|
+
- if f.object.target.present?
|
|
26
|
+
= render partial: '/admin/merge/attributes', locals: { resource: f.object.target }
|
|
27
|
+
|
|
28
|
+
.text-center
|
|
29
|
+
= f.button :submit, "Merge #{@merge}", data: { disable_with: 'Merging...', confirm: "Really merge? The source record will be destroyed."}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
EffectiveMergery.setup do |config|
|
|
2
|
+
# Authorization Method
|
|
3
|
+
#
|
|
4
|
+
# This method is called by all controller actions with the appropriate action and resource
|
|
5
|
+
# If the method returns false, an Effective::AccessDenied Error will be raised (see README.md for complete info)
|
|
6
|
+
#
|
|
7
|
+
# Use via Proc (and with CanCan):
|
|
8
|
+
# config.authorization_method = Proc.new { |controller, action, resource| can?(action, resource) }
|
|
9
|
+
#
|
|
10
|
+
# Use via custom method:
|
|
11
|
+
# config.authorization_method = :my_authorization_method
|
|
12
|
+
#
|
|
13
|
+
# And then in your application_controller.rb:
|
|
14
|
+
#
|
|
15
|
+
# def my_authorization_method(action, resource)
|
|
16
|
+
# current_user.is?(:admin)
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# Or disable the check completely:
|
|
20
|
+
# config.authorization_method = false
|
|
21
|
+
config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) } # CanCanCan
|
|
22
|
+
|
|
23
|
+
# Admin Screens Layout Settings
|
|
24
|
+
config.layout = 'application' # All EffectiveMergery controllers will use this layout
|
|
25
|
+
|
|
26
|
+
# config.layout = {
|
|
27
|
+
# merge: 'application',
|
|
28
|
+
# admin_merge: 'admin',
|
|
29
|
+
# }
|
|
30
|
+
|
|
31
|
+
config.admin_simple_form_options = {} # For the /admin/merge/new form
|
|
32
|
+
# config.admin_simple_form_options = {
|
|
33
|
+
# :html => {:class => ['form-horizontal']},
|
|
34
|
+
# :wrapper => :horizontal_form,
|
|
35
|
+
# :wrapper_mappings => {
|
|
36
|
+
# :boolean => :horizontal_boolean,
|
|
37
|
+
# :check_boxes => :horizontal_radio_and_checkboxes,
|
|
38
|
+
# :radio_buttons => :horizontal_radio_and_checkboxes
|
|
39
|
+
# }
|
|
40
|
+
# }
|
|
41
|
+
|
|
42
|
+
# Allow merges for only the following ActiveRecord class names:
|
|
43
|
+
# config.only = ['User']
|
|
44
|
+
|
|
45
|
+
# Allow merges on all ActiveRecord classes, except the following:
|
|
46
|
+
# config.except = []
|
|
47
|
+
|
|
48
|
+
end
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
EffectiveMergery::Engine.routes.draw do
|
|
2
|
+
namespace :admin do
|
|
3
|
+
resources :merge, only: [:index, :new, :create] do
|
|
4
|
+
get :attributes, on: :collection
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
Rails.application.routes.draw do
|
|
10
|
+
mount EffectiveMergery::Engine => '/', :as => 'effective_mergery'
|
|
11
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'effective_resources'
|
|
2
|
+
require 'effective_mergery/engine'
|
|
3
|
+
require 'effective_mergery/version'
|
|
4
|
+
|
|
5
|
+
module EffectiveMergery
|
|
6
|
+
|
|
7
|
+
# The following are all valid config keys
|
|
8
|
+
mattr_accessor :authorization_method
|
|
9
|
+
mattr_accessor :layout
|
|
10
|
+
mattr_accessor :admin_simple_form_options
|
|
11
|
+
|
|
12
|
+
mattr_accessor :only
|
|
13
|
+
mattr_accessor :except
|
|
14
|
+
|
|
15
|
+
def self.setup
|
|
16
|
+
yield self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.authorized?(controller, action, resource)
|
|
20
|
+
if authorization_method.respond_to?(:call) || authorization_method.kind_of?(Symbol)
|
|
21
|
+
raise Effective::AccessDenied.new() unless (controller || self).instance_exec(controller, action, resource, &authorization_method)
|
|
22
|
+
end
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.mergables
|
|
27
|
+
@mergables ||= (
|
|
28
|
+
Rails.application.eager_load! unless Rails.configuration.cache_classes
|
|
29
|
+
|
|
30
|
+
blacklist = ['Delayed::', 'Effective::', 'ActiveRecord::', 'ApplicationRecord']
|
|
31
|
+
|
|
32
|
+
ActiveRecord::Base.descendants.map { |obj| obj.name }.tap do |names|
|
|
33
|
+
names.reject! { |name| blacklist.any? { |b| name.start_with?(b) } }
|
|
34
|
+
|
|
35
|
+
if (onlies = Array(only)).present?
|
|
36
|
+
names.select! { |name| onlies.include?(name) }
|
|
37
|
+
elsif (excepts = Array(except)).present?
|
|
38
|
+
names.reject! { |name| excepts.include?(name) }
|
|
39
|
+
end
|
|
40
|
+
end.sort
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module EffectiveMergery
|
|
2
|
+
class Engine < ::Rails::Engine
|
|
3
|
+
engine_name 'effective_mergery'
|
|
4
|
+
|
|
5
|
+
config.autoload_paths += Dir["#{config.root}/lib/"]
|
|
6
|
+
|
|
7
|
+
# Set up our default configuration options.
|
|
8
|
+
initializer "effective_mergery.defaults", before: :load_config_initializers do |app|
|
|
9
|
+
eval File.read("#{config.root}/config/effective_mergery.rb")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module EffectiveMergery
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
include Rails::Generators::Migration
|
|
5
|
+
|
|
6
|
+
desc 'Creates an EffectiveMergery initializer in your application.'
|
|
7
|
+
|
|
8
|
+
source_root File.expand_path('../../templates', __FILE__)
|
|
9
|
+
|
|
10
|
+
def copy_initializer
|
|
11
|
+
template ('../' * 3) + 'config/effective_mergery.rb', 'config/initializers/effective_mergery.rb'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: effective_mergery
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: '0.1'
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Code and Effect
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-07-04 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 3.2.0
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 3.2.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: effective_resources
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: coffee-rails
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: sass-rails
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: simple_form
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
description: Deep merge any two Active Record objects.
|
|
84
|
+
email:
|
|
85
|
+
- info@codeandeffect.com
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- MIT-LICENSE
|
|
91
|
+
- README.md
|
|
92
|
+
- app/assets/javascripts/effective_mergery.js
|
|
93
|
+
- app/assets/javascripts/effective_mergery/merge.js.coffee
|
|
94
|
+
- app/assets/stylesheets/effective_mergery.scss
|
|
95
|
+
- app/assets/stylesheets/effective_mergery/_merge.scss
|
|
96
|
+
- app/controllers/admin/merge_controller.rb
|
|
97
|
+
- app/models/effective/access_denied.rb
|
|
98
|
+
- app/models/effective/merge.rb
|
|
99
|
+
- app/views/admin/merge/_attributes.html.haml
|
|
100
|
+
- app/views/admin/merge/create.html.haml
|
|
101
|
+
- app/views/admin/merge/index.html.haml
|
|
102
|
+
- app/views/admin/merge/new.html.haml
|
|
103
|
+
- config/effective_mergery.rb
|
|
104
|
+
- config/routes.rb
|
|
105
|
+
- lib/effective_mergery.rb
|
|
106
|
+
- lib/effective_mergery/engine.rb
|
|
107
|
+
- lib/effective_mergery/version.rb
|
|
108
|
+
- lib/generators/effective_mergery/install_generator.rb
|
|
109
|
+
homepage: https://github.com/code-and-effect/effective_mergery
|
|
110
|
+
licenses:
|
|
111
|
+
- MIT
|
|
112
|
+
metadata: {}
|
|
113
|
+
post_install_message:
|
|
114
|
+
rdoc_options: []
|
|
115
|
+
require_paths:
|
|
116
|
+
- lib
|
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
|
+
requirements:
|
|
119
|
+
- - ">="
|
|
120
|
+
- !ruby/object:Gem::Version
|
|
121
|
+
version: '0'
|
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
|
+
requirements:
|
|
124
|
+
- - ">="
|
|
125
|
+
- !ruby/object:Gem::Version
|
|
126
|
+
version: '0'
|
|
127
|
+
requirements: []
|
|
128
|
+
rubyforge_project:
|
|
129
|
+
rubygems_version: 2.4.5.1
|
|
130
|
+
signing_key:
|
|
131
|
+
specification_version: 4
|
|
132
|
+
summary: Deep merge any two Active Record objects.
|
|
133
|
+
test_files: []
|