upgrow 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/lib/upgrow.rb +2 -8
  4. data/lib/upgrow/action.rb +66 -16
  5. data/lib/upgrow/actions.rb +31 -0
  6. data/lib/upgrow/active_record_adapter.rb +24 -15
  7. data/lib/upgrow/active_record_schema.rb +63 -0
  8. data/lib/upgrow/basic_model.rb +64 -0
  9. data/lib/upgrow/basic_repository.rb +49 -22
  10. data/lib/upgrow/error.rb +19 -0
  11. data/lib/upgrow/immutable_object.rb +26 -21
  12. data/lib/upgrow/input.rb +7 -0
  13. data/lib/upgrow/model.rb +12 -12
  14. data/lib/upgrow/model_schema.rb +31 -0
  15. data/lib/upgrow/repository.rb +3 -0
  16. data/lib/upgrow/result.rb +18 -55
  17. data/lib/upgrow/schema.rb +33 -0
  18. data/test/application_system_test_case.rb +11 -0
  19. data/test/dummy/app/actions/application_action.rb +10 -0
  20. data/test/dummy/app/actions/articles/create_action.rb +15 -0
  21. data/test/dummy/app/actions/articles/destroy_action.rb +9 -0
  22. data/test/dummy/app/actions/articles/edit_action.rb +12 -0
  23. data/test/dummy/app/actions/articles/index_action.rb +11 -0
  24. data/test/dummy/app/actions/articles/new_action.rb +8 -0
  25. data/test/dummy/app/actions/articles/show_action.rb +11 -0
  26. data/test/dummy/app/actions/articles/update_action.rb +15 -0
  27. data/test/dummy/app/actions/comments/create_action.rb +15 -0
  28. data/test/dummy/app/actions/comments/destroy_action.rb +9 -0
  29. data/test/dummy/app/actions/comments/new_action.rb +8 -0
  30. data/test/dummy/app/actions/sessions/create_action.rb +23 -0
  31. data/test/dummy/app/actions/sessions/destroy_action.rb +6 -0
  32. data/test/dummy/app/actions/sessions/new_action.rb +8 -0
  33. data/test/dummy/app/actions/user_action.rb +10 -0
  34. data/test/dummy/app/actions/users/create_action.rb +13 -0
  35. data/test/dummy/app/actions/users/new_action.rb +8 -0
  36. data/test/dummy/app/controllers/application_controller.rb +10 -0
  37. data/test/dummy/app/controllers/articles_controller.rb +32 -28
  38. data/test/dummy/app/controllers/comments_controller.rb +41 -0
  39. data/test/dummy/app/controllers/sessions_controller.rb +34 -0
  40. data/test/dummy/app/controllers/users_controller.rb +29 -0
  41. data/test/dummy/app/helpers/application_helper.rb +27 -3
  42. data/test/dummy/app/helpers/users_helper.rb +15 -0
  43. data/test/dummy/app/inputs/article_input.rb +3 -0
  44. data/test/dummy/app/inputs/comment_input.rb +11 -0
  45. data/test/dummy/app/inputs/session_input.rb +9 -0
  46. data/test/dummy/app/inputs/user_input.rb +9 -0
  47. data/test/dummy/app/models/article.rb +0 -2
  48. data/test/dummy/app/models/comment.rb +4 -0
  49. data/test/dummy/app/models/user.rb +4 -0
  50. data/test/dummy/app/records/article_record.rb +2 -0
  51. data/test/dummy/app/records/comment_record.rb +7 -0
  52. data/test/dummy/app/records/user_record.rb +9 -0
  53. data/test/dummy/app/repositories/article_repository.rb +26 -0
  54. data/test/dummy/app/repositories/comment_repository.rb +3 -0
  55. data/test/dummy/app/repositories/user_repository.rb +12 -0
  56. data/test/dummy/config/routes.rb +6 -1
  57. data/test/dummy/db/migrate/20210320140432_create_comments.rb +12 -0
  58. data/test/dummy/db/migrate/20210409164927_create_users.rb +22 -0
  59. data/test/dummy/db/schema.rb +24 -1
  60. data/test/system/articles_test.rb +87 -29
  61. data/test/system/comments_test.rb +81 -0
  62. data/test/system/guest_user_test.rb +14 -0
  63. data/test/system/sign_in_test.rb +57 -0
  64. data/test/system/sign_out_test.rb +19 -0
  65. data/test/system/sign_up_test.rb +38 -0
  66. data/test/test_helper.rb +6 -1
  67. data/test/upgrow/action_test.rb +101 -9
  68. data/test/upgrow/actions_test.rb +24 -0
  69. data/test/upgrow/active_record_adapter_test.rb +12 -17
  70. data/test/upgrow/active_record_schema_test.rb +92 -0
  71. data/test/upgrow/basic_model_test.rb +95 -0
  72. data/test/upgrow/basic_repository_test.rb +48 -27
  73. data/test/upgrow/immutable_object_test.rb +43 -7
  74. data/test/upgrow/input_test.rb +19 -1
  75. data/test/upgrow/model_schema_test.rb +44 -0
  76. data/test/upgrow/model_test.rb +48 -11
  77. data/test/upgrow/result_test.rb +19 -64
  78. data/test/upgrow/schema_test.rb +44 -0
  79. metadata +128 -50
  80. data/test/dummy/app/actions/create_article_action.rb +0 -13
  81. data/test/dummy/app/actions/delete_article_action.rb +0 -7
  82. data/test/dummy/app/actions/edit_article_action.rb +0 -10
  83. data/test/dummy/app/actions/list_articles_action.rb +0 -8
  84. data/test/dummy/app/actions/show_article_action.rb +0 -10
  85. data/test/dummy/app/actions/update_article_action.rb +0 -13
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Comments
4
+ class CreateAction < ApplicationAction
5
+ expose :comment
6
+
7
+ def perform(input)
8
+ if input.valid?
9
+ @comment = CommentRepository.new.create(input)
10
+ else
11
+ failure(input.errors)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Comments
4
+ class DestroyAction < ApplicationAction
5
+ def perform(id)
6
+ CommentRepository.new.delete(id)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Comments
4
+ class NewAction < UserAction
5
+ def perform
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sessions
4
+ class CreateAction < ApplicationAction
5
+ def perform(input)
6
+ if input.valid?
7
+ @current_user = UserRepository.new.find_for_authentication(input)
8
+ unless @current_user
9
+ failure(
10
+ Upgrow::Error.new(
11
+ message: 'Invalid email or password.',
12
+ code: :invalid_email_or_password,
13
+ attribute: :password
14
+ ),
15
+ Upgrow::Error.new(attribute: :email)
16
+ )
17
+ end
18
+ else
19
+ failure(input.errors)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sessions
4
+ class DestroyAction < ApplicationAction
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sessions
4
+ class NewAction < ApplicationAction
5
+ def perform
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserAction < ApplicationAction
4
+ class UnauthorizedError < StandardError; end
5
+
6
+ def initialize(...)
7
+ super
8
+ raise UnauthorizedError unless @current_user
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Users
4
+ class CreateAction < ApplicationAction
5
+ def perform(input)
6
+ if input.valid?
7
+ @current_user = UserRepository.new.create(input)
8
+ else
9
+ failure(input.errors)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Users
4
+ class NewAction < ApplicationAction
5
+ def perform
6
+ end
7
+ end
8
+ end
@@ -1,3 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
  class ApplicationController < ActionController::Base
