avocado 0.5.0 → 0.7.0

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -14
  3. data/README.md +8 -43
  4. data/Rakefile +0 -2
  5. data/app/controllers/avocado/affirmations_controller.rb +21 -18
  6. data/app/controllers/avocado/base_controller.rb +26 -5
  7. data/app/controllers/avocado/credentials_controller.rb +41 -0
  8. data/app/controllers/avocado/emails_controller.rb +9 -17
  9. data/app/controllers/avocado/events_controller.rb +3 -3
  10. data/app/controllers/avocado/passwords_controller.rb +8 -8
  11. data/app/controllers/avocado/recoveries_controller.rb +8 -41
  12. data/app/controllers/avocado/registrations_controller.rb +7 -14
  13. data/app/controllers/avocado/sessions_controller.rb +21 -13
  14. data/app/controllers/avocado/verifications_controller.rb +14 -15
  15. data/app/views/avocado/affirmations/_form.html.erb +4 -0
  16. data/app/views/avocado/affirmations/edit.html.erb +7 -0
  17. data/app/views/avocado/affirmations/new.html.erb +2 -4
  18. data/app/views/avocado/{recoveries/edit.html.erb → credentials/_form.html.erb} +4 -13
  19. data/app/views/avocado/credentials/edit.html.erb +12 -0
  20. data/app/views/avocado/emails/_form.html.erb +8 -0
  21. data/app/views/avocado/emails/edit.html.erb +1 -6
  22. data/app/views/avocado/mailer/email_affirmation.text.erb +1 -1
  23. data/app/views/avocado/mailer/email_verification.text.erb +1 -1
  24. data/app/views/avocado/mailer/password_reset.text.erb +1 -1
  25. data/app/views/avocado/passwords/_form.html.erb +12 -0
  26. data/app/views/avocado/passwords/edit.html.erb +1 -9
  27. data/app/views/avocado/recoveries/_form.html.erb +4 -0
  28. data/app/views/avocado/recoveries/new.html.erb +2 -4
  29. data/app/views/avocado/registrations/_form.html.erb +12 -0
  30. data/app/views/avocado/registrations/new.html.erb +1 -12
  31. data/app/views/avocado/sessions/_form.html.erb +8 -0
  32. data/app/views/avocado/sessions/new.html.erb +1 -4
  33. data/app/views/avocado/verifications/edit.html.erb +7 -0
  34. data/config/locales/en.yml +45 -0
  35. data/config/routes/avocado.rb +11 -0
  36. data/config.ru +0 -2
  37. data/docs/USAGE.md +164 -0
  38. data/lib/avocado/authentication.rb +2 -4
  39. data/lib/avocado/current.rb +0 -2
  40. data/lib/avocado/engine.rb +5 -2
  41. data/lib/avocado/event.rb +0 -2
  42. data/lib/avocado/mailer.rb +0 -2
  43. data/lib/avocado/session.rb +6 -2
  44. data/lib/avocado/session_callbacks.rb +0 -2
  45. data/lib/avocado/user.rb +0 -2
  46. data/lib/avocado/user_callbacks.rb +0 -2
  47. data/lib/avocado/user_tokens.rb +0 -2
  48. data/lib/avocado/user_validations.rb +0 -2
  49. data/lib/avocado/version.rb +1 -3
  50. data/lib/avocado.rb +1 -2
  51. data/lib/generators/avocado/migrations/migrations_generator.rb +34 -0
  52. data/lib/generators/avocado/migrations/templates/create_events.rb.tt +12 -0
  53. data/lib/generators/avocado/migrations/templates/create_sessions.rb.tt +12 -0
  54. data/lib/generators/avocado/migrations/templates/create_users.rb.tt +11 -0
  55. data/lib/generators/avocado/views/views_generator.rb +21 -0
  56. metadata +27 -38
  57. data/config/routes.rb +0 -12
@@ -1,20 +1,23 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  class VerificationsController < BaseController
5
- with_options only: :show do
3
+ with_options only: %i[edit update] do
6
4
  skip_before_action :authenticate
