readymade 0.1.4 → 0.1.7

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: a730db0a4c2ccfefcb7c48a607ba75e691b8133ac8f6f7cdc6a67554bed180c3
4
- data.tar.gz: 84567afe201fd84977f5a56a46b68093c4bc7d814f4395d2cbb87325f268fa17
3
+ metadata.gz: 9d8b08e5bcf92035a49dbec37847653f0b99743c2f508c96e50b0aba312b3905
4
+ data.tar.gz: 2ec517133167b7ec909d9bf2e77c0fdb185774017f70f8871586ec0eb942925e
5
5
  SHA512:
6
- metadata.gz: 53c0991bce0adcfc2c9e2cbe8498936c90bcd01b197d3483027e04b594bb2ea9fbaf4b69cf7306312b4b2cb3784613f5facbde0d6ee46a6fba6b07fcab7b1814
7
- data.tar.gz: 6d280789685dc5bead01c40191668c58e56124108d9c2d5c81a9537b0ee147e4d2718d03460b2e4b512ee4b43ca98947781eff1f006746fb1108bac352294fb0
6
+ metadata.gz: c2388b93ffa8fd5bb5fe988546dab3383a70ec36296ca0efe6a34475c2e06514a43ff0b12c61986aaf50d6a03c529076c92d1b802647a310a12b44b966dc27d4
7
+ data.tar.gz: ec9b42d63e9ba52d2a27fa10ac2ccf572de6c287b14a1f0e9269c7554adb0f10deee2ad0a6fb62a05c5ac7db2854e96abb6ca554774b632bfaa4f037057822b0
data/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.1.6] - 2021-12-20
5
+
6
+ ### Features
7
+
8
+ * Add Readymade::Controller::Serialization
9
+
10
+ ## [0.1.5] - 2021-12-07
11
+
12
+ ### Improvements
13
+
14
+ * Better errors with Rails 6.1.
15
+
4
16
  ## [0.1.4] - 2021-11-22
5
17
 
6
18
  ### Features
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- readymade (0.1.4)
4
+ readymade (0.1.7)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Readymade
1
+ # Readymade 0.1.7
2
2
 
3
3
  This gems contains basic components to follow [ABDI architecture](https://github.com/OrestF/OrestF/blob/master/abdi/ABDI_architecture.md)
4
4
 
@@ -35,6 +35,41 @@ Inherit your components from:
35
35
 
36
36
  ```TODO: add```
37
37
 
38
+ #### #form_options
39
+
40
+ ```ruby
41
+ # app/forms/my_form.rb
42
+
43
+ class MyForm < Readymade::Form
44
+ PERMITTED_ATTRIBUTES = %i[email name category country]
45
+ REQUIRED_ATTRIBUTES = %i[email]
46
+
47
+ def form_options
48
+ {
49
+ categories: args[:company].categories,
50
+ countries: Country.all
51
+ }
52
+ end
53
+ end
54
+ ```
55
+
56
+ ```ruby
57
+ # app/controllers/items_controller.rb
58
+
59
+ def new
60
+ @form_options = MyForm.form_options(company: current_company)
61
+ end
62
+ ```
63
+
64
+ ```slim
65
+ / app/views/items/new.html.slim
66
+
67
+ = f.select :category, collection: @form_options[:categories]
68
+ = f.select :country, collection: @form_options[:countries]
69
+ = f.text_field :email, required: @form_options.required?(:email) # true
70
+ = f.text_field :name, required: @form_options.required?(:name) # false
71
+ ```
72
+
38
73
  ### Readymade::InstantForm
39
74
 
40
75
  Permit params and validates presence inline
@@ -60,7 +95,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
60
95
 
61
96
  ## Contributing
62
97
 
63
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/readymade. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/readymade/blob/master/CODE_OF_CONDUCT.md).
98
+ Bug reports and pull requests are welcome on GitHub at https://github.com/OrestF/readymade. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/readymade/blob/master/CODE_OF_CONDUCT.md).
64
99
 
65
100
 
66
101
  ## License