3
+ rescue_from(UserAction::UnauthorizedError) { redirect_to(new_session_path) }
4
+
5
+ before_action :instantiate_action
6
+
7
+ private
8
+
9
+ def instantiate_action
10
+ action_class = Upgrow::Actions[controller_name, action_name]
11
+ @action = action_class.new(user_id: session[:user_id])
12
+ end
3
13
  end
@@ -2,57 +2,61 @@
2
2
 
3
3
  class ArticlesController < ApplicationController
4
4
  def index
5
- @articles = ListArticlesAction.new.perform.articles
5
+ @result = @action.perform
6
6
  end
7
7
 
8
8
  def show
9
- @article = ShowArticleAction.new.perform(params[:id]).article
9
+ @result = @action.perform(params[:id])
10
10
  end
11
11
 
12
12
  def new
13
13
  @input = ArticleInput.new
14
+ @result = @action.perform
14
15
  end
15
16
 
16
17
  def edit
17
- article = EditArticleAction.new.perform(params[:id]).article
18
+ @result = @action.perform(params[:id])
18
19
  @input = ArticleInput.new(
19
- title: article.title, body: article.body
20
+ title: @result.article.title, body: @result.article.body
20
21
  )
21
22
  end
22
23
 
23
24
  def create
24
- @input = ArticleInput.new(article_params)
25
+ @input = ArticleInput.new(
26
+ article_params.merge(user_id: session[:user_id])
27
+ )
28
+
29
+ @result = @action.perform(@input)
25
30
 