7
5
  before_action :set_user
8
6
  end
9
7
 
10
- def show
8
+ def edit
9
+ end
10
+
11
+ def update
11
12
  @user.update! verified: true
12
- redirect_to root_path, notice: "Email address verified."
13
+ redirect_to root_path,
14
+ notice: t(".success")
13
15
  end
14
16
 
15
17
  def create
16
- send_email_verification
17
- redirect_to root_path, notice: "Verification email sent to your address."
18
+ send_email_verification(current_user)
19
+ redirect_to root_path,
20
+ notice: t(".success")
18
21
  end
19
22
 
20
23
  private
@@ -22,17 +25,13 @@ module Avocado
22
25
  def set_user
23
26
  @user = user_from_signed_email_verification_token
24
27
  rescue ActiveSupport::MessageVerifier::InvalidSignature
25
- redirect_to root_path, alert: "Email verification link is invalid."
28
+ redirect_to root_path,
29
+ alert: t(".errors.invalid_token")
26
30
  end
27
31
 
28
32
  def user_from_signed_email_verification_token
29
- ::User.find_by_token_for!(:email_verification, params[:id])
30
- end
31
-
32
- def send_email_verification
33
- mailer_for(current_user)
34
- .email_verification
35
- .deliver_later
33
+ ::User
34
+ .find_by_token_for!(:email_verification, params[:id])
36
35
  end
37
36
  end
38
37
  end
@@ -0,0 +1,4 @@
1
+ <div>
2
+ <%= form.label :email %>
3
+ <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
4
+ </div>
@@ -0,0 +1,7 @@
1
+ <h2>
2
+ Sign in without password
3
+ </h2>
4
+
5
+ <%= form_with url: affirmation_path(id: params[:id]), method: :patch do |form| %>
6
+ <%= form.button "Submit", name: nil %>
7
+ <% end -%>
@@ -6,9 +6,7 @@
6
6
  <%= link_to "Reset your password", new_recovery_path %>
7
7
  </p>
8
8
 
9
- <%= form_with url: affirmations_path do |form| %>
10
- <%= form.label :email %>
11
- <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
12
-
9
+ <%= form_with url: affirmations_path, scope: :user do |form| %>
10
+ <%= render form %>
13
11
  <%= form.button "Submit", name: nil %>
14
12
  <% end -%>
@@ -1,17 +1,8 @@
1
- <h2>
2
- Change your password
3
- </h2>
4
-
5
- <p>
6
- <%= link_to "Sign in to your account" %>
7
- </p>
8
-
9
- <%= form_with model: @user, url: recovery_path(id: params[:id]), method: :patch do |form| %>
1
+ <div>
10
2
  <%= form.label :password %>
11
3
  <%= form.password_field :password, autocomplete: "new-password", required: true %>
12
-
4
+ </div>
5
+ <div>
13
6
  <%= form.label :password_confirmation %>
14
7
  <%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
15
-
16
- <%= form.button "Submit", name: nil %>
17
- <% end %>
8
+ </div>
@@ -0,0 +1,12 @@
1
+ <h2>
2
+ Change your password
3
+ </h2>
4
+
5
+ <p>
6
+ <%= link_to "Sign in to your account" %>
7
+ </p>
8
+
9
+ <%= form_with model: @user, url: credential_path(id: params[:id]), method: :patch do |form| %>
10
+ <%= render form %>
11
+ <%= form.button "Submit", name: nil %>
12
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <div>
2
+ <%= form.label :email %>
3
+ <%= form.email_field :email, autocomplete: "email", required: true %>
4
+ </div>
5
+ <div>
6
+ <%= form.label :password_challenge, "Current password" %>
7
+ <%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
8
+ </div>
@@ -10,11 +10,6 @@
10
10
  <% end %>
11
11
 
12
12
  <%= form_with model: @user, url: email_path, method: :patch do |form| %>
