effective_resources 0.2.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25f7989cfcdf5345382d521f94331238f4ecd109
4
- data.tar.gz: 0d2a3d92af2badd786a6d15da1e78daadaa5ffb9
3
+ metadata.gz: e0162b9865a0d7b0f8792b361f46f886c905286a
4
+ data.tar.gz: d3b8a389e8ff5e40860603aa22ed948bde07cc37
5
5
  SHA512:
6
- metadata.gz: 3eb401a0edeef0cda4a3f8eddf9e409f30e8a4e643e62bfa70e8914a4d4f44b69eb20719872d254f96d7afdb98bae7dfb6be20492ba327e3d3d08c4c5c7d315f
7
- data.tar.gz: 847044d382ea15c9b1a06786a09db78d82fe1d16636260d664d6d6f5afc90d2f1bb4a51fbada52b655f2516d719076ef21dfec73ec6a32bcbf0fcfa806fcc97c
6
+ metadata.gz: 7868a5dc8b09f78c1fd044878b9872e65a27e6698a8f52878d6a09a87dbde581c84a33b029d6d0c1869c2e362c24ab446c7b8e3d78ae95fd8e6f071d8c9786e1
7
+ data.tar.gz: 63eb662a68bb241d51b441dad12c2bcbba3cceaa8a04495e2fb868c56cb1aa441a64258ce347e69ccc268d98e7c08f16d345c906f954b92fa1a3e246d44daa07
data/README.md CHANGED
@@ -6,8 +6,6 @@ Implements the 7 RESTful actions as a one-liner on any controller.
6
6
 
7
7
  ## Getting Started
8
8
 
9
- Add to your Gemfile:
10
-
11
9
  ```ruby
12
10
  gem 'effective_resources'
13
11
  ```
@@ -18,6 +16,14 @@ Run the bundle command to install it:
18
16
  bundle install
