cookbook 0.1.2 → 0.1.6

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
  SHA256:
3
- metadata.gz: 3e5ddf2c7e8f42e08fdfe0efa01b04db1692f1a3b7bcaf22bb5b280894b517e6
4
- data.tar.gz: 714e544111f74044a07b4a8185937a00ac334f06e886140c0dbe7fca361f014c
3
+ metadata.gz: 2959709e5e50fec64984caac992b47de183442c12ce5388b37d476434e1155dc
4
+ data.tar.gz: 0b8861cf190ec4da06ac43dc6dee23ccc360c2251a427e4a7fcfc9369b32283f
5
5
  SHA512:
6
- metadata.gz: c8bda17026410a17d057aa27d74a275976848a6be03e85bf34d6edc86e900ca360ad24ba36515f3f6b23e5cbfc4e715c4a6682bd339793c7a28d4a7b650a082c
7
- data.tar.gz: f486ba4c50eb39296f6518e5804ebbc6d86f20e5b86eeae42b8c644e5181ce2166b4d2bb991bc17b0d9067fb96edff07dcdb94364bb4740675fc948dd9fb3b28
6
+ metadata.gz: dc961bc7d3a9396de7265eeb271b17ff4c500b6c4c40f5187bfa721702017c7fdf0c70ca453951d792cf5fbf1ea1ada3753548bfedce74e517331be5cb8d13be
7
+ data.tar.gz: 41ceed87fb03aa183e10f4e1ddab2e2de7e147343d7af48a0dc225dcfd38878aca4ecc727e223986ed6aa146a8469c799f61745c2d938c9c1c9c7099bba64a62
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ source 'https://rubygems.org'
5
5
  gem 'rails', '>= 6', '< 7'
6
6
 
7
7
  gem 'haml-rails', '>= 2.0', '< 3'
8
- gem 'sass-rails', '>= 6', '< 7'
8
+ gem 'sass-rails', '>= 5', '< 7'
9
9
 
10
10
  gem 'cancancan', '>= 3.3', '< 4'
11
11
 
data/Gemfile.lock CHANGED
@@ -155,18 +155,6 @@ GEM
155
155
  rdoc
156
156
  semver
157
157
  jwt (2.2.3)
158
- kaminari (1.2.1)
159
- activesupport (>= 4.1.0)
160
- kaminari-actionview (= 1.2.1)
161
- kaminari-activerecord (= 1.2.1)
162
- kaminari-core (= 1.2.1)
163
- kaminari-actionview (1.2.1)
164
- actionview
165
- kaminari-core (= 1.2.1)
166
- kaminari-activerecord (1.2.1)
167
- activerecord
168
- kaminari-core (= 1.2.1)
169
- kaminari-core (1.2.1)
170
158
  loofah (2.12.0)
171
159
  crass (~> 1.0.2)
172
160
  nokogiri (>= 1.5.9)
@@ -347,7 +335,6 @@ DEPENDENCIES
347
335
  faker
348
336
  haml-rails (>= 2.0, < 3)
349
337
  juwelier (~> 2.1.0)
350
- kaminari (>= 1.2.1, < 2)
351
338
  puma (>= 4.3, < 5)
352
339
  rails (>= 6, < 7)
353
340
  rspec-html-matchers
@@ -355,7 +342,7 @@ DEPENDENCIES
355
342
  rubocop
356
343
  rubocop-rails
357
344
  rubocop-rspec
358
- sass-rails (>= 6, < 7)
345
+ sass-rails (>= 5, < 7)
359
346
  shoulda
360
347
  shoulda-matchers (>= 4.3, < 5)
361
348
  simple_form (>= 5.1, < 6)
data/README.md CHANGED
@@ -3,8 +3,6 @@ Works Cited allows you to add a list of the works cited in ActiveRecord objects,
3
3
 
4
4
  Works Cited can be configured to use CanCanCan to authorize the editing of citations. This makes it easy for you to control access.