13
- <%= form.label :email %>
14
- <%= form.email_field :email, autocomplete: "email", required: true %>
15
-
16
- <%= form.label :password_challenge, "Current password" %>
17
- <%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
18
-
13
+ <%= render form %>
19
14
  <%= form.button "Submit", name: nil %>
20
15
  <% end %>
@@ -1,3 +1,3 @@
1
1
  Sign in by following this link:
2
2
 
3
- <%= affirmation_url(id: @signed_id) %>
3
+ <%= edit_affirmation_url(id: @signed_id) %>
@@ -1,3 +1,3 @@
1
1
  Verify your email by following this link:
2
2
 
3
- <%= verification_url(id: @signed_id) %>
3
+ <%= edit_verification_url(id: @signed_id) %>
@@ -1,3 +1,3 @@
1
1
  Reset your password by following this link:
2
2
 
3
- <%= edit_recovery_url(id: @signed_id) %>
3
+ <%= edit_credential_url(id: @signed_id) %>
@@ -0,0 +1,12 @@
1
+ <div>
2
+ <%= form.label :password_challenge, "Current password" %>
3
+ <%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
4
+ </div>
5
+ <div>
6
+ <%= form.label :password %>
7
+ <%= form.password_field :password, autocomplete: "new-password", required: true %>
8
+ </div>
9
+ <div>
10
+ <%= form.label :password_confirmation %>
11
+ <%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
12
+ </div>
@@ -3,14 +3,6 @@
3
3
  </h2>
4
4
 
5
5
  <%= form_with model: @user, url: password_path, method: :patch do |form| %>
6
- <%= form.label :password_challenge, "Current password" %>
7
- <%= form.password_field :password_challenge, autocomplete: "current-password", required: true %>
8
-
9
- <%= form.label :password %>
10
- <%= form.password_field :password, autocomplete: "new-password", required: true %>
11
-
12
- <%= form.label :password_confirmation %>
13
- <%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
14
-
6
+ <%= render form %>
15
7
  <%= form.button "Submit", name: nil %>
16
8
  <% end %>
@@ -0,0 +1,4 @@
1
+ <div>
2
+ <%= form.label :email %>
3
+ <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
4
+ </div>
@@ -6,9 +6,7 @@
6
6
  <%= link_to "Sign in to your account", new_session_path %>
7
7
  </p>
8
8
 
9
- <%= form_with url: recoveries_path do |form| %>
10
- <%= form.label :email %>
11
- <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
12
-
9
+ <%= form_with url: recoveries_path, scope: :user do |form| %>
10
+ <%= render form %>
13
11
  <%= form.button "Submit", name: nil %>
14
12
  <% end -%>
@@ -0,0 +1,12 @@
1
+ <div>
2
+ <%= form.label :email %>
3
+ <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
4
+ </div>
5
+ <div>
6
+ <%= form.label :password %>
7
+ <%= form.password_field :password, autocomplete: "new-password", required: true %>
8
+ </div>
9
+ <div>
10
+ <%= form.label :password_confirmation %>
11
+ <%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
12
+ </div>
@@ -7,17 +7,6 @@
7
7
  </p>
8
8
 
9
9
  <%= form_with model: @user, url: registrations_path do |form| %>
10
- <div>
11
- <%= form.label :email %>
12
- <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
13
- </div>
14
- <div>
15
- <%= form.label :password %>
16
- <%= form.password_field :password, autocomplete: "new-password", required: true %>
17
- </div>
18
- <div>
19
- <%= form.label :password_confirmation %>
20
- <%= form.password_field :password_confirmation, autocomplete: "new-password", required: true %>
21
- </div>
10
+ <%= render form %>
22
11
  <%= form.button "Submit", name: nil %>
23
12
  <% end %>
@@ -0,0 +1,8 @@
1
+ <div>
2
+ <%= form.label :email %>
3
+ <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
4
+ </div>
5
+ <div>
6
+ <%= form.label :password %>
7
+ <%= form.password_field :password, autocomplete: "current-password", required: true %>
8
+ </div>
@@ -7,9 +7,6 @@
7
7
  </p>
