Skip to content

Commit 510ac1e

Browse files
committed
Move schema mount login into separate class
1 parent c1f9570 commit 510ac1e

13 files changed

Lines changed: 226 additions & 84 deletions

config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@
1212
GraphqlDevise::Schema.query(GraphqlDevise::Types::QueryType)
1313

1414
GraphqlDevise.load_schema
15+
16+
Devise.mailer.helper(GraphqlDevise::MailerHelper)
1517
end
1618
end

lib/graphql_devise.rb

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,21 @@ def self.load_schema
1818
@schema_loaded = true
1919
end
2020

21-
def self.mount_resource(resource)
22-
@mounted_resources << resource
21+
def self.resource_mounted?(mapping_name)
22+
@mounted_resources.include?(mapping_name)
2323
end
2424

25-
def self.resource_mounted?(resource)
26-
@mounted_resources.include?(resource)
25+
def self.mount_resource(mapping_name)
26+
@mounted_resources << mapping_name
27+
end
28+
29+
def self.add_mapping(mapping_name, resource)
30+
return if Devise.mappings.key?(mapping_name)
31+
32+
Devise.add_mapping(
33+
mapping_name.to_s.pluralize.to_sym,
34+
module: :devise, class_name: resource
35+
)
2736
end
2837
end
2938

@@ -47,3 +56,6 @@ def self.resource_mounted?(resource)
4756
require 'graphql_devise/mount_method/options_validator'
4857
require 'graphql_devise/mount_method/operation_preparer'
4958
require 'graphql_devise/mount_method/operation_sanitizer'
59+
60+
require 'graphql_devise/resource_loader'
61+
require 'graphql_devise/schema_plugin'

lib/graphql_devise/mount_method/operation_preparer.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
module GraphqlDevise
99
module MountMethod
1010
class OperationPreparer
11-
def initialize(resource:, selected_operations:, preparer:, custom:, additional_operations:)
11+
def initialize(mapping_name:, selected_operations:, preparer:, custom:, additional_operations:)
1212
@selected_operations = selected_operations
1313
@preparer = preparer
14-
@mapping_name = resource.underscore.tr('/', '_')
14+
@mapping_name = mapping_name
1515
@custom = custom
1616
@additional_operations = additional_operations
1717
end

lib/graphql_devise/mount_method/operation_preparers/resource_name_setter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def initialize(name)
77
end
88

99
def call(operation)
10-
operation.instance_variable_set(:@resource_name, @name.to_sym)
10+
operation.instance_variable_set(:@resource_name, @name)
1111

1212
operation
1313
end

lib/graphql_devise/rails/routes.rb