19
17
  ```
20
18
 
19
+ Install the configuration file:
20
+
21
+ ```console
22
+ rails generate effective_resources:install
23
+ ```
24
+
25
+ The generator will install an initializer which describes all configuration options.
26
+
21
27
  ## Usage
22
28
 
23
29
  Add to your contoller:
@@ -26,6 +32,8 @@ Add to your contoller:
26
32
  class PostsController < ApplicationController
27
33
  include Effective::CrudController
28
34
 
35
+ member_action :something
36
+
29
37
  protected
30
38
 
31
39
  def post_scope
@@ -65,6 +73,18 @@ Call `simple_form_submit(f)` like follows:
65
73
 
66
74
  to render 3 submit buttons: `Save`, `Save and Continue`, and `Save and Add New`.
67
75
 
76
+ ### simple_form_save
77
+
78
+ Call `simple_form_save(f)` like follows:
79
+
80
+ ```haml
81
+ = simple_form_for(post) do |f|
82
+ ...
83
+ = simple_form_save(f)
84
+ ```
85
+
86
+ to render just the `Save` button, with appropriate data-disable, title, etc.
87
+
68
88
  ## License
69
89
 
70
90
  MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
@@ -0,0 +1,2 @@
1
+ //= require_tree ./effective_resources
2
+
@@ -0,0 +1,85 @@
1
+ ;(function($, window, document, undefined) {
2
+ 'use strict';
3
+
4
+ var defaults = {};
5
+
6
+ function EffectiveUjs(element, command, options) {
7
+ if(typeof(command) === 'string') { // Convert to camelCase
8
+ command = command.replace(/-([a-z])/g, function (str) { return str[1].toUpperCase(); });
9
+ }
10
+
11
+ if(typeof(this[command]) === 'function') {
12
+ this[command]($(element), $.extend({}, defaults, options));
13
+ }
14
+ }
15
+
16
+ $.extend(EffectiveUjs.prototype, {
17
+
18
+ // Converts all inputs to required fields
19
+ // $('#div-with-inputs').effective('inputs-required')
20
+ // $('input').effective('inputs-required')
21
+ inputsRequired: function(element, options) {
22
+ var elements = (element.first().is(':input') ? element : element.find('input,select,textarea'));
23
+
24
+ elements.each(function(index) {
25
+ var input = $(this);
26
+ var formGroup = input.closest('.form-group');
27
+
28
+ if(input.attr('type') == 'hidden') { return; }
29
+ if(input.hasClass('optional') && (input.attr('name') || '').indexOf('[address2]') > -1) { return; } // EffectiveAddresses
30
+
31
+ // Require the input
32
+ input.prop('required', true);
33
+
34
+ // Add the *
35
+ formGroup.find('abbr').remove();
36
+ input.parent().find('abbr').remove();
37
+
38
+ if(input.parent().is('label')) {
39
+ input.after("<abbr title='required'>*</abbr> ");
40
+ } else if(formGroup.length > 0) {
41
+ formGroup.find('label').prepend("<abbr title='required'>*</abbr> ");
42
+ } else {
43
+ input.parent().find('label').prepend("<abbr title='required'>*</abbr> ");
44
+ }
45
+
46
+ if(formGroup.length > 0) {
47
+ formGroup.removeClass('optional').addClass('required');
48
+ formGroup.find('.optional').removeClass('optional').addClass('required');
49
+ }
50
+ });
51
+ },
52
+
53
+ // Converts all inputs to non-required fields
54
+ // $('#div-with-inputs').effective('inputs-optional')
55
+ // $('input').effective('inputs-optional')
56
+ inputsOptional: function(element, options) {
57
+ var elements = (element.first().is(':input') ? element : element.find('input,select,textarea'));
58
+
59
+ elements.each(function(index) {
60
+ var input = $(this);
61
+ var formGroup = input.closest('.form-group');
62
+
63
+ if(input.attr('type') == 'hidden') { return; }
64
+
65
+ // Un-require the input
66
+ input.prop('required', false).removeAttr('required');
67
+
68
+ // Remove the *
69
+ formGroup.find('abbr').remove();
70
+ input.parent().find('abbr').remove();
71
+
72
+ if(formGroup.length > 0) {
73
+ formGroup.removeClass('required').addClass('optional');
74
+ formGroup.find('.required').removeClass('required').addClass('optional');
75
+ }
76
+ });
77
+ }
78
+
79
+ });
80
+
81
+ $.fn.effective = function(command, options) {
82
+ return this.each(function() { new EffectiveUjs(this, command, options); });
83
+ };
84
+
85
+ })(jQuery, window, document);
@@ -6,6 +6,16 @@ module Effective
6
6
  end
7
7
 
8
8
  module ClassMethods
9
+ # Add the following to your controller for a simple member action
10
+ # member_action :print
11
+ def member_action(action)
12
+ define_method(action) do
13
+ self.resource ||= resource_class.find(params[:id])
14
+
15
+ @page_title ||= resource.to_s
16
+ EffectiveResources.authorized?(self, action, resource)
17
+ end
18
+ end
9
19
  end
10
20
 
11
21
  def index
@@ -114,6 +124,10 @@ module Effective
114
124
 
115
125
  private
116
126
 
127
+ def effective_resource
128
+ @_effective_resource ||= Effective::Resource.new(controller_path)
129
+ end
130
+
117
131
  def resource_name # 'thing'
118
132
  effective_resource.name
119
133
  end
@@ -167,11 +181,5 @@ module Effective
167
181
  effective_resource.index_path
168
182
  end
169
183
 
170
- private
171
-
172
- def effective_resource
173
- @_effective_resource ||= Effective::Resource.new(controller_path)
174
- end
175
-
176
184
  end
177
185
  end
@@ -1,18 +1,19 @@
1
1
  module EffectiveResourcesHelper
2
2
 
3
- def simple_form_submit(form)
4
- content_tag(:p, class: 'text-right') do
3
+ def simple_form_submit(form, options = {class: 'text-right'}, &block)
4
+ content_tag(:p, class: options[:class]) do
5
5
  [
6
6
  form.button(:submit, 'Save', data: { disable_with: 'Saving...' }),
7
7
  form.button(:submit, 'Save and Continue', data: { disable_with: 'Saving...' }),
8
- form.button(:submit, 'Save and Add New', data: { disable_with: 'Saving...' })
9
- ].join(' ').html_safe
8
+ form.button(:submit, 'Save and Add New', data: { disable_with: 'Saving...' }),
9
+ (capture(&block) if block_given?)
10
+ ].compact.join(' ').html_safe
10
11
  end
11
12
  end
12
13
 
13
- def simple_form_save(form)
14
- content_tag(:p, class: 'text-right') do
15
- form.button(:submit, 'Save', data: { disable_with: 'Saving...' })
14
+ def simple_form_save(form, options = {class: 'text-right'}, &block)
15
+ content_tag(:p, class: options[:class]) do
16
+ form.button(:submit, 'Save', data: { disable_with: 'Saving...' }) + (capture(&:block) if block_given?)
16
17
  end
17
18
  end
18
19
 
@@ -3,6 +3,7 @@ module Effective
3
3
  include Effective::Resources::Associations
4
4
  include Effective::Resources::Attributes
5
5
  include Effective::Resources::Init
6
+ include Effective::Resources::Instance
6
7
  include Effective::Resources::Klass
7
8
  include Effective::Resources::Naming
8
9
  include Effective::Resources::Paths
@@ -4,19 +4,22 @@ module Effective
4
4
 
5
5
  def belong_tos
6
6
  return [] unless klass.respond_to?(:reflect_on_all_associations)
7
-
8
7
  @belong_tos ||= klass.reflect_on_all_associations(:belongs_to)
9
8
  end
10
9
 
11
- def nested_resources
12
- return {} unless klass.respond_to?(:reflect_on_all_autosave_associations)
13
-
14
- @nested ||= klass.reflect_on_all_autosave_associations.inject({}) do |hash, reference|
15
- hash[reference] = Effective::Resource.new(reference); hash
16
- end
10
+ def has_ones
11
+ return [] unless klass.respond_to?(:reflect_on_all_associations)
12
+ @has_ones ||= klass.reflect_on_all_associations(:has_one)
17
13
  end
18
14
 
19
15
  def has_manys
16
+ return [] unless klass.respond_to?(:reflect_on_all_associations)
17
+ @has_manys ||= klass.reflect_on_all_associations(:has_many).reject { |association| association.options[:autosave] }
18
+ end
19
+
20
+ def nested_resources
21
+ return [] unless klass.respond_to?(:reflect_on_all_associations)
22
+ @nested_resources ||= klass.reflect_on_all_associations(:has_many).select { |association| association.options[:autosave] }
20
23
  end
21
24
 
22
25
  def scopes
@@ -4,8 +4,9 @@ module Effective
4
4
 
5
5
  private
6
6
 
7
- def _initialize(input)
8
- @input_name = _initialize_input_name(input)
7
+ def _initialize(obj)
8
+ @input_name = _initialize_input_name(obj)
9
+ @instance = obj if (klass && obj.instance_of?(klass))
9
10
  end
10
11
 
11
12
  def _initialize_input_name(input)
@@ -13,10 +14,11 @@ module Effective
13
14
  when String ; input
14
15
  when Symbol ; input
15
16
  when Class ; input.name
16
- when ActiveRecord::Reflection::MacroReflection ; input.name
17
+ when (ActiveRecord::Reflection::MacroReflection rescue false); input.name
18
+ when (ActionDispatch::Journey::Route rescue false); input.defaults[:controller]
17
19
  when nil ; raise 'expected a string or class'
18
20
  else ; input.class.name
19
- end.to_s.downcase
21
+ end.to_s.underscore
20
22
  end
21
23
 
22
24
  # Lazy initialized
@@ -0,0 +1,55 @@
1
+ module Effective
2
+ module Resources
3
+ module Instance
4
+ attr_reader :instance
5
+
6
+ # This is written for use by effective_logging and effective_trash
7
+
8
+ def instance_attributes
9
+ return {} unless instance.present?
10
+
11
+ attributes = { attributes: instance.attributes }
12
+
13
+ # Collect to_s representations of all belongs_to associations
14
+ belong_tos.each do |association|
15
+ attributes[association.name] = instance.send(association.name).to_s
16
+ end
17
+
18
+ has_ones.each do |association|
19
+ attributes[association.name] = instance.send(association.name).to_s
20
+ end
21
+
22
+ nested_resources.each do |association|
23
+ attributes[association.name] = {}
24
+
25
+ Array(instance.send(association.name)).each_with_index do |child, index|
26
+ resource = Effective::Resource.new(child)
27
+ attributes[association.name][index] = resource.instance_attributes
28
+ end
29
+ end
30
+
31
+ attributes.delete_if { |_, value| value.blank? }
32
+ end
33
+
34
+ def instance_changes
35
+ return {} unless instance.present?
36
+
37
+ changes = instance.changes
38
+
39
+ # Log to_s changes on all belongs_to associations
40
+ belong_tos.each do |association|
41
+ if (change = changes.delete(association.foreign_key)).present?
42
+ changes[association.name] = [(association.klass.find_by_id(change.first) if changes.first), instance.send(association.name)]
43
+ end
44
+ end
45
+
46
+ changes
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+
55
+
@@ -3,7 +3,11 @@ module Effective
3
3
  module Klass
4
4
 
5
5
  def klass
6
- namespaced_class_name.safe_constantize || class_name.safe_constantize || name.safe_constantize
6
+ @model_klass ||= (
7
+ namespaced_class_name.safe_constantize ||
8
+ class_name.safe_constantize ||
9
+ name.classify.safe_constantize
10
+ )
7
11
  end
8
12
 
9
13
  def datatable_klass
@@ -17,6 +21,14 @@ module Effective
17
21
  end
18
22
  end
19
23
 
24
+ def controller_klass
25
+ @controller_klass ||= (
26
+ "#{namespaced_class_name.pluralize}Controller".safe_constantize ||
27
+ "#{class_name.pluralize.classify}Controller".safe_constantize ||
28
+ "#{name.pluralize.classify}Controller".safe_constantize
29
+ )
30
+ end
31
+
20
32
  end
21
33
  end
22
34
  end
@@ -2,7 +2,7 @@ module EffectiveResources
2
2
  class Engine < ::Rails::Engine
3
3
  engine_name 'effective_resources'
4
4
 
5
- config.autoload_paths += Dir["#{config.root}/lib/"]
5
+ config.autoload_paths += Dir["#{config.root}/lib/", "#{config.root}/app/controllers/concerns/effective/"]
6
6
 
7
7
  # Set up our default configuration options.
8
8
  initializer 'effective_resources.defaults', before: :load_config_initializers do |app|
@@ -1,3 +1,3 @@
1
1
  module EffectiveResources
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.2.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-26 00:00:00.000000000 Z
11
+ date: 2017-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -33,6 +33,8 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - MIT-LICENSE
35
35
  - README.md
36
+ - app/assets/javascripts/effective_resources.js
37
+ - app/assets/javascripts/effective_resources/effective_ujs.js
36
38
  - app/controllers/concerns/effective/crud_controller.rb
37
39
  - app/helpers/effective_resources_helper.rb
38
40
  - app/models/effective/access_denied.rb
@@ -42,6 +44,7 @@ files:
42
44
  - app/models/effective/resources/associations.rb
43
45
  - app/models/effective/resources/attributes.rb
44
46
  - app/models/effective/resources/init.rb
47
+ - app/models/effective/resources/instance.rb
45
48
  - app/models/effective/resources/klass.rb
46
49
  - app/models/effective/resources/naming.rb
47
50
  - app/models/effective/resources/paths.rb