next_on_rails 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +591 -0
  4. data/Rakefile +32 -0
  5. data/app/controllers/next_on_rails/application_controller.rb +21 -0
  6. data/app/controllers/next_on_rails/devise_token_auth_override/concerns/current_resource_serializer.rb +15 -0
  7. data/app/controllers/next_on_rails/devise_token_auth_override/confirmations_controller.rb +4 -0
  8. data/app/controllers/next_on_rails/devise_token_auth_override/omniauth_callbacks_controller.rb +7 -0
  9. data/app/controllers/next_on_rails/devise_token_auth_override/passwords_controller.rb +23 -0
  10. data/app/controllers/next_on_rails/devise_token_auth_override/registrations_controller.rb +33 -0
  11. data/app/controllers/next_on_rails/devise_token_auth_override/sessions_controller.rb +27 -0
  12. data/app/controllers/next_on_rails/devise_token_auth_override/token_validations_controller.rb +13 -0
  13. data/app/controllers/next_on_rails/devise_token_auth_override/unlocks_controller.rb +23 -0
  14. data/app/controllers/next_on_rails/merger_controller.rb +36 -0
  15. data/app/serializers/next_on_rails/active_model_errors_serializer.rb +45 -0
  16. data/app/serializers/next_on_rails/errors_serializer.rb +16 -0
  17. data/config/routes.rb +12 -0
  18. data/lib/generators/nor/backend/backend_generator.rb +129 -0
  19. data/lib/generators/nor/backend/templates/Procfile +2 -0
  20. data/lib/generators/nor/backend/templates/application_controller.rb +2 -0
  21. data/lib/generators/nor/backend/templates/cors.rb +23 -0
  22. data/lib/generators/nor/backend/templates/current_user_serializer.rb.tt +8 -0
  23. data/lib/generators/nor/backend/templates/user.rb.tt +8 -0
  24. data/lib/generators/nor/backend/templates/user_migration.rb.tt +53 -0
  25. data/lib/generators/nor/backend/templates/user_serializer.rb.tt +11 -0
  26. data/lib/generators/nor/frontend/frontend_generator.rb +60 -0
  27. data/lib/generators/nor/frontend/templates/frontend/components/flash.js +29 -0
  28. data/lib/generators/nor/frontend/templates/frontend/components/inputs.js +69 -0
  29. data/lib/generators/nor/frontend/templates/frontend/components/login-form.js +23 -0
  30. data/lib/generators/nor/frontend/templates/frontend/components/registration-form.js +49 -0
  31. data/lib/generators/nor/frontend/templates/frontend/next-on-rails.config.js +3 -0
  32. data/lib/generators/nor/frontend/templates/frontend/next.config.js +20 -0
  33. data/lib/generators/nor/frontend/templates/frontend/pages/_app.js +3 -0
  34. data/lib/generators/nor/frontend/templates/frontend/pages/index.js +57 -0
  35. data/lib/generators/nor/frontend/templates/frontend/server.js +31 -0
  36. data/lib/generators/nor/frontend/templates/frontend/stylesheets/application.scss +2 -0
  37. data/lib/generators/nor/install/USAGE +30 -0
  38. data/lib/generators/nor/install/install_generator.rb +8 -0
  39. data/lib/generators/nor/scaffold/USAGE +10 -0
  40. data/lib/generators/nor/scaffold/scaffold_generator.rb +53 -0
  41. data/lib/generators/nor/scaffold/templates/controller.rb.tt +40 -0
  42. data/lib/generators/nor/scaffold/templates/frontend/components/details.js.tt +20 -0
  43. data/lib/generators/nor/scaffold/templates/frontend/components/form.js.tt +17 -0
  44. data/lib/generators/nor/scaffold/templates/frontend/pages/crud.js.tt +123 -0
  45. data/lib/generators/nor/scaffold/templates/frontend/pages/edit.js.tt +55 -0
  46. data/lib/generators/nor/scaffold/templates/frontend/pages/index.js.tt +88 -0
  47. data/lib/generators/nor/scaffold/templates/frontend/pages/new.js.tt +51 -0
  48. data/lib/generators/nor/scaffold/templates/frontend/pages/show.js.tt +43 -0
  49. data/lib/next_on_rails.rb +12 -0
  50. data/lib/next_on_rails/engine.rb +5 -0
  51. data/lib/next_on_rails/version.rb +3 -0
  52. data/lib/tasks/next_on_rails_tasks.rake +4 -0
  53. metadata +235 -0
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'NextOnRails'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,21 @@
1
+ module NextOnRails
2
+ class ApplicationController < ActionController::API
3
+ include DeviseTokenAuth::Concerns::SetUserByToken
4
+
5
+ # rescue_from CanCan::AccessDenied do |_exception|
6
+ # head :forbidden
7
+ # end
8
+
9
+ protected
10
+
11
+ def render_resource(resource, serializer_options = {}, render_options = {})
12
+ serializer = serializer_options.delete(:serializer) || "#{resource.model_name}Serializer"
13
+ serializer = serializer.classify.constantize
14
+ if resource.errors.empty?
15
+ render json: serializer.new(resource, **serializer_options), **render_options
16
+ else
17
+ render json: ActiveModelErrorsSerializer.new(resource), status: :unprocessable_entity
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module NextOnRails
2
+ module DeviseTokenAuthOverride
3
+ module Concerns
4
+ module CurrentResourceSerializer
5
+ extend ActiveSupport::Concern
6
+
7
+ private
8
+
9
+ def current_resource_serializer(resource)
10
+ "Current#{resource.class}Serializer".constantize
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::ConfirmationsController < DeviseTokenAuth::ConfirmationsController
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCallbacksController
3
+ def omniauth_failure
4
+ render json: params[:message] || 'An error occurred', status: :unprocessable_entity
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::PasswordsController < DeviseTokenAuth::PasswordsController
3
+ def render_create_success
4
+ head :ok
5
+ end
6
+
7
+ def render_update_success
8
+ head :ok
9
+ end
10
+
11
+ def render_create_error
12
+ render json: ActiveModelErrorsSerializer.new(@resource), status: :unprocessable_entity
13
+ end
14
+
15
+ def render_update_error
16
+ render json: ActiveModelErrorsSerializer.new(@resource), status: :unprocessable_entity
17
+ end
18
+
19
+ def render_error(status, message, _data = nil)
20
+ render json: ErrorsSerializer.new(message), status: status
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::RegistrationsController < DeviseTokenAuth::RegistrationsController
3
+ include DeviseTokenAuthOverride::Concerns::CurrentResourceSerializer
4
+
5
+ def render_create_success
6
+ render json: current_resource_serializer(@resource).new(@resource), status: :created
7
+ end
8
+
9
+ def render_create_error
10
+ render json: ActiveModelErrorsSerializer.new(@resource), status: :unprocessable_entity
11
+ end
12
+
13
+ def render_update_success
14
+ render json: current_resource_serializer(@resource).new(@resource), status: :ok
15
+ end
16
+
17
+ def render_update_error
18
+ render json: ActiveModelErrorsSerializer.new(@resource), status: :unprocessable_entity
19
+ end
20
+
21
+ def render_error(status, message, _data = nil)
22
+ render json: ErrorsSerializer.new(message), status: status
23
+ end
24
+
25
+ def sign_up_params
26
+ params.permit(:email, :password, :password_confirmation)
27
+ end
28
+
29
+ def account_update_params
30
+ params.permit(:email, :password, :password_confirmation, :current_password, :username)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::SessionsController < DeviseTokenAuth::SessionsController
3
+ include DeviseTokenAuthOverride::Concerns::CurrentResourceSerializer
4
+
5
+ def render_new_error
6
+ head :method_not_allowed
7
+ end
8
+
9
+ def render_create_success
10
+ render json: current_resource_serializer(@resource).new(@resource), status: :ok
11
+ end
12
+
13
+ def render_destroy_success
14
+ head :ok
15
+ end
16
+
17
+ def render_error(status, message, _data = nil)
18
+ render json: ErrorsSerializer.new(message), status: status
19
+ end
20
+
21
+ private
22
+
23
+ def resource_params
24
+ params.permit(:email, :password)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::TokenValidationsController < DeviseTokenAuth::TokenValidationsController
3
+ include DeviseTokenAuthOverride::Concerns::CurrentResourceSerializer
4
+
5
+ def render_validate_token_success
6
+ render json: current_resource_serializer(@resource).new(@resource), status: :ok
7
+ end
8
+
9
+ def render_error(status, message, _data = nil)
10
+ render json: ErrorsSerializer.new(message), status: status
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module NextOnRails
2
+ class DeviseTokenAuthOverride::UnlocksController < DeviseTokenAuth::UnlocksController
3
+ def render_create_success
4
+ head :ok
5
+ end
6
+
7
+ def render_create_error
8
+ render json: ActiveModelErrorsSerializer.new(@resource), status: :unprocessable_entity
9
+ end
10
+
11
+ def render_error(status, message, _data = nil)
12
+ render json: ErrorsSerializer.new(message), status: status
13
+ end
14
+
15
+ private
16
+
17
+ # Hope in this issue:
18
+ # https://github.com/lynndylanhurley/devise_token_auth/issues/1274
19
+ def after_unlock_path_for(_resource)
20
+ DeviseTokenAuth.default_confirm_success_url
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ module NextOnRails
2
+ class MergerController < ApplicationController
3
+ rescue_from NameError do
4
+ head :bad_request
5
+ end
6
+
7
+ def merge
8
+ json = {}
9
+ resources.each do |resource, _params|
10
+ json[resource] = "$$$#{resource}$$$"
11
+ end
12
+ json = { merge: json }.to_json
13
+ resources.each do |resource, params|
14
+ response_string_json = response_from_controller(resource, params)
15
+ json.gsub!("\"$$$#{resource}$$$\"", response_string_json)
16
+ end
17
+ render json: json
18
+ end
19
+
20
+ private
21
+
22
+ def response_from_controller(resource_name, resource_params)
23
+ action = resource_name == resource_name.singularize ? :show : :index
24
+ controller = "#{resource_name.classify.pluralize}Controller".constantize.new
25
+ controller.params = resource_params
26
+ return { data: {} }.to_json if action == :show && resource_params[:id].blank?
27
+
28
+ controller.dispatch(action, request, ActionDispatch::Response.new)
29
+ return controller.response.body
30
+ end
31
+
32
+ def resources
33
+ params.require(:resources).permit!
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ module NextOnRails
2
+ class ActiveModelErrorsSerializer
3
+ def initialize(model)
4
+ @model = model
5
+ end
6
+
7
+ def serializable_hash
8
+ i = -1
9
+ full_messages = @model.errors.full_messages
10
+ errors = @model.errors.messages.map do |field, error_messages|
11
+ error_messages.map do |error_message|
12
+ i += 1
13
+ {
14
+ title: error_message,
15
+ detail: full_messages[i],
16
+ attribute: field,
17
+ source: { pointer: "/data/attributes/#{field}" }
18
+ }
19
+ end
20
+ end
21
+ @model.class.reflect_on_all_associations.each do |relationship|
22
+ Array.wrap(@model.send(relationship.name)).each_with_index do |child, index|
23
+ i = -1
24
+ full_messages = @model.errors.full_messages
25
+ errors << child.errors.messages.map do |field, error_messages|
26
+ error_messages.map do |error_message|
27
+ i += 1
28
+ {
29
+ title: error_message,
30
+ detail: full_messages[i],
31
+ attribute: "#{child.model_name.plural}[#{index}].#{field}",
32
+ source: { pointer: "/data/attributes/#{child.model_name.plural}[#{index}].#{field}" }
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ return { errors: errors.flatten, hash_errors: @model.errors.as_json }
39
+ end
40
+
41
+ def to_json(options = nil)
42
+ self.serializable_hash.to_json(options)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ module NextOnRails
2
+ class ErrorsSerializer
3
+ def initialize(*messages)
4
+ @messages = messages
5
+ end
6
+
7
+ def serializable_hash
8
+ # return { errors: [{ detail: @message }] }
9
+ return { errors: @messages.map { |message| { detail: message } } }
10
+ end
11
+
12
+ def to_json(options = nil)
13
+ self.serializable_hash.to_json(options)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ NextOnRails::Engine.routes.draw do
2
+ # mount_devise_token_auth_for 'User', at: 'auth', controllers: {
3
+ # confirmations: 'next_on_rails/devise_token_auth_override/confirmations',
4
+ # omniauth_callbacks: 'next_on_rails/devise_token_auth_override/omniauth_callbacks',
5
+ # passwords: 'next_on_rails/devise_token_auth_override/passwords',
6
+ # registrations: 'next_on_rails/devise_token_auth_override/registrations',
7
+ # sessions: 'next_on_rails/devise_token_auth_override/sessions',
8
+ # token_validations: 'next_on_rails/devise_token_auth_override/token_validations',
9
+ # unlocks: 'next_on_rails/devise_token_auth_override/unlocks'
10
+ # }
11
+ get :merge, to: 'merger#merge'
12
+ end
@@ -0,0 +1,129 @@
1
+ module Nor
2
+ class BackendGenerator < Rails::Generators::Base
3
+ include Rails::Generators::Migration
4
+
5
+ attr_reader :user_class, :mount_path
6
+
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ def initialize(args, *options)
10
+ raise 'Next On Rails can be installed only on a Rails API app! Please create a new app with `rails new APPNAME --api`' unless rails_api?
11
+
12
+ super
13
+ @user_class = args[0] || 'User'
14
+ @mount_path = args[1] || 'auth'
15
+ end
16
+
17
+ def install_user
18
+ model_file = "app/models/#{user_class.singularize.gsub('::', '').underscore}.rb"
19
+ template 'user.rb', model_file unless File.exist?(model_file)
20
+
21
+ migration_file = "devise_token_auth_create_#{user_class.pluralize.gsub('::', '').underscore}"
22
+ migration_template 'user_migration.rb', File.join('db', 'migrate', "#{migration_file}.rb") unless self.class.migration_exists?('db/migrate', migration_file)
23
+ end
24
+
25
+ def install_devise_token_auth
26
+ generate 'devise_token_auth:install', @user_class, @mount_path
27
+ config = <<~CONFIG
28
+
29
+ \s\s# Configure default URLs and redirects
30
+ \s\sconfig.default_confirm_success_url = 'http://localhost:3001/'
31
+ \s\sconfig.default_password_reset_url = 'http://localhost:3001/change-password'
32
+ \s\sconfig.redirect_whitelist = ['http://localhost:3001/*']
33
+
34
+ \s\s# If config.check_current_password_before_update is set to :attributes the
35
+ \s\s# current_password param is checked before any update, if it is set to
36
+ \s\s# :password the current_password param is checked only if the request
37
+ \s\s# updates user password. Default current_password is never checked.
38
+ \s\sconfig.check_current_password_before_update = :password
39
+ CONFIG
40
+ insert_into_file 'config/initializers/devise_token_auth.rb', config, before: /end$/
41
+ end
42
+
43
+ def install_routes
44
+ custom_routes = <<~ROUTES
45
+ , controllers: {
46
+ confirmations: 'next_on_rails/devise_token_auth_override/confirmations',
47
+ omniauth_callbacks: 'next_on_rails/devise_token_auth_override/omniauth_callbacks',
48
+ passwords: 'next_on_rails/devise_token_auth_override/passwords',
49
+ registrations: 'next_on_rails/devise_token_auth_override/registrations',
50
+ sessions: 'next_on_rails/devise_token_auth_override/sessions',
51
+ token_validations: 'next_on_rails/devise_token_auth_override/token_validations',
52
+ unlocks: 'next_on_rails/devise_token_auth_override/unlocks'
53
+ }
54
+ mount NextOnRails::Engine => '/'
55
+ ROUTES
56
+ insert_into_file 'config/routes.rb', custom_routes, after: "mount_devise_token_auth_for '#{@user_class}', at: '#{@mount_path}'"
57
+ end
58
+
59
+ def install_application_controller
60
+ remove_file 'app/controllers/application_controller.rb'
61
+ template 'application_controller.rb', 'app/controllers/application_controller.rb'
62
+ end
63
+
64
+ def install_devise_config
65
+ template File.join(Gem.loaded_specs['devise'].full_gem_path, 'lib/generators/templates/devise.rb'), 'config/initializers/devise.rb'
66
+ gsub_file 'config/initializers/devise.rb', "require 'devise/orm/'", "# require 'devise/orm/'" if File.exist?('config/initializers/devise.rb')
67
+ end
68
+
69
+ def install_cors_config
70
+ config = <<~CONFIG
71
+ Rails.application.config.middleware.insert_before 0, Rack::Cors do
72
+ allow do
73
+ origins 'localhost:3001'
74
+
75
+ resource '*',
76
+ headers: :any,
77
+ methods: [:get, :post, :put, :patch, :delete, :options, :head],
78
+ expose: [
79
+ DeviseTokenAuth.headers_names[:'access-token'],
80
+ DeviseTokenAuth.headers_names[:client],
81
+ DeviseTokenAuth.headers_names[:expiry],
82
+ DeviseTokenAuth.headers_names[:uid],
83
+ DeviseTokenAuth.headers_names[:'token-type']
84
+ ]
85
+ end
86
+ end
87
+ CONFIG
88
+ append_to_file 'config/initializers/cors.rb', config
89
+ end
90
+
91
+ def install_user_serializer
92
+ template 'user_serializer.rb', "app/serializers/#{@user_class.underscore}_serializer.rb"
93
+ template 'current_user_serializer.rb', "app/serializers/current_#{@user_class.underscore}_serializer.rb"
94
+ end
95
+
96
+ def remove_wrap_parameters
97
+ gsub_file 'config/initializers/wrap_parameters.rb', 'wrap_parameters format: [:json]', 'wrap_parameters format: []'
98
+ end
99
+
100
+ def setup_gems
101
+ gem_group :development do
102
+ gem 'foreman'
103
+ gem 'letter_opener'
104
+ end
105
+ template 'Procfile'
106
+ config = <<~CONFIG
107
+
108
+ \s\s# Mailer setup
109
+ \s\sconfig.action_mailer.preview_path = Rails.root.join('test', 'mailers', 'previews')
110
+ \s\sconfig.action_mailer.delivery_method = :letter_opener
111
+ \s\sconfig.action_mailer.raise_delivery_errors = true
112
+ \s\sconfig.action_mailer.default_url_options = { host: 'http://localhost:3000' }
113
+ CONFIG
114
+ insert_into_file 'config/environments/development.rb', config, before: /end$/
115
+ end
116
+
117
+ def self.next_migration_number(_path)
118
+ Time.zone.now.utc.strftime('%Y%m%d%H%M%S')
119
+ end
120
+
121
+ protected
122
+
123
+ def rails_api?
124
+ filename = 'config/application.rb'
125
+ str = 'config.api_only = true'
126
+ str.in?(File.read(filename))
127
+ end
128
+ end
129
+ end