Lines changed: 5 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,13 @@
11
module ActionDispatch::Routing
22
class Mapper
3-
DEVISE_OPERATIONS = [
4-
:sessions,
5-
:registrations,
6-
:passwords,
7-
:confirmations,
8-
:omniauth_callbacks,
9-
:unlocks,
10-
:invitations
11-
].freeze
12-
133
def mount_graphql_devise_for(resource, options = {})
14-
default_operations = GraphqlDevise::DefaultOperations::MUTATIONS.merge(GraphqlDevise::DefaultOperations::QUERIES)
15-
16-
# clean_options responds to all keys defined in GraphqlDevise::MountMethod::SUPPORTED_OPTIONS
17-
clean_options = GraphqlDevise::MountMethod::OptionSanitizer.new(options).call!
18-
19-
GraphqlDevise::MountMethod::OptionsValidator.new(
20-
[
21-
GraphqlDevise::MountMethod::OptionValidators::SkipOnlyValidator.new(options: clean_options),
22-
GraphqlDevise::MountMethod::OptionValidators::ProvidedOperationsValidator.new(
23-
options: clean_options, supported_operations: default_operations
24-
)
25-
]
26-
).validate!
27-
28-
devise_for(
29-
resource.pluralize.underscore.tr('/', '_').to_sym,
30-
module: :devise,
31-
class_name: resource,
32-
skip: DEVISE_OPERATIONS
4+
clean_options = GraphqlDevise::ResourceLoader.new(resource, options, true).call(
5+
GraphqlDevise::Types::QueryType,
6+
GraphqlDevise::Types::MutationType
337
)
348

35-
devise_scope resource.underscore.tr('/', '_').to_sym do
36-
post clean_options.at, to: 'graphql_devise/graphql#auth'
37-
get clean_options.at, to: 'graphql_devise/graphql#auth'
38-
end
39-
40-
# Avoid routes reload done by Devise
41-
return if GraphqlDevise.resource_mounted?(resource)
42-
43-
authenticatable_type = clean_options.authenticatable_type.presence ||
44-
"Types::#{resource}Type".safe_constantize ||
45-
GraphqlDevise::Types::AuthenticatableType
46-
47-
prepared_mutations = GraphqlDevise::MountMethod::OperationPreparer.new(
48-
resource: resource,
49-
custom: clean_options.operations,
50-
additional_operations: clean_options.additional_mutations,
51-
preparer: GraphqlDevise::MountMethod::OperationPreparers::MutationFieldSetter.new(authenticatable_type),
52-
selected_operations: GraphqlDevise::MountMethod::OperationSanitizer.call(
53-
default: GraphqlDevise::DefaultOperations::MUTATIONS, only: clean_options.only, skipped: clean_options.skip
54-
)
55-
).call
56-
57-
prepared_mutations.each do |action, mutation|
58-
GraphqlDevise::Types::MutationType.field(action, mutation: mutation)
59-
end
60-
61-
prepared_queries = GraphqlDevise::MountMethod::OperationPreparer.new(
62-
resource: resource,
63-
custom: clean_options.operations,
64-
additional_operations: clean_options.additional_queries,
65-
preparer: GraphqlDevise::MountMethod::OperationPreparers::ResolverTypeSetter.new(authenticatable_type),
66-
selected_operations: GraphqlDevise::MountMethod::OperationSanitizer.call(
67-
default: GraphqlDevise::DefaultOperations::QUERIES, only: clean_options.only, skipped: clean_options.skip
68-
)
69-
).call
70-
71-
prepared_queries.each do |action, resolver|
72-
GraphqlDevise::Types::QueryType.field(action, resolver: resolver)
73-
end
74-
75-
Devise.mailer.helper(GraphqlDevise::MailerHelper)
76-
77-
GraphqlDevise.mount_resource(resource)
9+
post clean_options.at, to: 'graphql_devise/graphql#auth'
10+
get clean_options.at, to: 'graphql_devise/graphql#auth'
7811
end
7912
end
8013
end
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
module GraphqlDevise
2+
class ResourceLoader
3+
def initialize(resource, options, routing = false)
4+
@resource = resource
5+
@options = options
6+
@routing = routing
7+
@default_operations = GraphqlDevise::DefaultOperations::MUTATIONS.merge(GraphqlDevise::DefaultOperations::QUERIES)
8+
end
9+
10+
def call(query, mutation)
11+
mapping_name = @resource.to_s.underscore.tr('/', '_').to_sym
12+
13+
# clean_options responds to all keys defined in GraphqlDevise::MountMethod::SUPPORTED_OPTIONS
14+
clean_options = GraphqlDevise::MountMethod::OptionSanitizer.new(@options).call!
15+
16+
return clean_options if GraphqlDevise.resource_mounted?(mapping_name) && @routing
17+
18+
validate_options!(clean_options)
19+
20+
authenticatable_type = clean_options.authenticatable_type.presence ||
21+
"Types::#{@resource}Type".safe_constantize ||
22+
GraphqlDevise::Types::AuthenticatableType
23+
24+
prepared_mutations = prepare_mutations(mapping_name, clean_options, authenticatable_type)
25+
26+
if prepared_mutations.any? && mutation.blank?
27+
raise GraphqlDevise::Error, 'You need to provide a mutation type unless all mutations are skipped'
28+
end
29+
30+
prepared_mutations.each do |action, prepared_mutation|
31+
mutation.field(action, mutation: prepared_mutation)
32+
end
33+
34+
prepared_resolvers = prepare_resolvers(mapping_name, clean_options, authenticatable_type)
35+
36+
prepared_resolvers.each do |action, resolver|
37+
query.field(action, resolver: resolver)
38+
end
39+
40+
GraphqlDevise.add_mapping(mapping_name, @resource)
41+
GraphqlDevise.mount_resource(mapping_name) if @routing
42+
43+
clean_options
44+
end
45+
46+
private
47+
48+
def prepare_resolvers(mapping_name, clean_options, authenticatable_type)
49+
GraphqlDevise::MountMethod::OperationPreparer.new(
50+
mapping_name: mapping_name,
51+
custom: clean_options.operations,
52+
additional_operations: clean_options.additional_queries,
53+
preparer: GraphqlDevise::MountMethod::OperationPreparers::ResolverTypeSetter.new(authenticatable_type),
54+
selected_operations: GraphqlDevise::MountMethod::OperationSanitizer.call(
55+
default: GraphqlDevise::DefaultOperations::QUERIES, only: clean_options.only, skipped: clean_options.skip
56+
)
57+
).call
58+
end
59+
60+
def prepare_mutations(mapping_name, clean_options, authenticatable_type)
61+
GraphqlDevise::MountMethod::OperationPreparer.new(
62+
mapping_name: mapping_name,
63+
custom: clean_options.operations,
64+
additional_operations: clean_options.additional_mutations,
65+
preparer: GraphqlDevise::MountMethod::OperationPreparers::MutationFieldSetter.new(authenticatable_type),
66+
selected_operations: GraphqlDevise::MountMethod::OperationSanitizer.call(
67+
default: GraphqlDevise::DefaultOperations::MUTATIONS, only: clean_options.only, skipped: clean_options.skip
68+
)
69+
).call
70+
end
71+
72+
def validate_options!(clean_options)
73+
GraphqlDevise::MountMethod::OptionsValidator.new(
74+
[
75+
GraphqlDevise::MountMethod::OptionValidators::SkipOnlyValidator.new(options: clean_options),
76+
GraphqlDevise::MountMethod::OptionValidators::ProvidedOperationsValidator.new(
77+
options: clean_options, supported_operations: @default_operations
78+
)
79+
]
80+
).validate!
81+
end
82+
end
83+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module GraphqlDevise
2+
class SchemaPlugin
3+
def initialize(query:, mutation: nil, resource_loaders: [])
4+
@query = query
5+
@mutation = mutation
6+
@resource_loaders = resource_loaders
7+
8+
# Must happen on initialize so operations are loaded before the types are added to the schema on GQL < 1.10
9+
load_fields
10+
end
11+
12+
private
13+
14+
def load_fields
15+
@resource_loaders.each do |resource_loader|
16+
raise Error, 'Invalid resource loader instance' unless resource_loader.instance_of?(GraphqlDevise::ResourceLoader)
17+
18+
resource_loader.call(@query, @mutation, false)
19+
end
20+
end
21+
end
22+
end

spec/services/mount_method/operation_preparer_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
describe '#call' do
55
subject(:prepared_operations) do
66
described_class.new(
7-
resource: resource,
7+
mapping_name: mapping,
88
selected_operations: selected,
99
preparer: preparer,
1010
custom: custom,
@@ -13,7 +13,7 @@
1313
end
1414

1515
let(:logout_class) { Class.new(GraphQL::Schema::Resolver) }
16-
let(:resource) { 'User' }
16+
let(:mapping) { :user }
1717
let(:selected) { { login: double(:login_default), logout: logout_class } }
1818
let(:preparer) { double(:preparer, call: logout_class) }
1919
let(:custom) { { login: double(:custom_login, graphql_name: nil) } }

spec/services/mount_method/operation_preparers/custom_operation_preparer_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
let(:login_operation) { double(:confirm_operation, graphql_name: nil) }
88
let(:logout_operation) { double(:sign_up_operation, graphql_name: nil) }
9-
let(:mapping_name) { 'user' }
9+
let(:mapping_name) { :user }
1010
let(:operations) { { login: login_operation, logout: logout_operation, invalid: double(:invalid) } }
1111
let(:selected_keys) { [:login, :logout, :sign_up, :confirm] }
1212

spec/services/mount_method/operation_preparers/default_operation_preparer_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
let(:sign_up_operation) { double(:sign_up_operation, graphql_name: nil) }
1010
let(:login_operation) { double(:confirm_operation, graphql_name: nil) }
1111
let(:logout_operation) { double(:sign_up_operation, graphql_name: nil) }
12-
let(:mapping_name) { 'user' }
12+
let(:mapping_name) { :user }
1313
let(:preparer) { double(:preparer) }
1414
let(:operations) { { login: login_operation, logout: logout_operation, sign_up: sign_up_operation, confirm: confirm_operation } }
1515
let(:custom_keys) { [:login, :logout] }

0 commit comments

Comments
 (0)