8
8
 
9
9
  <%= form_with model: @session do |form| %>
10
- <%= form.label :email %>
11
- <%= form.email_field :email, autofocus: true, autocomplete: "email", required: true %>
12
- <%= form.label :password %>
13
- <%= form.password_field :password, autocomplete: "current-password", required: true %>
10
+ <%= render form %>
14
11
  <%= form.button "Submit", name: nil %>
15
12
  <% end -%>
@@ -0,0 +1,7 @@
1
+ <h2>
2
+ Verify your email
3
+ </h2>
4
+
5
+ <%= form_with url: verification_path(id: params[:id]), method: :patch do |form| %>
6
+ <%= form.button "Submit", name: nil %>
7
+ <% end -%>
@@ -0,0 +1,45 @@
1
+ en:
2
+ avocado:
3
+ affirmations:
4
+ create:
5
+ success: Check email for sign in instructions.
6
+ errors:
7
+ invalid_token: Sign in link is invalid.
8
+ unverified_email: Verify email first before signing in.
9
+ update:
10
+ success: Signed in successfully.
11
+ credentials:
12
+ update:
13
+ success: Password reset successfully.
14
+ errors:
15
+ invalid_token: Password reset link is invalid.
16
+ emails:
17
+ update:
18
+ success: Email has been changed.
19
+ filters:
20
+ invalid_password_challenge: Password challenge failed.
21
+ passwords:
22
+ update:
23
+ success: Password has been changed.
24
+ recoveries:
25
+ create:
26
+ success: Check email for reset instructions.
27
+ errors:
28
+ unverified_email: Verify email first before resetting password.
29
+ registrations:
30
+ create:
31
+ success: Registration successful.
32
+ sessions:
33
+ create:
34
+ success: Session created.
35
+ destroy:
36
+ success: Session destroyed.
37
+ errors:
38
+ authentication: Authentication failed.
39
+ verifications:
40
+ create:
41
+ success: Verification email sent.
42
+ errors:
43
+ invalid_token: Email verification link is invalid.
44
+ update:
45
+ success: Email address verified.
@@ -0,0 +1,11 @@
1
+ scope module: :avocado do
2
+ resource :email, only: %i[edit update]
3
+ resource :password, only: %i[edit update]
4
+ resources :affirmations, only: %i[new create edit update]
5
+ resources :credentials, only: %i[edit update]
6
+ resources :events, only: %i[index]
7
+ resources :recoveries, only: %i[new create]
8
+ resources :registrations, only: %i[new create]
9
+ resources :sessions, only: %i[index new create destroy]
10
+ resources :verifications, only: %i[create edit update]
11
+ end
data/config.ru CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "rubygems"
4
2
  require "bundler"
5
3
 