@@ -0,0 +1,70 @@
1
+ require 'active_support/concern'
2
+
3
+ module Readymade
4
+ module Controller
5
+ module Serialization
6
+ extend ActiveSupport::Concern
7
+
8
+ def record_response(record, *args)
9
+ options = args.extract_options!
10
+ return render_json({}, :not_found) if record.nil?
11
+
12
+ hash = serialize_record(record, options)
13
+
14
+ status = if record.errors.none?
15
+ options[:status] || :ok
16
+ else
17
+ hash[:errors] = record.errors.messages
18
+ :bad_request
19
+ end
20
+ render_json(hash, status)
21
+ end
22
+
23
+ def collection_response(collection, *args)
24
+ options = args.extract_options!
25
+
26
+ render_json(
27
+ {
28
+ items: serialize_collection(paginate(collection, options), options),
29
+ count: collection.count
30
+ },
31
+ options[:status] || :ok
32
+ )
33
+ end
34
+
35
+ def render_json(message, status)
36
+ render json: message, status: status
37
+ end
38
+
39
+ def serialize_collection(collection, options = {})
40
+ serializer = options.delete(:serializer) || "#{collection.klass.name}Serializer".constantize
41
+ serializer.render_as_hash(collection, options)
42
+ end
43
+
44
+ def serialize_record(record, options = {})
45
+ serializer = options.delete(:serializer) || "#{record.class.name}Serializer".constantize
46
+ serializer.render_as_hash(record, { root: :data }.merge!(options))
47
+ end
48
+
49
+ def operation_response(response_obj, options = {})
50
+ message, status = case response_obj.status.to_sym
51
+ when :success, :ok
52
+ [
53
+ if response_obj.data[:record].present?
54
+ serialize_record(response_obj.data[:record],
55
+ options)
56
+ else
57
+ {}
58
+ end,
59
+ :ok
60
+ ]
61
+ when :validation_fail, :bad_request
62
+ [{ errors: response_obj.data[:errors] }, :bad_request]
63
+ else
64
+ [response_obj.status.to_sym, {}]
65
+ end
66
+ render_json(message, status)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -31,6 +31,7 @@ module Readymade
31
31
  attr_accessor key
32
32
  end
33
33
  end
34
+
34
35
  # automatically validates all REQUIRED_ATTRIBUTES
35
36
  singleton_class.validates(*required_attributes, presence: true) if required_attributes.present?
36
37
 
@@ -52,8 +53,13 @@ module Readymade
52
53
  next if params[attr].blank?
53
54
 
54
55
  if form_class.is_a?(Array)
55
- n_forms = params[attr].map { |_i, attrs| form_class[0].new(attrs) }
56
-
56
+ n_forms = if params[attr].is_a?(Hash)
57
+ # { 0 => {id: 1, name: 'my name'}, 1 => { id: 2, name: 'other name' }}
58
+ params[attr].map { |_i, attrs| form_class[0].new(attrs) }
59
+ else
60
+ # [{id: 1, name: 'my name'}, { id: 2, name: 'other name' }]
61
+ params[attr].map { |attrs| form_class[0].new(attrs) }
62
+ end
57
63
  @nested_forms.push(*n_forms)
58
64
  define_singleton_method("#{attr}_forms") { n_forms }
59
65
  else
@@ -71,6 +77,7 @@ module Readymade
71
77
  nested_forms.compact.map(&:validate).all? || sync_nested_errors(nested_forms)
72
78
  end
73
79
 
80
+ # copy errors from nested forms into parent form
74
81
  def sync_nested_errors(nested_forms)
75
82
  nested_forms.each do |n_form|
76
83
  n_form.errors.each do |code, text|
@@ -81,14 +88,23 @@ module Readymade
81
88
  false
82
89
  end
83
90
 
91
+ # sync errors from form to record or vice-versa
84
92
  def sync_errors(from: self, to: record)
85
93
  return if [from, to].any?(&:blank?)
86
94
 
87
- errors = from.errors.instance_variable_get('@messages').to_h
88
- errors.merge!(to.errors.instance_variable_get('@messages').to_h)
95
+ if Rails.version.to_f > 6.0
96
+ from.errors.messages.each do |key, values|
97
+ Array.wrap(values).uniq.each do |uv|
98
+ to.errors.add(key, uv)
99
+ end
100
+ end
101
+ else
102
+ errors = from.errors.instance_variable_get('@messages').to_h
103
+ errors.merge!(to.errors.instance_variable_get('@messages').to_h)
89
104
 
