cookbook 0.1.2 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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