5
5
 
6
- Works Cited does not require, but is compatible with Rails Admin.
7
-
8
6
  ## Installation
9
7
  Add this line to your application's Gemfile:
10
8
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.6
@@ -0,0 +1,41 @@
1
+ class addFields {
2
+ // This executes when the function is instantiated.
3
+ constructor() {
4
+ this.links = document.querySelectorAll('.add_fields')
5
+ this.iterateLinks()
6
+ }
7
+
8
+ iterateLinks() {
9
+ // If there are no links on the page, stop the function from executing.
10
+ if (this.links.length === 0) return
11
+ // Loop over each link on the page. A page could have multiple nested forms.
12
+ this.links.forEach(link => {
13
+ link.addEventListener('click', e => {
14
+ this.handleClick(link, e)
15
+ })
16
+ })
17
+ }
18
+
19
+ handleClick(link, e) {
20
+ // Stop the function from executing if a link or event were not passed into the function.
21
+ if (!link || !e) return
22
+ // Prevent the browser from following the URL.
23
+ e.preventDefault()
24
+ // Save a unique timestamp to ensure the key of the associated array is unique.
25
+ let time = new Date().getTime()
26
+ // Save the data id attribute into a variable. This corresponds to `new_object.object_id`.
27
+ let linkId = link.dataset.id
28
+ // Create a new regular expression needed to find any instance of the `new_object.object_id` used in the fields data attribute if there's a value in `linkId`.
29
+ let regexp = linkId ? new RegExp(linkId, 'g') : null
30
+ // Replace all instances of the `new_object.object_id` with `time`, and save markup into a variable if there's a value in `regexp`.
31
+ let newFields = regexp ? link.dataset.fields.replace(regexp, time) : null
32
+ // Add the new markup to the form if there are fields to add.
33
+ newFields ? link.insertAdjacentHTML('beforebegin', newFields) : null
34
+ // Tell it new fields are there
35
+ const event = new Event('cookbook:add_fields')
36
+ window.dispatchEvent(event);
37
+ }
38
+ }
39
+
40
+ // Wait for turbolinks to load, otherwise `document.querySelectorAll()` won't work
41
+ window.addEventListener('load', () => new addFields())
@@ -0,0 +1,2 @@
1
+ //= require cookbook/addFields
2
+ //= require cookbook/removeFields
@@ -0,0 +1,36 @@
1
+ class removeFields {
2
+ // This executes when the function is instantiated.
3
+ constructor() {
4
+ this.iterateLinks()
5
+ }
6
+
7
+ iterateLinks() {
8
+ document.querySelectorAll('.remove_fields').forEach(link => {
9
+ link.addEventListener('click', e => {
10
+ this.handleClick(link, e)
11
+ })
12
+ })
13
+ }
14
+
15
+ handleClick(link, e) {
16
+ // Stop the function from executing if a link or event were not passed into the function.
17
+ if (!link || !e) return
18
+ // Prevent the browser from following the URL.
19
+ e.preventDefault()
20
+ // Find the parent wrapper for the set of nested fields.
21
+ let fieldParent = link.closest('.nested-fields')
22
+ // If there is a parent wrapper, find the hidden delete field.
23
+ let deleteField = fieldParent
24
+ ? fieldParent.querySelector('input[type="hidden"]')
25
+ : null
26
+ // If there is a delete field, update the value to `1` and hide the corresponding nested fields.
27
+ if (deleteField) {
28
+ deleteField.value = 1
29
+ fieldParent.style.display = 'none'
30
+ }
31
+ }
32
+ }
33
+
34
+ // Wait for turbolinks to load, otherwise `document.querySelectorAll()` won't work
35
+ window.addEventListener('load', () => new removeFields())
36
+ window.addEventListener('cookbook:add_fields', () => new removeFields())
@@ -15,6 +15,45 @@ module Cookbook
15
15
  render 'cookbook/fields', form: form, usables: build_usables(form.object)
16
16
  end
