application_form 0.4.0 → 0.5.3

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: 05c6c488f4f25253c2fb3889eda3776207218a8a1bfb7101b18e9fc38fc5e663
4
- data.tar.gz: e8c073b39558f58391202b6d7353cc4be57e7c4df01987f31b1b624012fd010f
3
+ metadata.gz: b81f5d6a05cf8fcfabc3714481407e04d5ee752c6dced927000764de369b7172
4
+ data.tar.gz: e72b208fadad3073246fd8feb0819af6efefa87738930d7cab21e65913da423f
5
5
  SHA512:
6
- metadata.gz: e174c55c53544fd420808519c705f546fe166a44965c279a09ac25ccbd52c47e09329c06031aa3f1e143987400678322f870fa5736717f68c7397f7579097b86
7
- data.tar.gz: d1f64700776c503711dc40a6ee4530963058cac534bfd49473a5567c01b2bda117b375f223eeedb434196ee3fb2275ca35db7ad6c165f7ee3da14138383f6552
6
+ metadata.gz: 0cff5090a0feb65b5d2f243262f8679b47478a3407e8a957690f7d182ff45ecbe71292be1fd7d27af0558cb8a79182dd938c161697f1002095f5d3dbd99263ae
7
+ data.tar.gz: 290f830403a64539fc3f0bf7c9119ae3c0c9aca4627d4aa2bb363179064f2330d61de204a9feaf7071fca1b3e7f980fc32dfb01ed3423cfb4b70de271c56e2d5
data/Makefile CHANGED
@@ -16,4 +16,7 @@ release:
16
16
  build:
17
17
  bundle exec rake build
18
18
 
19
+ push:
20
+ git push origin master
21
+
19
22
  .PHONY: test
data/README.md CHANGED
@@ -41,7 +41,7 @@ or with namespace model
41
41
 
42
42
  $ rails g application_form:form admin_post --model=blog/post
43
43
 
44
- ### Example
44
+ ### Basic usage
45
45
 
46
46
  ```ruby
47
47
  # app/forms/user_sign_up_form.rb
@@ -66,13 +66,63 @@ class UserSignUpForm < User
66
66
  end
67
67
  ```
68
68
 
69
- In some cases it is necessary to use ActiveRecord object directly without form. For such cases conveniently to use method `become()` (built-in ActiveRecord):
69
+ ```
70
+ form = UserSignUpForm.new(user_params)
71
+ form.valid?
72
+ ```
73
+
74
+ ### Usage with `becomes`
75
+
76
+ In some cases it is necessary to use ActiveRecord object directly without form. For such cases conveniently to use method `becomes()` (built-in ActiveRecord):
70
77
 
71
78
  ```ruby
72
79
  user = User.find(params[:id])
73
80
  form = user.becomes(UserSignUpForm)
74
81
  ```
75
82
 
83
+ ### Checks
84
+
85
+ Checks are build on top of Rails validations. They are semantically separated from validations, because we treat them as business logic checks, not as data validation.
86
+
87
+ ```ruby
88
+ class ReservationCreateForm < Reservation
89
+ include ApplicationForm
90
+
91
+ permit :user_id, :vehicle_id, :start_at, :end_at, :pickup_location_id, :return_location_id
92
+
93
+ check :max_number_of_reservations_reached, ->(form) { !form.user&.reservations_limit_reached? }
94
+ check :car_is_on_maintenance, ->(form) { form.vehicle&.reservable? }
95
+ end
96
+
97
+ # In controller:
98
+ form = ReservationCreateForm.new(prepared_params)
99
+
100
+ if form.checks_passed?
101
+ # ...
102
+ else
103
+ render_error!(form.first_failed_check) # form.first_failed_check returns "reservation.error.max_number_of_reservations_reached"
104
+ end
105
+ ```
106
+
107
+ You can also assign check to a specific field:
108
+
109
+ ```ruby
110
+ check :end_at_must_be_greater_then_start_at, ->(form) { form.end_at > form.start_at }, :end_at
111
+ ```
112
+
113
+ In this case it will work as a regular validation.
114
+
115
+ ### `assign_attrs`
116
+
117
+ It works as regular `assign_attributes` but it also returns the object, so that you can chain it:
118
+
119
+ ```ruby
120
+ form = current_user.becomes(UserApplyReferralProgramForm)
121
+ .assign_attrs(registration_referral_code: referral_code)
122
+ ```
123
+
124
+ It is a usual pattern when you use for in `#update` action.
125
+
76
126
  ## Development
77
127
 
78
128
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -24,9 +24,8 @@ module ApplicationForm
24
24
  module ClassMethods
25
25
  delegate :sti_name, to: :superclass
26
26
  delegate :human_attribute_name, to: :superclass
27
- # NOTE: too many side effects if it is enabled
28
- # examples: form names, translations
29
- # delegate :name, to: :superclass
27
+ # NOTE: Controvertial thing. More details: https://github.com/Hexlet/active_form_model/issues/10
28
+ delegate :name, to: :superclass
30
29
 
31
30
  def permit(*args)
32
31
  @_permitted_args = args
@@ -35,6 +34,16 @@ module ApplicationForm
35
34
  def _permitted_args
36
35
  @_permitted_args || (superclass.respond_to?(:_permitted_args) && superclass._permitted_args) || []
37
36
  end
37
+
38
+ def check(key, block, field = :base)
39
+ validate do |form|
40
+ if !block.call(form)
41
+ entity_name = self.class.superclass.to_s.tableize.split('/').last.singularize
42
+ full_key = "#{entity_name}.errors.#{key}"
43
+ form.add_error_key(field, full_key)
44
+ end
45
+ end
46
+ end
38
47
  end
39
48
 
40
49
  def update(attrs = {})
@@ -55,4 +64,22 @@ module ApplicationForm
55
64
  def permit_attrs(attrs)
56
65
  attrs.respond_to?(:permit) ? attrs.send(:permit, self.class._permitted_args) : attrs
57
66
  end
67
+
68
+ def first_error_message
69
+ errors&.full_messages&.first
70
+ end
71
+
72
+ def checks_passed?
73
+ valid?
74
+ end
75
+
76
+ def first_failed_check
77
+ errors.details[:base].first[:error].to_s
78
+ end
79
+
80
+ def assign_attrs(attrsibutes)
81
+ attrs = ActiveSupport::HashWithIndifferentAccess.new(attributes)
82
+ assign_attributes(attrs)
83
+ self
84
+ end
58
85
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ApplicationForm
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: application_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kirill Mokevnin