26
- CreateArticleAction.new.perform(@input)
27
- .and_then do |article:|
28
- redirect_to(
29
- article_path(article.id), notice: 'Article was successfully created.'
30
- )
31
- end
32
- .or_else do |errors|
33
- @errors = errors
34
- render(:new)
35
- end
31
+ if @result.success?
32
+ redirect_to(
33
+ article_path(@result.article.id),
34
+ notice: 'Article was successfully created.'
35
+ )
36
+ else
37
+ render(:new)
38
+ end
36
39
  end
37
40
 
38
41
  def update
39
- @input = ArticleInput.new(article_params)
42
+ @input = ArticleInput.new(
43
+ article_params.merge(user_id: session[:user_id])
44
+ )
45
+
46
+ @result = @action.perform(params[:id], @input)
40
47
 
41
- UpdateArticleAction.new.perform(params[:id], @input)
42
- .and_then do |article:|
43
- redirect_to(
44
- article_path(article.id),
45
- notice: 'Article was successfully updated.'
46
- )
47
- end
48
- .or_else do |errors|
49
- @errors = errors
50
- render(:edit)
51
- end
48
+ if @result.success?
49
+ redirect_to(
50
+ article_path(@result.article.id),
51
+ notice: 'Article was successfully updated.'
52
+ )
53
+ else
54
+ render(:edit)
55
+ end
52
56
  end
53
57
 
54
58
  def destroy
55
- DeleteArticleAction.new.perform(params[:id])
59
+ @action.perform(params[:id])
56
60
  redirect_to(articles_url, notice: 'Article was successfully destroyed.')
57
61
  end
58
62
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentsController < ApplicationController
4
+ def new
5
+ @input = CommentInput.new(article_id: params[:article_id])
6
+ @result = @action.perform
7
+ end
8
+
9
+ def create
10
+ @input = CommentInput.new(
11
+ comment_params.merge(article_id: params[:article_id],
12
+ user_id: session[:user_id])
13
+ )
14
+
15
+ @result = @action.perform(@input)
16
+
17
+ if @result.success?
18
+ redirect_to(
19
+ article_path(@result.comment.article_id),
20
+ notice: 'Comment was successfully created.'
21
+ )
22
+ else
23
+ render(:new)
24
+ end
25
+ end
26
+
27
+ def destroy
28
+ @action.perform(params[:id])
29
+ redirect_to(
30
+ article_path(params[:article_id]),
31
+ notice: 'Comment was successfully destroyed.'
32
+ )
33
+ end
34
+
35
+ private
36
+
37
+ # Only allow a list of trusted parameters through.
38
+ def comment_params
39
+ params.require(:comment_input).permit(:body)
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SessionsController < ApplicationController
4
+ def new
5
+ @input = SessionInput.new
6
+ @result = @action.perform
7
+ end
8
+
9
+ def create
10
+ @input = SessionInput.new(session_params)
11
+
12
+ @result = @action.perform(@input)
13
+
14
+ if @result.success?
15
+ reset_session
16
+ session[:user_id] = @result.current_user.id
17
+ redirect_to(root_path)
18
+ else
19
+ render(:new)
20
+ end
21
+ end
22
+
23
+ def destroy
24
+ reset_session
25
+ redirect_to(root_path)
26
+ end
27
+
28
+ private
29
+
30
+ # Only allow a list of trusted parameters through.
31
+ def session_params
32
+ params.require(:session_input).permit(:email, :password)
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UsersController < ApplicationController
4
+ def new
5
+ @input = UserInput.new
6
+ @result = @action.perform
7
+ end
8
+
9
+ def create
10
+ @input = UserInput.new(user_params)
11
+
12
+ @result = @action.perform(@input)
13
+
14
+ if @result.success?
15
+ reset_session
16
+ session[:user_id] = @result.current_user.id
17
+ redirect_to(root_path)
18
+ else
19
+ render(:new)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # Only allow a list of trusted parameters through.
26
+ def user_params
27
+ params.require(:user_input).permit(:email, :password)
28
+ end
29
+ end
@@ -24,7 +24,9 @@ module ApplicationHelper
24
24
 