17
17
 
18
+ # This method creates a link with `data-id` `data-fields` attributes. These attributes are used to create new instances of the nested fields through Javascript.
19
+ def cookbook_link_to_add_fields(name, f, association, partial = nil)
20
+
21
+ # Takes an object (@person) and creates a new instance of its associated model (:addresses)
22
+ # To better understand, run the following in your terminal:
23
+ # rails c --sandbox
24
+ # @person = Person.new
25
+ # new_object = @person.send(:addresses).klass.new
26
+ new_object = f.object.send(association).klass.new
27
+
28
+ # Saves the unique ID of the object into a variable.
29
+ # This is needed to ensure the key of the associated array is unique. This is makes parsing the content in the `data-fields` attribute easier through Javascript.
30
+ # We could use another method to achive this.
31
+ id = new_object.object_id
32
+
33
+ # https://api.rubyonrails.org/ fields_for(record_name, record_object = nil, fields_options = {}, &block)
34
+ # record_name = :addresses
35
+ # record_object = new_object
36
+ # fields_options = { child_index: id }
37
+ # child_index` is used to ensure the key of the associated array is unique, and that it matched the value in the `data-id` attribute.
38
+ # `person[addresses_attributes][child_index_value][_destroy]`
39
+ fields = f.fields_for(association, new_object, child_index: id) do |builder|
40
+
41
+ # `association.to_s.singularize + "_fields"` ends up evaluating to `address_fields`
42
+ # The render function will then look for `views/people/_address_fields.html.erb`
43
+ # The render function also needs to be passed the value of 'builder', because `views/people/_address_fields.html.erb` needs this to render the form tags.
44
+ partial.nil? ? render(association.to_s.singularize + "_fields", f: builder) : render(partial, f: builder)
45
+ end
46
+
47
+ # This renders a simple link, but passes information into `data` attributes.
48
+ # This info can be named anything we want, but in this case we chose `data-id:` and `data-fields:`.
49
+ # The `id:` is from `new_object.object_id`.
50
+ # The `fields:` are rendered from the `fields` blocks.
51
+ # We use `gsub("\n", "")` to remove anywhite space from the rendered partial.
52
+ # The `id:` value needs to match the value used in `child_index: id`.
53
+ link_to(name, '#', class: "add_fields button button-action", data: {id: id, fields: fields.gsub("\n", "")})
54
+
55
+ end
56
+
18
57
  private
19
58
 
20
59
  def build_usables(object)
@@ -1,11 +1,28 @@
1
1
  # frozen_string_literal: true
2
+ require 'pp'
2
3
 
3
4
  module Cookbook
4
5
  # Cookbook::Use is basically a linking table with extra information.
5
6
  class Use < ApplicationRecord
7
+ attr_accessor(:used_in_tables)
8
+
6
9
  # Relationships
7
- belongs_to :use_in, polymorphic: true
8
- belongs_to :use_of, polymorphic: true
10
+ belongs_to :use_in, polymorphic: true, inverse_of: :uses
11
+ belongs_to :use_of, polymorphic: true, inverse_of: :uses
12
+
13
+ class << self
14
+ def add_use_of(table_sym)
15
+ singular = table_sym.to_s.singularize
16
+ model_name = singular.classify.constantize.to_s
17
+ belongs_to singular.to_sym, class_name: model_name, foreign_key: :use_of_id, inverse_of: :uses, optional: true
18
+ end
19
+
20
+ def add_use_in(table_sym)
21
+ singular = table_sym.to_s.singularize
22
+ model_name = singular.classify.constantize.to_s
23
+ belongs_to singular.to_sym, class_name: model_name, foreign_key: :use_in_id, inverse_of: :uses, optional: true
24
+ end
25
+ end
9
26
 
10
27
  # Methods
11
28
  def object_label
@@ -32,9 +49,6 @@ module Cookbook
32
49
  object_label_method { :object_label }
33
50
  edit do
34
51
  include_all_fields
