avocado 0.5.0 → 0.7.0

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