data/docs/USAGE.md ADDED
@@ -0,0 +1,164 @@
1
+ # Overview
2
+
3
+ The 🥑 gem is a [Rails Engine] composed of a mixture of Ruby modules that get
4
+ included into application classes and Ruby classes which will run directly from
5
+ the 🥑 gem itself. The classes are intended to provide good defaults for basic
6
+ scenarios, and can be subclassed and overridden for special cases.
7
+
8
+ ## Requirements
9
+
10
+ Apps must be running Rails 7.1 or newer. The 🥑 gem uses features like
11
+ `authenticate_by`, the `password_challenge` feature of `has_secure_password`,
12
+ `generates_token_for`, and `normalizes` which don't exist in earlier versions.
13
+
14
+ The database schema must have columns that match the `users`, `sessions`, and
15
+ `events` tables from the [demo app schema]. More columns in each table are
16
+ acceptable; the demo is just a minimum. Slight variations (using `uuid` instead
17
+ of `bigint` for example) are harmless, but large departures will break the
18
+ integration.
19
+
20
+ Run `bin/rails g avocado:migrations` to generate migrations for the tables.
21
+
22
+ The application must also have:
23
+
24
+ - An `ApplicationController` base controller class for the controllers to
25
+ inherit from.
26
+ - An `ApplicationMailer` base mailer class which sets a layout and default
27
+ `from` value.
28
+ - A `root_path` route helper method (typically generated by routes configured in
29
+ the application).
30
+
31
+ ## Usage
32
+
33
+ ### Models
34
+
35
+ Include these modules into `ActiveRecord` model classes:
36
+
37
+ ```ruby
38
+ class User < ApplicationRecord
39
+ include Avocado::User
40
+ end
41
+
42
+ class Session < ApplicationRecord
43
+ include Avocado::Session
44
+ end
45
+
46
+ class Event < ApplicationRecord
47
+ include Avocado::Event
48
+ end
49
+ ```
50
+
51
+ This will set up some basic associations, validations, callbacks, and
52
+ normalizations for those models.
53
+
54
+ ### Controllers
55
+
56
+ Add the `Avocado::Authentication` module to the top-level controller:
57
+
58
+ ```ruby
59
+ class ApplicationController < ActionController::Base
60
+ include Avocado::Authentication
61
+ end
62
+ ```
63
+
64
+ ### Routes
65
+
66
+ By defalt, 🥑 does not add any routes to the application when initialized. To
67
+ hook up the controllers to routes, they must be added to the `config/routes.rb`
68
+ of the application. It's possible to add all of the routes, or just a subset.
69
+
70
+ This example defines a `root` route and also pulls in every feature route:
71
+
72
+ ```ruby
73
+ Rails.application.routes.draw do
74
+ root to: "records#index"
75
+ draw(🥑)
76
+ end
77
+ ```
78
+
79
+ This example defines a `root` route and adds only a subset of feature routes:
80
+
81
+ ```ruby
82
+ Rails.application.routes.draw do
83
+ root to: "records#index"
84
+ scope module: 🥑 do
85
+ resources :registrations, only: %i[new create]
86
+ resources :sessions, only: %i[new create destroy]
87
+ end
88
+ end
89
+ ```
90
+
91
+ ## Summary
92
+
93
+ ### Routable controller features
94
+
95
+ The 🥑 gem will create REST-ful routes that go to the various controllers during
96
+ app initialization.
97
+
98
+ These external (unauthenticated) features are available:
99
+
100
+ - `Registrations` -- Fill out new user form and create users
101
+ - `Sessions` -- Sign in and sign out
102
+ - `Recoveries` -- Triggers password reset via emailed expiring link
103
+ - `Credentials` -- Use expiring token link from recovery to update password
104
+ - `Verifications` -- Confirm email address on account creation or email change
105
+ - `Affirmations` -- "Passwordless" authentication via emailed expiring link
106
+
107
+ These internal (authenticated) features are available:
108
+
109
+ - `Sessions` -- Index view of active sessions, ability to destroy sessions
110
+ - `Events` -- Index view of the user activity audit log
111
+ - `Passwords` -- Edit and update a user password
112
+ - `Emails` -- Edit and update a user email
113
+
114
+ Linking to any of these internal pages is optional. Apps can use them as-is,
115
+ override their views, or even ignore them entirely and make local versions.
116
+
117
+ ### Mailers
118
+
119
+ There is an `Avocado::Mailer` which gets called to send emails. The mailer views
120
+ here are very basic, and should be overriden within applications. Place views
121
+ within `app/views/avocado/mailer/` to make this happen.
122
+
123
+ ### Before actions
124
+
125
+ There is an `authenticate` method installed as default controller behavior using
126
+ `before_action :authenticate`. Any actions which do not need to be authenticated
127
+ should disable this with `skip_before_action :authenticate`, or inherit from a
128
+ controller which performs the skip.
129
+
130
+ There is also a `set_current_request_details` method installed as a default
131
+ `before_action` which takes some loggable request meta information (User Agent,
132
+ IP Address) and sets their values in `Current` so that they are accesible to
133
+ code elsewhere in the 🥑 gem.
134
+
135
+ ### Helpers
136
+
137
+ The `Avocado::Authentication` module included into the application controller
138
+ provides some helper methods available in controllers, views, and helpers:
139
+
140
+ - `signed_in?` is true if the session has a signed in user
141
+ - `current_session` provides the DB record for the session, if one exists
142
+ - `current_user` returns the user belonging to that session
143
+
144
+ Usage of these can be seen in the views in the [demo app].
145
+
146
+ ## Customization
147
+
148
+ There is not any configuration. To override functionality:
149
+
150
+ - Redefine a method created in one of the models by the included module
151
+ - Subclass a controller and update the routing to go to the subclass
152
+ - Place views in the app where avocado expects (`app/views/avocado`) them to
153
+ override the defaults
154
+
155
+ There is an `avocado:views` generator which will copy all the views as a
156
+ starting point for further modification.
157
+
158
+ ## Examples
159
+
160
+ There is a [demo app] used by the specs which has some example usage.
161
+
162
+ [demo app schema]: https://github.com/tcuwp/avocado/blob/main/spec/internal/db/schema.rb
163
+ [demo app]: https://github.com/tcuwp/avocado/blob/main/spec/internal
164
+ [Rails Engine]: https://guides.rubyonrails.org/engines.html#what-are-engines-questionmark
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module Authentication
5
3
  extend ActiveSupport::Concern