35
- field :use_in do
36
- visible false
37
- end
38
52
  end
39
53
  end
40
54
  end
@@ -1,11 +1,11 @@
1
- = javascript_include_tag 'vanilla_nested'
1
+ = javascript_include_tag 'cookbook/application'
2
2
  - if Cookbook.configuration.include_cookbook_css == true
3
3
  = stylesheet_link_tag 'cookbook/application'
4
4
  - usables.each do |usable|
5
5
  %fieldset.used_in{class: usable.plural_class}
6
6
  %legend
7
7
  %h3= usable.title
8
- = link_to_add_nested form, usable.uses_sym, "##{usable.plural_class}", partial: 'cookbook/uses/fields', link_text: "Add #{usable.singular_title}", link_classes: 'button button-action'
9
8
  %div{id: usable.plural_class}
10
9
  = form.fields_for usable.uses_sym do |g|
11
- = render 'cookbook/uses/fields', form: g, usable: usable
10
+ = render 'cookbook/use_fields', f: g, usable: usable
11
+ = cookbook_link_to_add_fields "Add #{usable.singular_title}", form, usable.uses_sym, 'cookbook/use_fields'
@@ -0,0 +1,22 @@
1
+ %fieldset.nested-fields
2
+ :ruby
3
+ table_sym = f.object_name.gsub(/[^\[]+\[([^\]]+)_uses_attributes\].*/, "\\1").pluralize
4
+ model = table_sym.to_s.classify.constantize
5
+ collection = if Cookbook.configuration.authorize_with == :cancancan
6
+ model.accessible_by(current_ability, :select)
7
+ else
8
+ model.all
9
+ end
10
+ %legend
11
+ %h4
12
+ = model.model_name.human
13
+ = f.hidden_field :_destroy
14
+ = f.hidden_field :use_of_type, value: model.model_name.to_s
15
+ = f.input :use_of_id, collection: collection, as: :select, label_method: model.label_method, value_method: :id, selected: f.object.use_of_id, include_blank: "Select #{model.model_name.human}"
16
+ = f.input :quantity_minimum
17
+ = f.input :quantity_maximum
18
+ = f.input :unit
19
+ = f.input :sort
20
+ = f.input :preparation, hint: 'like "crushed" or "greased"'
21
+ = f.input :note, hint: 'like "to taste"'
22
+ = link_to "Remove", '#', class: 'remove_fields button button-danger'
data/cookbook.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: cookbook 0.1.2 ruby lib
5
+ # stub: cookbook 0.1.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "cookbook".freeze
9
- s.version = "0.1.2"
9
+ s.version = "0.1.6"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.metadata = { "source_code_uri" => "http://github.com/gemvein/cookbook" } if s.respond_to? :metadata=
13
13
  s.require_paths = ["lib".freeze]
14
14
  s.authors = ["Loren Lundgren".freeze]
15
- s.date = "2021-09-13"
15
+ s.date = "2021-09-21"
16
16
  s.description = "Cookbook allows you to associate instructions with components in a cross referenced way. Good for cooking recipes or an instruction manual for DIY projects.".freeze
17
17
  s.email = "loren.lundgren@gmail.com".freeze
18
18
  s.executables = ["rails".freeze]
@@ -30,14 +30,17 @@ Gem::Specification.new do |s|
30
30
  "README.md",
31
31
  "Rakefile",
32
32
  "VERSION",
33
+ "app/assets/javascript/cookbook/addFields.js",
34
+ "app/assets/javascript/cookbook/application.js",
35
+ "app/assets/javascript/cookbook/removeFields.js",
33
36
  "app/assets/stylesheets/cookbook/application.scss",
34
37
  "app/controllers/concerns/cookbook/params.rb",
35
38
  "app/helpers/cookbook/application_helper.rb",
36
39
  "app/models/cookbook/use.rb",
37
40
  "app/views/cookbook/_fields.html.haml",