25
25
  if method
26
26
  errors_for(method).each do |error|
27
- result += @template.content_tag(:p, error, class: 'help is-danger')
27
+ result += @template.content_tag(
28
+ :p, error.message, class: 'help is-danger'
29
+ )
28
30
  end
29
31
  end
30
32
 
@@ -46,6 +48,7 @@ module ApplicationHelper
46
48
  def text_field(method, label: true, expanded: false, field: true, **args)
47
49
  input_class = ['input']
48
50
  input_class << 'is-danger' if errors_for(method).any?
51
+
49
52
  output = control(expanded: expanded) do
50
53
  super(method, class: input_class, **args)
51
54
  end
@@ -68,6 +71,28 @@ module ApplicationHelper
68
71
  field(method: method, label: true) { output }
69
72
  end
70
73
 
74
+ def email_field(method, **args)
75
+ input_class = ['input']
76
+ input_class << 'is-danger' if errors_for(method).any?
77
+
78
+ output = control(expanded: false) do
79
+ super(method, class: input_class, **args)
80
+ end
81
+
82
+ field(method: method, label: true) { output }
83
+ end
84
+
85
+ def password_field(method, **args)
86
+ input_class = ['input']
87
+ input_class << 'is-danger' if errors_for(method).any?
88
+
89
+ output = control(expanded: false) do
90
+ super(method, class: input_class, **args)
91
+ end
92
+
93
+ field(method: method, label: true) { output }
94
+ end
95
+
71
96
  # Render a form submit button.
72
97
  #
73
98
  # @param text [Symbol] the text for the button.
@@ -95,8 +120,7 @@ module ApplicationHelper
95
120
  end
96
121
 
97
122
  def errors_for(method)
98
- (options[:errors] || ActiveModel::Errors.new(self))
99
- .full_messages_for(method)
123
+ (options[:errors] || []).select { |error| error.attribute == method }
100
124
  end
101
125
  end
102
126
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UsersHelper
4
+ def user_signed_in?
5
+ current_user.present?
6
+ end
7
+
8
+ def current_user
9
+ @result.current_user
10
+ end
11
+
12
+ def belongs_to_current_user?(model)
13
+ user_signed_in? && model.user_id == current_user.id
14
+ end
15
+ end
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class ArticleInput < Upgrow::Input
3
4
  attribute :title
4
5
  attribute :body
6
+ attribute :user_id
5
7
 
8
+ validates :user_id, presence: true
6
9
  validates :title, presence: true
7
10
  validates :body, presence: true, length: { minimum: 10 }
8
11
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CommentInput < Upgrow::Input
4
+ attribute :article_id
5
+ attribute :user_id
6
+ attribute :body
7
+
8
+ validates :article_id, presence: true
9
+ validates :user_id, presence: true
10
+ validates :body, presence: true, length: { minimum: 10 }
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SessionInput < Upgrow::Input
4
+ attribute :email
5
+ attribute :password
6
+
7
+ validates :email, presence: true
8
+ validates :password, presence: true
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserInput < Upgrow::Input
4
+ attribute :email
5
+ attribute :password
6
+
7
+ validates :email, presence: true
8
+ validates :password, presence: true
9
+ end