@@ -37,12 +35,12 @@ module Avocado
37
35
 
38
36
  def sign_in(user)
39
37
  ::Session.create!(user: user).tap do |session|
40
- cookies.signed.permanent[:session_token] = {value: session.id, httponly: true}
38
+ cookies.signed.permanent[:session_token] = {value: session.token, httponly: true}
41
39
  end
42
40
  end
43
41
 
44
42
  def session_from_token
45
- ::Session.find_by_id(cookies.signed[:session_token])
43
+ ::Session.find_by_token(cookies.signed[:session_token])
46
44
  end
47
45
 
48
46
  def set_current_request_details
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  class Current < ActiveSupport::CurrentAttributes
5
3
  attribute :session,
@@ -1,9 +1,12 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "avocado"
4
2
  require "rails/engine"
5
3
 
6
4
  module Avocado
7
5
  class Engine < Rails::Engine
6
+ initializer :avocado_routing do
7
+ ActiveSupport.on_load(:action_dispatch_request) do
8
+ ActionDispatch::Routing::Mapper.define_method(:🥑) { :avocado }
9
+ end
10
+ end
8
11
  end
9
12
  end
data/lib/avocado/event.rb CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module Event
5
3
  extend ActiveSupport::Concern
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  class Mailer < ApplicationMailer
5
3
  before_action :set_user
@@ -1,14 +1,18 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module Session
5
3
  extend ActiveSupport::Concern
6
4
 
5
+ SECURE_TOKEN_LENGTH = 64
6
+
7
7
  included do
8
8
  include SessionCallbacks
9
9
 
10
+ has_secure_token length: SECURE_TOKEN_LENGTH, on: :initialize
11
+
10
12
  belongs_to :user
11
13
 
14
+ validates :token, presence: true
15
+
12
16
  scope :newest_first, -> { order(created_at: :desc) }
13
17
  scope :non_current, -> { where.not(id: Current.session) }
14
18
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module SessionCallbacks
5
3
  extend ActiveSupport::Concern
data/lib/avocado/user.rb CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module User
5
3
  extend ActiveSupport::Concern
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module UserCallbacks
5
3
  extend ActiveSupport::Concern
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module UserTokens
5
3
  extend ActiveSupport::Concern
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
2
  module UserValidations
5
3
  extend ActiveSupport::Concern
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Avocado
4
- VERSION = "0.5.0"
2
+ VERSION = "0.7.0"
5
3
  end
data/lib/avocado.rb CHANGED
@@ -1,5 +1,4 @@
1
- # frozen_string_literal: true
2
-
1
+ require "active_support"
3
2
  require_relative "avocado/engine"
4
3
 
5
4
  module Avocado