41
+ "app/views/cookbook/_use_fields.html.haml",
38
42
  "app/views/cookbook/_used_in.html.haml",
39
43
  "app/views/cookbook/_uses_of.html.haml",
40
- "app/views/cookbook/uses/_fields.html.haml",
41
44
  "bin/rails",
42
45
  "config/initializers/simple_form.rb",
43
46
  "config/locales/simple_form.en.yml",
@@ -192,7 +195,7 @@ Gem::Specification.new do |s|
192
195
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
193
196
  s.add_runtime_dependency(%q<rails>.freeze, [">= 6", "< 7"])
194
197
  s.add_runtime_dependency(%q<haml-rails>.freeze, [">= 2.0", "< 3"])
195
- s.add_runtime_dependency(%q<sass-rails>.freeze, [">= 6", "< 7"])
198
+ s.add_runtime_dependency(%q<sass-rails>.freeze, [">= 5", "< 7"])
196
199
  s.add_runtime_dependency(%q<cancancan>.freeze, [">= 3.3", "< 4"])
197
200
  s.add_runtime_dependency(%q<simple_form>.freeze, [">= 5.1", "< 6"])
198
201
  s.add_runtime_dependency(%q<vanilla_nested>.freeze, [">= 1.3", "< 2"])
@@ -210,7 +213,7 @@ Gem::Specification.new do |s|
210
213
  else
211
214
  s.add_dependency(%q<rails>.freeze, [">= 6", "< 7"])
212
215
  s.add_dependency(%q<haml-rails>.freeze, [">= 2.0", "< 3"])
213
- s.add_dependency(%q<sass-rails>.freeze, [">= 6", "< 7"])
216
+ s.add_dependency(%q<sass-rails>.freeze, [">= 5", "< 7"])
214
217
  s.add_dependency(%q<cancancan>.freeze, [">= 3.3", "< 4"])
215
218
  s.add_dependency(%q<simple_form>.freeze, [">= 5.1", "< 6"])
216
219
  s.add_dependency(%q<vanilla_nested>.freeze, [">= 1.3", "< 2"])
@@ -229,7 +232,7 @@ Gem::Specification.new do |s|
229
232
  else
230
233
  s.add_dependency(%q<rails>.freeze, [">= 6", "< 7"])
231
234
  s.add_dependency(%q<haml-rails>.freeze, [">= 2.0", "< 3"])
232
- s.add_dependency(%q<sass-rails>.freeze, [">= 6", "< 7"])
235
+ s.add_dependency(%q<sass-rails>.freeze, [">= 5", "< 7"])
233
236
  s.add_dependency(%q<cancancan>.freeze, [">= 3.3", "< 4"])
234
237
  s.add_dependency(%q<simple_form>.freeze, [">= 5.1", "< 6"])
235
238
  s.add_dependency(%q<vanilla_nested>.freeze, [">= 1.3", "< 2"])
@@ -11,10 +11,28 @@ module Cookbook
11
11
  include InstanceMethods
12
12
 
13
13
  self.used_in = model_symbols
14
+ Cookbook::Use.add_use_in(table_name.to_sym)
14
15
 
15
16
  # Relationships
16
- has_many :uses, as: :use_in, class_name: 'Cookbook::Use'
17
+ has_many :uses, as: :use_in, class_name: 'Cookbook::Use', inverse_of: :use_in
18
+ # Used only as a setter, not a getter
19
+ accepts_nested_attributes_for :uses, reject_if: :all_blank, allow_destroy: true
17
20
  associate_used_in
21
+
22
+ used_in.each do |table_sym|
23
+ singular = table_sym.to_s.singularize
24
+ model = singular.classify.constantize
25
+ equals_method_symbol = "#{singular}_uses_attributes=".to_sym
26
+ define_method(equals_method_symbol) do |values|
27
+ items = []
28
+ values.each_pair do |key, value|
29
+ value['use_in'] = self
30
+ value['use_of'] = model.find_by(id: value['use_of_id'])
31
+ items << value
32
+ end
33
+ self.uses_attributes = items
34
+ end
35
+ end
18
36
  end