90
- to.errors.instance_variable_set('@messages', errors)
91
- to.errors.messages.transform_values!(&:uniq) # Does not work with rails 6.1
105
+ to.errors.instance_variable_set('@messages', errors)
106
+ to.errors.messages.transform_values!(&:uniq) # Does not work with rails 6.1
107
+ end
92
108
  rescue FrozenError => _e
93
109
  end
94
110
 
@@ -128,5 +144,53 @@ module Readymade
128
144
  def nested_forms_mapping
129
145
  {}
130
146
  end
147
+
148
+ # EXAMPLE
149
+ # class Items::Forms::Create::Value < ::Readymade::Form
150
+ # PERMITTED_ATTRIBUTES = %i[attr1 attr2].freeze
151
+ # REQUIRED_ATTRIBUTES = %i[attr1].freeze
152
+ #
153
+ # class Value < ::Readymade::Form::Value
154
+ # def to_h
155
+ # {
156
+ # vat_percent: Item::VAT_OPTIONS,
157
+ # price_type: Item.price_types.keys,
158
+ # item_category: args[:company].item_categories
159
+ # }
160
+ # end
161
+ # end
162
+
163
+ # @form_options = Items::Forms::Create::Value.new(company: current_company)
164
+ # f.association :item_category, collection: @form_options[:item_category]
165
+
166
+ def self.form_options(**args)
167
+ Readymade::Form::FormOptions.new(**args.merge!(form_class: self))
168
+ end
169
+ class FormOptions
170
+ attr_reader :args
171
+
172
+ def initialize(**args)
173
+ @args = args
174
+ @f_class = args.delete(:form_class)
175
+ end
176
+
177
+ def [](key)
178
+ to_h[key]
179
+ end
180
+
181
+ def to_h
182
+ raise Readymade::Error.new('define form_options on your form') unless (f = @f_class.new({}, @args)).respond_to?(:form_options)
183
+
184
+ f.form_options
185
+ end
186
+
187
+ def as_json(options = {})
188
+ to_h.as_json(options)
189
+ end
190
+
191
+ def required?(attr)
192
+ @f_class::REQUIRED_ATTRIBUTES.include?(attr.to_sym)
193
+ end
194
+ end
131
195
  end
132
196
  end
@@ -2,6 +2,5 @@
2
2
 
3
3
  module Readymade
4
4
  class InstantForm < Form
5
-
6
5
  end
7
6
  end
@@ -26,7 +26,7 @@ module Readymade
26
26
  def record_valid?
27
27
  return true if record.errors.none? && record.valid?
28
28
 
29
- sync_errors_to_form && false
29
+ false
30
30
  end
31
31
 
32
32
  def save_record
@@ -43,6 +43,7 @@ module Readymade
43
43
 
44
44
  def validation_fail(status = :validation_fail, args = {})
45
45
  sync_errors_to_form
46
+
46
47
  response(status, args.merge!(record: record,
47
48
  record_params: record_params,
48
49
  form: form,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Readymade
4
- VERSION = '0.1.4'
4
+ VERSION = '0.1.7'
5
5
  end
data/lib/readymade.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'readymade/controller/serialization'
3
4
  require 'readymade/action'
4
5
  require 'readymade/form'
5
6
  require 'readymade/instant_form'
data/readymade.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
26
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
27
  end
28
+ spec.files << 'lib/readymade/controller/serialization.rb'
28
29
  spec.bindir = 'exe'
29
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
31
  spec.require_paths = ['lib']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readymade
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - OrestF
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2022-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -73,6 +73,7 @@ files:
73
73
  - bin/setup
74
74
  - lib/readymade.rb
75
75
  - lib/readymade/action.rb
76
+ - lib/readymade/controller/serialization.rb
76
77
  - lib/readymade/form.rb
77
78
  - lib/readymade/instant_form.rb
78
79
  - lib/readymade/operation.rb