19
37
 
20
38
  # Extended by has_cookbook mixin
@@ -27,20 +45,31 @@ module Cookbook
27
45
  model = table_sym.to_s.classify.constantize
28
46
  name = model.model_name.to_s
29
47
  uses_symbol = "#{model.model_name.param_key}_uses".to_sym
48
+ singular_symbol = table_sym.to_s.singularize.to_sym
30
49
 
31
50
  has_many uses_symbol, lambda {
32
51
  where(use_of_type: name)
33
- }, as: :use_in, class_name: 'Cookbook::Use'
52
+ }, as: :use_in, class_name: 'Cookbook::Use', inverse_of: singular_symbol
53
+
54
+ # Used only as a getter, not a setter
34
55
  accepts_nested_attributes_for uses_symbol, reject_if: :all_blank, allow_destroy: true
35
56
 
36
- has_many table_sym, through: :uses, source: :use_of, source_type: name
57
+ has_many table_sym, through: uses_symbol, source: :use_of, source_type: name
37
58
 
38
59
  if defined?(RailsAdmin)
39
60
  rails_admin do
61
+ include_all_fields
40
62
  field :uses do
41
63
  visible false
42
64
  end
43
65
  tables.each do |table_sym|
66
+ singular = table_sym.to_s.singularize
67
+ uses_symbol = "#{singular}_uses".to_sym
68
+ field uses_symbol do # Show only on reload
69
+ visible do
70
+ !bindings[:object].new_record?
71
+ end
72
+ end
44
73
  field table_sym do # We don't want these associations to show
45
74
  visible false
46
75
  end
@@ -10,20 +10,38 @@ module Cookbook
10
10
  extend ClassMethods
11
11
  include InstanceMethods
12
12
 
13
- self.uses_of = model_symbols
13
+ self.use_of = model_symbols
14
14
  self.label_method = :name
15
+ Cookbook::Use.add_use_of(table_name.to_sym)
15
16
 
16
17
  # Relationships
17
- has_many :uses, as: :use_of, class_name: 'Cookbook::Use'
18
+ has_many :uses, as: :use_of, class_name: 'Cookbook::Use', inverse_of: :use_of
18
19
  associate_uses_of
20
+
21
+ if defined?(RailsAdmin)
22
+ rails_admin do
23
+ field :uses do
24
+ visible false
25
+ end
26
+ self.use_of.each do |table_sym| # We don't want these associations to show
27
+ table_uses_sym = "#{table_sym.to_s.singularize}_uses".to_sym
28
+ field table_uses_sym do
29
+ visible false
30
+ end
31
+ field table_sym do
32
+ visible false
33
+ end
34
+ end
35
+ end
36
+ end
19
37
  end
20
38
 
21
39
  # Extended by acts_as_used_in mixin
22
40
  module ClassMethods
23
- attr_accessor :uses_of, :label_method
41
+ attr_accessor :label_method, :use_of
24
42
 
25
43
  def associate_uses_of
26
- uses_of.each do |table_sym|
44
+ self.use_of.each do |table_sym|
27
45
  model = table_sym.to_s.classify.constantize
28
46
  name = model.model_name.to_s
29
47
 
data/lib/cookbook.rb CHANGED
@@ -19,7 +19,6 @@ module Cookbook
19
19
  require 'haml-rails'
20
20
  require 'sass-rails'
21
21
  require 'simple_form'
22
- require 'vanilla_nested'
23
22
  require 'cancancan' if Cookbook.configuration.authorize_with == :cancancan
24
23
  end
25
24
 
@@ -13,4 +13,5 @@
13
13
  //= require rails-ujs
14
14
  //= require activestorage
15
15
  //= require cookbook
16
+ //= require ../../../../../app/assets/javascripts/cookbook
16
17
  //= require_tree .
Binary file
Binary file