GithubHelp home page GithubHelp logo

graphql-devise / graphql_devise Goto Github PK

View Code? Open in Web Editor NEW
190.0 8.0 36.0 609 KB

GraphQL interface on top devise_token_auth

License: MIT License

Ruby 99.43% Shell 0.06% HTML 0.50%
graphql devise devise-token-auth rails dta graphql-interface api api-server activerecord gem

graphql_devise's Introduction

GraphqlDevise

Build Status Coverage Status Gem Version

GraphQL interface on top of the Devise Token Auth (DTA) gem.

Table of Contents

Introduction

Graphql-Devise heavily relies on 3 gems:

This gem provides a GraphQL interface on top of DTA which is designed for REST APIs. Features like token management, token expiration and everything up until using the actual GraphQL schema is still controlled by DTA. For that reason the gem's generator invokes DTA and Devise generators and creates initializer files for each one of them.

We strongly recommend getting familiar with DTA documentation to use this gem to its full potential. More configuration details available in configuration section

Installation

Add this line to your application's Gemfile:

gem 'graphql_devise'

And then execute:

$ bundle

Running the Generator

Graphql Devise generator will execute Devise and Devise Token Auth generators to setup the gems in your project. You can customize them to your needs using their initializer files(one per gem) as usual.

$ bundle exec rails generate graphql_devise:install

The generator accepts 2 params and 1 option:

  • user_class: Model name in which Devise modules will be included. This uses a find or create strategy. Defaults to User.
  • mount_path: Path in which the dedicated graphql schema for devise will be mounted. Defaults to /graphql_auth.
  • --mount: This options is available starting from v0.12.0, it allows you to mount the operations in your own schema instead of a dedicated one. When provided mount_path param is ignored.

Mounting the Schema in a Separate Route

To configure the gem to use a separate schema, the generator will use user_class and mount_path params. The route will be mounted in config/routes.rb. For instance the executing:

$ bundle exec rails g graphql_devise:install Admin api/auth

Will do the following:

  • Execute Devise install generator
  • Execute Devise Token Auth install generator with Admin and api/auth as params
    • Find or create Admin model
    • Add devise modules to Admin model
    • Other changes that you can find here
  • Add the route to config/routes.rb
    • mount_graphql_devise_for Admin, at: 'api/auth'

Admin could be any model name you are going to be using for authentication, and api/auth could be any mount path you would like to use for auth.

Important

  • Remember that by default this gem mounts a completely separate GraphQL schema on a separate controller in the route provided by the at option in the mount_graphql_devise_for method in the config/routes.rb file. If no at option is provided, the route will be /graphql_auth.
  • Avoid passing the --mount option if you want to use a separate route and schema.

Mounting Operations in an Existing Schema (> v0.12.0)

To configure the gem to use an existing GQL schema use the --mount option. For instance the executing:

$ bundle exec rails g graphql_devise:install Admin --mount MySchema

Will do the following:

  • Execute Devise install generator
  • Execute Devise Token Auth install generator with Admin and api/auth as params
    • Find or create Admin model
    • Add devise modules to Admin model
    • Other changes that you can find here
    • Add SchemaPlugin to the specified schema.

Important

  • When using the --mount option the mount_path param is ignored.
  • The generator will look for your schema under app/graphql/ directory. We are expecting the name of the file is the same as the as the one passed in the mount option transformed with underscore. In the example, passing MySchema, will try to find the file app/graphql/my_schema.rb.
  • You can actually mount a resource's auth schema in a separate route and in your app's schema at the same time, but that's probably not a common scenario.

Usage

GraphqlDevise operations can be used in two ways:

Creating a separate schema is the default option, the generator will do that by default.

Mounting Auth Schema on a Separate Route

You can mount this gem's GraphQL auth schema in your routes file like this:

# config/routes.rb

Rails.application.routes.draw do
  mount_graphql_devise_for(
    User,
    at: 'api/v1',
    authenticatable_type: Types::MyCustomUserType,
    operations: {
      login: Mutations::Login
    },
    skip: [:register],
    # optional, use only if you need a specific base controller to mount the new actions
    base_controller: ApiController,
    additional_mutations: {
      # generates mutation { adminUserSignUp }
      admin_user_sign_up: Mutations::AdminUserSignUp
    },
    additional_queries: {
      # generates query { publicUserByUuid }
      public_user_by_uuid: Resolvers::UserByUuid
    }
  )
end

This can be done using the generator or manually. The second argument of the mount_graphql_devise method is a hash of options where you can customize how the queries and mutations are mounted into the schema. For a list of available options go here

Mounting Operations In an Existing Schema

Starting with v0.12.0 you can mount the GQL operations provided by this gem into an existing schema in your app.

# app/graphql/dummy_schema.rb

class DummySchema < GraphQL::Schema
  # It's important that this line goes before setting the query and mutation type on your
  # schema in graphql versions < 1.10.0
  use GraphqlDevise::SchemaPlugin.new(
    query:            Types::QueryType,
    mutation:         Types::MutationType,
    resource_loaders: [
      GraphqlDevise::ResourceLoader.new(User, only: [:login, :confirm_registration_with_token])
    ]
  )

  mutation(Types::MutationType)
  query(Types::QueryType)
end

The example above describes just one of the possible scenarios you might need. The second argument of the GraphqlDevise::ResourceLoader initializer is a hash of options where you can customize how the queries and mutations are mounted into the schema. For a list of available options go here.

It's important to use the plugin in your schema before assigning the mutation and query type to it in graphql versions < 1.10.0. Otherwise the auth operations won't be available.

You can provide as many resource loaders as you need to the resource_loaders option, and each of those will be loaded into your schema. These are the options you can initialize the SchemaPlugin with:

  1. query: This param is mandatory unless you skip all queries via the resource loader options. This should be the same QueryType you provide to the query method in your schema.
  2. mutation: This param mandatory unless you skip all mutations via the resource loader options. This should be the same MutationType you provide to the mutation method in your schema.
  3. resource_loaders: This is an optional array of GraphqlDevise::ResourceLoader instances. Here is where you specify the operations that you want to load into your app's schema. If no loader is provided, no operations will be added to your schema, but you will still be able to authenticate queries and mutations selectively. More on this in the controller authentication section.
  4. authenticate_default: This is a boolean value which is true by default. This value defines what is the default behavior for authentication in your schema fields. true means every root level field requires authentication unless specified otherwise using the authenticate: false option on the field. false means your root level fields won't require authentication unless specified otherwise using the authenticate: true option on the field.
  5. unauthenticated_proc: This param is optional. Here you can provide a proc that receives one argument (field name) and is called whenever a field that requires authentication is called without an authenticated resource. By default a GraphQL::ExecutionError will be raised if authentication fails. This will provide a GQL like error message on the response.
  6. public_introspection: The introspection query is a very useful GQL resource that provides information about what queries the schema supports. This query is very powerful and there may be some case in which you want to limit its usage to authenticated users. To accomplish this the schema plugin provides the public_introspection option. This option accepts a boolean value and by default will consider introspection queries public in all environments but production.

Available Mount Options

Both the mount_graphql_devise_for method and the GraphqlDevise::ResourceLoader class take the same options. So, wether you decide to mount this gem in a separate route from your main application's schema or you use our GraphqlDevise::SchemaPlugin to load this gem's auth operation into your schema, these are the options you can provide as a hash.

# Using the mount method in your config/routes.rb file
mount_graphql_devise_for(User, {})

# Providing options to a GraphqlDevise::ResourceLoader
GraphqlDevise::ResourceLoader.new(User, {})
  1. at: Route where the GraphQL schema will be mounted on the Rails server. In this example your API will have these two routes: POST /api/v1/graphql_auth and GET /api/v1/graphql_auth. If this option is not specified, the schema will be mounted at /graphql_auth. This option only works if you are using the mount method.
  2. operations: Specifying this is optional. Here you can override default behavior by specifying your own mutations and queries for every GraphQL operation. Check available operations in this file mutations and queries. All mutations and queries are built so you can extend default behavior just by extending our default classes and yielding your customized code after calling super, example here.
  3. authenticatable_type: By default, the gem will add an authenticatable field to every mutation and an authenticatable type to every query. Gem will try to use Types::<model>Type by default, so in our example you could define Types::UserType and every query and mutation will use it. But, you can override this type with this option like in the example.
  4. base_controller: Specifying this is optional. By default the controller used to mount the route is GraphqlDevise::ApplicationController which inherits from ActionController::API or ActionController::Base depending on the rails version of the main project. This option allows you to set the controller used as the parent of the controller where the route will be mounted. This config is similar to Devise's base_controller config but in this case each route can have a different parent controller. This option only works if you are using the mount method.
  5. skip: An array of the operations that should not be available in the authentication schema. All these operations are symbols and should belong to the list of available operations in the gem.
  6. only: An array of the operations that should be available in the authentication schema. The skip and only options are mutually exclusive, an error will be raised if you pass both to the mount method.
  7. additional_mutations: Here you can add as many mutations as you need, for those features that don't fully match the provided default mutations and queries. You need to provide a hash to this option, and each key will be the name of the mutation on the schema. Also, the value provided must be a valid mutation. This is similar to what you can accomplish with devise_scope.
  8. additional_queries: Here you can add as many queries as you need, for those features that don't fully match the provided default mutations and queries. You need to provide a hash to this option, and each key will be the name of the query on the schema. Also, the value provided must be a valid Resolver. This is also similar to what you can accomplish with devise_scope.

Additional mutations and queries will be added to the schema regardless of other options you might have specified like skip or only. Additional queries and mutations is usually a good place for other operations on your schema that require no authentication (like sign_up). Also by adding them through the mount method, your mutations and resolvers can inherit from our base mutation or base resolver respectively, to take advantage of some of the methods provided by devise just like with devise_scope

Available Operations

The following is a list of the symbols you can provide to the operations, skip and only options of the mount method:

:login
:logout
:register
:update_password_with_token
:send_password_reset_with_token
:resend_confirmation_with_token
:confirm_registration_with_token

Configuring Model

Just like with Devise and DTA, you need to include a module in your authenticatable model, so with our example, your user model will have to look like this:

# app/models/user.rb

class User < ApplicationRecord
  devise :database_authenticatable,
         :registerable,
         :recoverable,
         :rememberable,
         :trackable,
         :lockable,
         :validatable,
         :confirmable

  # including after calling the `devise` method is important.
  include GraphqlDevise::Authenticatable
end

The install generator can do this for you if you specify the user_class option. See Installation for details.

Email Reconfirmation

We want reconfirmable in this gem to work separately from DTA's or Devise (too much complexity in the model based on callbacks).

Email reconfirmation is supported just like in Devise and DTA, but we want reconfirmable in this gem to work on model basis instead of having a global configuration like in Devise. For this reason Devise's global reconfirmable setting is ignored.

For a resource to be considered reconfirmable it has to meet 2 conditions:

  1. Include the :confirmable module.
  2. Has an unconfirmed_email column in the resource's table.

In order to trigger the reconfirmation email in a reconfirmable resource, you simply need to call a different update method on your resource,update_with_email. When the resource is not reconfirmable or the email is not updated, this method behaves exactly the same as ActiveRecord's update.

Current flow

update_with_email requires one additional attribute when email will change or an error will be raised:

  • confirmation_url: The full url of your client application. The confirmation email will contain this url plus a confirmation token. You need to call confirmRegistrationWithToken with the given token on your client application.

So, it's up to you where you require confirmation of changing emails. Here's a demonstration on the method usage:

user.update_with_email(
  name:             'New Name',
  email:            '[email protected]',
  confirmation_url: 'https://google.com'
)

Customizing Email Templates

The approach of this gem is a bit different from DeviseTokenAuth. We have placed our templates in app/views/graphql_devise/mailer, so if you want to change them, place yours on the same dir structure on your Rails project. You can customize these two templates:

  1. app/views/graphql_devise/mailer/confirmation_instructions.html.erb
  2. app/views/graphql_devise/mailer/reset_password_instructions.html.erb

The main reason for this difference is just to make it easier to have both Standard Devise and this gem running at the same time. Check these files to see the available helper methods you can use in your views.

I18n

GraphQL Devise supports locales. For example, the graphql_devise.confirmations.send_instructions locale setting supports the %{email} variable in case you would like to include it in the resend confirmation instructions for the user. Take a look at our locale file to see all of the available messages.

Keep in mind that if your app uses multiple locales, you should set the I18n.locale accordingly. You can learn how to do this here.

Authenticating Controller Actions

When mounting the operation is in you own schema instead of a dedicated one, you will need to authenticate users in your controllers, just like in DTA. There are 2 alternatives to accomplish this.

Authenticate Resource in the Controller (>= v0.15.0)

This authentication mechanism sets the resource by token in the controller, or it doesn't if credentials are invalid. You simply need to pass the return value of our gql_devise_context method in the context of your GQL schema execution like this:

# app/controllers/my_controller.rb

class MyController < ApplicationController
  include GraphqlDevise::SetUserByToken

  def my_action
    result = DummySchema.execute(params[:query], context: gql_devise_context(User))
    render json: result unless performed?
  end
end

gql_devise_context receives as many models as you need to authenticate in the request, like this:

# app/controllers/my_controller.rb

class MyController < ApplicationController
  include GraphqlDevise::SetUserByToken

  def my_action
    result = DummySchema.execute(params[:query], context: gql_devise_context(User, Admin))
    render json: result unless performed?
  end
end

Internally in your own mutations and queries a key current_resource will be available in the context if a resource was successfully authenticated or nil otherwise.

Keep in mind that sending multiple models to the gql_devise_context method means that depending on who makes the request, the context value current_resource might contain instances of the different models you provided.

Note: If for any reason you need more control over how users are authenticated, you can use the authenticate_model method anywhere in your controller. The method will return the authenticated resource or nil if authentication fails. It will also set the instance variable @resource in the controller.

Please note that by using this mechanism your GQL schema will be in control of what queries are restricted to authenticated users and you can only do this at the root level fields of your GQL schema. Configure the plugin as explained here so this can work.

Authentication Options

Whether you setup authentications as a default in the plugin, or you do it at the field level, these are the options you can use:

  1. Any truthy value: If current_resource is not .present?, query will return an authentication error.
  2. A callable object: Provided object will be called with current_resource as the only argument if current_resource is .present?. If return value of the callable object is false, query will return an authentication error.

In your main app's schema this is how you might specify if a field needs to be authenticated or not:

module Types
  class QueryType < Types::BaseObject
    # user field used the default set in the Plugin's initializer
    field :user, resolver: Resolvers::UserShow
    # this field will never require authentication
    field :public_field, String, null: false, authenticate: false
    # this field requires authentication
    field :private_field, String, null: false, authenticate: true
    # this field requires authenticated users to also be admins
    field :admin_field, String, null: false, authenticate: ->(user) { user.admin? }
  end
end

Making Requests

Here is a list of the available mutations and queries assuming your mounted model is User.

Introspection query

If you are using the schema plugin, you can require authentication before doing an introspection query by modifying the public_introspection option of the plugin. Check the plugin config section for more information.

Mutations

Operation Description Example
login This mutation has a second field by default. credentials can be fetched directly on the mutation return type.
Credentials are still returned in the headers of the response.
userLogin(email: String!, password: String!): UserLoginPayload
logout requires authentication headers. Deletes current session if successful. userLogout: UserLogoutPayload
register The parameter confirmUrl is optional unless you are using the confirmable plugin from Devise in your resource's model. If you have confirmable set up, you will have to provide it unless you have config.default_confirm_success_url set in config/initializers/devise_token_auth.rb. userRegister(email: String!, password: String!, passwordConfirmation: String!, confirmUrl: String): UserRegisterPayload
sendPasswordResetWithToken Sends an email to the provided address with a link to reset the password of the resource. First step of the most recently implemented password reset flow. userSendPasswordResetWithToken(email: String!, redirectUrl: String!): UserSendPasswordResetWithTokenPayload
updatePasswordWithToken Uses a resetPasswordToken to update the password of a resource. Second and last step of the most recently implemented password reset flow. userSendPasswordResetWithToken(resetPasswordToken: String!, password: String!, passwordConfirmation: String!): UserUpdatePasswordWithTokenPayload
resendConfirmationWithToken The UserResendConfirmationWithTokenPayload will return a message: String! that can be used to notify a user what to do after the instructions were sent to them. Email will contain a link to the provided confirmUrl and a confirmationToken query param. userResendConfirmationWithToken(email: String!, confirmUrl: String!): UserResendConfirmationWithTokenPayload

Reset Password Flow

This gem supports two password recovery flows. The most recently implemented is preferred and requires less steps. More detail on how it works can be found here.

More Configuration Options

As mentioned in the introduction there are many configurations that will change how this gem behaves. You can change this values on the initializer files generated by the installer.

Devise Token Auth Initializer

The generated initializer file config/initializers/devise_token_auth.rb has all the available options documented as comments. You can also use DTA's docs as a reference. In this section the most important configurations will be highlighted.

  • change_headers_on_each_request: This configurations defaults to false. This will allow you to store the credentials for as long as the token life_span permits. And you can send the same credentials in each request. Setting this to true means that tokens will change on each request you make, and the new values will be returned in the headers. So your client needs to handle this.
  • batch_request_buffer_throttle: When change_headers_on_each_request is set to true, you might still want your credentials to be valid more than once as you might send parallel request. The duration you set here will determine how long the same credentials work after the first request is received.
  • token_lifespan: This configuration takes a duration and you can set it to a value like 1.month, 2.weeks, 1.hour, etc.

Note: Remember this gem adds a layer on top of DTA, so some configurations might not apply.

Devise Initializer

The generated initializer file config/initializers/devise_token_auth.rb has all the available options documented as comments. You can also use Devise's docs as a reference. In this section the most important configurations will be highlighted.

  • password_length: You can change this value to validate password length on sign up and password update (must enable the validatable module).
  • mailer_sender: Set it to a string with the sender's email address like '[email protected]'.
  • case_insensitive_keys: Setting a value like [:email] will make email field case insensitive on login, sign up, etc.
  • email_regexp: You can customize the regex that will validate the format of email addresses (must enable the validatable module).

Note: Remember this gem adds a layer on top of Devise, so some configurations might not apply.

GraphQL 2.0 Support (>= v1.0.0)

This gem now supports GraphQL Ruby v2. There's one manual step you need to take in order for this to work.

You need a custom field_class in your MutationType and QueryType. If you don't have one setup already, you can simply add the one this gem provides, like this:

module Types
  class MutationType < BaseObject
    field_class GraphqlDevise::Types::BaseField
  end
end

module Types
  class QueryType < Types::BaseObject
    field_class GraphqlDevise::Types::BaseField
  end
end

If you already have a field_class defined in any of your types, the only thing you need to do is add another kwarg to that class initializer (authenticate) and make that value available through an attribute reader.

The next example is this gem's implementation of a custom class, but you can implement your own however you see fit as long as you expose an authenticate public method with the value that was passed to the initializer.

module GraphqlDevise
  module Types
    class BaseField < GraphQL::Schema::Field
      def initialize(*args, authenticate: nil, **kwargs, &block)
        @authenticate = authenticate
        super(*args, **kwargs, &block)
      end

      attr_reader :authenticate
    end
  end
end

GraphQL Interpreter

GraphQL-Ruby >= 1.9.0 includes a new runtime module which you may use for your schema. Eventually, it will become the default. You can read more about it here.

This gem supports schemas using the interpreter and it is recommended as it introduces several improvements which focus mainly on performance.

Using Alongside Standard Devise

The DeviseTokenAuth gem allows experimental use of the standard Devise gem to be configured at the same time, for more information you can check this answer here.

This gem supports the same and should be easier to handle email templates due to the fact we don't override standard Devise templates.

Changelog

Full list of changes in CHANGELOG.md

Future Work

We will continue to improve the gem and add better docs.

  1. Make sure this gem can correctly work alongside DTA and the original Devise gem.
  2. Improve DOCS.
  3. Add support for unlockable and other Devise modules.
  4. Add feature specs for confirm account and reset password flows.

We will continue to build better docs for the gem after this first release, but in the mean time you can use our specs to better understand how to use the gem. Also, the dummy app used in our specs will give you a clear idea on how to configure the gem on your Rails application.

Buy Us a Coffee

If you'd like to support our work, you are welcome to do so!

BTC
bc1qntlmyl24wuf6y5jyn2vg8kduss57dwtyrcflyq
ADA
addr1q8e8cjzutzptcrfgjgsjl3k4t4xy5ucrmkf2dmq9qn966q8saucty53avujfc9yu9vfk7266auhdx9fz4fsryzeagqds893nfw

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/graphql-devise/graphql_devise.

License

The gem is available as open source under the terms of the MIT License.

graphql_devise's People

Contributors

00dav00 avatar aarona avatar artplan1 avatar celsomartins avatar dlederle avatar j15e avatar janraasch avatar jpmermoz avatar lagtag avatar mathiaspfeil avatar mcelicalderon avatar mengqing avatar tomasbarry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql_devise's Issues

CookieOverflow for Own Schema Mount

Describe the bug

When using the own schema mount option, our session cookie overflows. This happened immediately after I removed the routes.rb mount option. This is due to the value being saved in the session for 'warden.user.user.key' to be the entire object rather than some string or integer.

Screen Shot 2020-06-22 at 7 32 28 PM

Environment

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.6'

gem 'rails', '~> 6.0.3', '>= 6.0.3.1'

gem 'activeadmin', '~> 2.7.0'
gem 'activeadmin_quill_editor', '~> 0.2.0'
gem 'arctic_admin', '~> 3.2.0'
gem 'bootsnap', '>= 1.4.2', require: false
gem 'graphiql-rails', '~> 1.7.0'
gem 'graphql', '~> 1.10.13'
gem 'graphql_devise', '~> 0.12.3'
gem 'html2text', '~> 0.3.1'
gem 'money-rails', '~>1.13.3'
gem 'pg', '>= 0.18', '< 2.0'
gem 'puma', '~> 4.1'
gem 'pundit', '~> 2.1.0'
gem 'rack-cors', '~> 1.1.1'
gem 'state_machines-activerecord', '~> 0.6.0'

group :development, :test do
  gem 'byebug', platforms: %i[mri mingw x64_mingw]
  gem 'factory_bot_rails', '~> 5.2.0'
  gem 'faker', '~> 2.12'
  gem 'pry', '~> 0.13.1'
  gem 'rspec-rails', '~> 4.0.1'
end

group :development do
  gem 'listen', '~> 3.2'
  gem 'rubocop', '~> 0.83.0', require: false
  gem 'rubocop-rails', '~> 2.5.2', require: false
  gem 'rubocop-rspec', '~> 1.39.0', require: false
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

Steps to reproduce

  1. Use the schema mount option for this gem. Don't mix both. Putting the routes mount option back, fixes the issue.
  2. Make sure to do the graphql_context(:user) to authenticate the user.
  3. Try any authenticated query/mutation and it should raise a cookieoverflow error.

Expected behavior

It should just return something like this when accessing the session object, instead of putting the entire activerecord object.

{"session_id"=>"a7e8a69beb3f5b1bf4aa2edec48cd46a", "warden.user.user.key"=>[[104], "$2a$04$mH7drnwTc.3gqJt4YMmXb."]}

Actual behavior

It returned the entire object instead of just an id and some key.

Screen Shot 2020-06-22 at 7 32 28 PM

Reproducible demo

Tried using the dummy app found in the gem. Here are the steps I did to reproduce the problem:

  1. Comment these lines from the routes file:
mount_graphql_devise_for 'User', at: '/api/v1/graphql_auth', operations: {
    login:   Mutations::Login,
    sign_up: Mutations::SignUp
  }, additional_mutations: {
    register_confirmed_user: Mutations::RegisterConfirmedUser
  }, additional_queries: {
    public_user: Resolvers::PublicUser
  }

This would essentially make the User resource to be solely mounted in the graphql schema only.
2. Add :logout in the User resource loader in the dummy schema file. This will be used for the demo.
3. Change the post request for the logout spec to use the 'graphql' schema instead of the default 'graphql_auth' one.
4. Put a binding.pry first line in the resolve function for the logout mutation and check for controller.session.to_h

Error when including this gem's controller concern

Describe the bug

When using GraphqlDevise::Concerns::SetUserByToken we get a included called twice error from activesupport. Using DTA's DeviseTokenAuth::Concerns::SetUserByToken fixes the problem. Good thing that the generators use that one, so it shouldn't be a problem for now, but we should still look into that

Is the gem ready for production of react-native apps?

Question

During the setup procedure of this gem, I happen to encounter loads of path redirects.
However, the userLogin response didn't even have a token provided.
So, It would be helpful if there's a little demo app for react-native.

Devise doesn't use I18n references in its confirmation mailer. Should we?

What is the problem the enhancement will solve?

If I understand correctly, we want to mimic a lot of Devise's core functionality. When I took on the Resend Confirmation enhancement, I had noticed we were using i18n references in the app/views/mailer/confirmation_instructions.html.erb file. I added them to the gem's locale file but it looks like Devise doesn't do this. Consider the following two files:

https://github.com/plataformatec/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/app/views/devise/mailer/confirmation_instructions.html.erb
https://github.com/plataformatec/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/lib/generators/templates/markerb/confirmation_instructions.markerb

Describe the solution you have in mind

I would like a consensus on how we should solve this. Should we follow the direction that Devise went with or should we use i18n in our mailers? I feel like this could be an improvement if we did this but at the same time, people usually create their own specialized mailer views if they're making a professional application. Although, that doesn't mean they won't need i18n presets. WDYT?

graphql dual endpoint integration problem

Question

71514019-d384d900-28d7-11ea-8363-f480201caf41

I have /auth and the typical /graphql endpoints.
I use apollo with react-native.

The problem is that when I use the /auth the endpoint to login and it's successful,
however, when I try to use the /graphql endpoint to fetch data, the app just got refreshed and logged out with the /auth endpoint.

const jclient = new ApolloClient({
  link: 'http://localhost:3000/graphql',
  cache: new InMemoryCache(),
});

const {loading, error, data} = useQuery(GET_DOGS, {
  client: jclient,
});

So, I wonder if it's right to use two endpoints for graphql.

Thanks.

How to call userLogout?

Question

Hi folks.

Mutation userLogout seems to doesn't have arguments. How I call this from cURL, for example?

I have tried first
curl http://localhost:3001/graphql -H 'Content-Type: application/json' -H 'accept: application/json' -H 'access-token: Lu80OieoLgdWY7RjaW0Oxg' -H 'client: GjCBl8F5QA2e8phBWS4v1Q' -H 'uid: [email protected]' -d '{"query": "mutation { userLogout(input: {variables: {}}) { authenticatable { email } } }" }'

and tried later
curl http://localhost:3001/graphql -H 'Content-Type: application/json' -H 'accept: application/json' -H 'access-token: Lu80OieoLgdWY7RjaW0Oxg' -H 'client: GjCBl8F5QA2e8phBWS4v1Q' -H 'uid: [email protected]' -d '{"query": "mutation { userLogout(input: {}) { authenticatable { email } } }" }'

and this too
curl http://localhost:3001/graphql -H 'Content-Type: application/json' -H 'accept: application/json' -H 'access-token: Lu80OieoLgdWY7RjaW0Oxg' -H 'client: GjCBl8F5QA2e8phBWS4v1Q' -H 'uid: [email protected]' -d '{"query": "mutation { userLogout { authenticatable { email } } }" }'

But the return is always the same: {"errors":[{"message":"No query string was present"}]}

Thank You.

"Unexpected parent_type" error on userConfirmAccount query

Describe the bug

I have been trying out this gem for the last couple of days and so far it's been awesome, so thanks for the great work!

Trying out the userConfirmAccount flow, I get:

Completed 500 Internal Server Error in 5027ms (ActiveRecord: 0.0ms | Allocations: 54116)

RuntimeError (Unexpected parent_type: ):
  
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:525:in `block in get_field'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:1953:in `with_definition_error_check'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:518:in `get_field'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/base_visitor.rb:97:in `on_field'
.....

I kept digging and found that this happened with the Dummy query too. Not sure if it might be environment related?

Environment

Gemfile
Gemfile.lock

(paste the link(s) to the Gemfile and Gemfile.lock files.)

Steps to reproduce

  1. Include gem and mount the routes
  2. Create a user
  3. Try to confirm the user via the link in the email (or the query)

Expected behavior

Redirect to the redirectUrl.

Actual behavior

500 error:

RuntimeError (Unexpected parent_type: ):
  
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:525:in `block in get_field'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:1953:in `with_definition_error_check'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:518:in `get_field'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/base_visitor.rb:97:in `on_field'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:79:in `public_send'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:79:in `visit_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:174:in `on_node_with_modifications'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:102:in `block in on_abstract_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:101:in `each'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:101:in `on_abstract_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:123:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/definition_dependencies.rb:47:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/subscription_root_exists.rb:12:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/mutation_root_exists.rb:12:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb:13:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb:44:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/variable_names_are_unique.rb:20:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb:18:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/fields_will_merge.rb:24:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/operation_names_are_valid.rb:12:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/unique_directives_per_location.rb:27:in `block (2 levels) in <module:UniqueDirectivesPerLocation>'
/home/mateo/Proyects/graphql-ruby/lib/graphql/internal_representation/rewrite.rb:68:in `block in on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/internal_representation/rewrite.rb:92:in `push_root_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/internal_representation/rewrite.rb:68:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/base_visitor.rb:76:in `on_operation_definition'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:79:in `public_send'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:79:in `visit_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:174:in `on_node_with_modifications'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:102:in `block in on_abstract_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:101:in `each'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:101:in `on_abstract_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:123:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/definition_dependencies.rb:38:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb:79:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb:26:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/fragments_are_used.rb:6:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/fragments_are_finite.rb:6:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/fragment_names_are_unique.rb:17:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/operation_names_are_valid.rb:16:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/rules/no_definitions_are_present.rb:34:in `on_document'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:79:in `public_send'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:79:in `visit_node'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:174:in `on_node_with_modifications'
/home/mateo/Proyects/graphql-ruby/lib/graphql/language/visitor.rb:68:in `visit'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/validator.rb:42:in `block in validate'
/home/mateo/Proyects/graphql-ruby/lib/graphql/tracing.rb:67:in `trace'
/home/mateo/Proyects/graphql-ruby/lib/graphql/static_validation/validator.rb:25:in `validate'
/home/mateo/Proyects/graphql-ruby/lib/graphql/query/validation_pipeline.rb:75:in `ensure_has_validated'
/home/mateo/Proyects/graphql-ruby/lib/graphql/query/validation_pipeline.rb:47:in `internal_representation'
/home/mateo/.rbenv/versions/2.6.2/lib/ruby/2.6.0/forwardable.rb:230:in `internal_representation'
/home/mateo/Proyects/graphql-ruby/lib/graphql/query.rb:236:in `irep_selection'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema/member/instrumentation.rb:22:in `before_query'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:58:in `public_send'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:58:in `block in call_hooks'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:57:in `each'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:57:in `call_hooks'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:44:in `each_query_call_hooks'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:27:in `block in apply_instrumenters'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:72:in `call_hooks'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/instrumentation.rb:26:in `apply_instrumenters'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/multiplex.rb:175:in `instrument_and_analyze'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/multiplex.rb:61:in `block in run_queries'
/home/mateo/Proyects/graphql-ruby/lib/graphql/tracing.rb:67:in `trace'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/multiplex.rb:59:in `run_queries'
/home/mateo/Proyects/graphql-ruby/lib/graphql/execution/multiplex.rb:49:in `run_all'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:1633:in `multiplex'
/home/mateo/Proyects/graphql-ruby/lib/graphql/schema.rb:1604:in `execute'
/home/mateo/Proyects/graphql_devise/app/controllers/graphql_devise/graphql_controller.rb:13:in `auth'
actionpack (6.0.2.2) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (6.0.2.2) lib/abstract_controller/base.rb:196:in `process_action'
actionpack (6.0.2.2) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (6.0.2.2) lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport (6.0.2.2) lib/active_support/callbacks.rb:135:in `run_callbacks'
actionpack (6.0.2.2) lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack (6.0.2.2) lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack (6.0.2.2) lib/action_controller/metal/instrumentation.rb:33:in `block in process_action'
activesupport (6.0.2.2) lib/active_support/notifications.rb:180:in `block in instrument'
activesupport (6.0.2.2) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (6.0.2.2) lib/active_support/notifications.rb:180:in `instrument'
actionpack (6.0.2.2) lib/action_controller/metal/instrumentation.rb:32:in `process_action'
actionpack (6.0.2.2) lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord (6.0.2.2) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack (6.0.2.2) lib/abstract_controller/base.rb:136:in `process'
actionpack (6.0.2.2) lib/action_controller/metal.rb:191:in `dispatch'
actionpack (6.0.2.2) lib/action_controller/metal.rb:252:in `dispatch'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:51:in `dispatch'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/routing/mapper.rb:18:in `block in <class:Constraints>'
actionpack (6.0.2.2) lib/action_dispatch/routing/mapper.rb:48:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:837:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/rack/agent_hooks.rb:30:in `traced_call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/rack/browser_monitoring.rb:33:in `traced_call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
warden (1.2.8) lib/warden/manager.rb:36:in `block in call'
warden (1.2.8) lib/warden/manager.rb:34:in `catch'
warden (1.2.8) lib/warden/manager.rb:34:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rack (2.2.2) lib/rack/etag.rb:27:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rack (2.2.2) lib/rack/conditional_get.rb:27:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rack (2.2.2) lib/rack/head.rb:12:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
activerecord (6.0.2.2) lib/active_record/migration.rb:567:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.0.2.2) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (6.0.2.2) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/executor.rb:14:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rollbar (2.25.0) lib/rollbar/middleware/rails/rollbar.rb:25:in `block in call'
rollbar (2.25.0) lib/rollbar.rb:145:in `scoped'
rollbar (2.25.0) lib/rollbar/middleware/rails/rollbar.rb:22:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
rollbar (2.25.0) lib/rollbar/middleware/rails/show_exceptions.rb:22:in `call_with_rollbar'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
railties (6.0.2.2) lib/rails/rack/logger.rb:38:in `call_app'
railties (6.0.2.2) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.2.2) lib/rails/rack/logger.rb:26:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/request_id.rb:27:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rack (2.2.2) lib/rack/runtime.rb:22:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
activesupport (6.0.2.2) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/executor.rb:14:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/static.rb:126:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rack (2.2.2) lib/rack/sendfile.rb:110:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/host_authorization.rb:83:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
rack-cors (1.1.1) lib/rack/cors.rb:100:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
railties (6.0.2.2) lib/rails/engine.rb:526:in `call'
newrelic_rpm (6.10.0.364) lib/new_relic/agent/instrumentation/middleware_tracing.rb:99:in `call'
puma (4.3.3) lib/puma/configuration.rb:228:in `call'
puma (4.3.3) lib/puma/server.rb:682:in `handle_request'
puma (4.3.3) lib/puma/server.rb:472:in `process_client'
puma (4.3.3) lib/puma/server.rb:328:in `block in run'
puma (4.3.3) lib/puma/thread_pool.rb:134:in `block in spawn_thread'

Reproducible demo

(Paste the link to an example project and exact instructions to reproduce the issue.)

Resend verification mail when an unverified account try to log in

Hello, I'm requesting this enhancement in case my SMTP server is down or my user not receiving the mail to verify his/her email for some reasons.
What I suggest is to resend a confirmation instruction mail when a user try to log in with an unconfirmed account.
Thanks !

Replace the auth model concern on generator execution

Question

I see the concern is include DeviseTokenAuth::Concerns::Model
both in the docs and the dummy app.

But the generated one is include DeviseTokenAuth::Concerns::User

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable
  include DeviseTokenAuth::Concerns::User
end

So, which one should be used?

ActionController::InvalidAuthenticityToken for fresh install

Describe the bug

Im not sure if there is some config item I am missing, but this seems like a localized issue.

Trying to use the gem results in

ActionController::InvalidAuthenticityToken at /auth
===================================================

> ActionController::InvalidAuthenticityToken

actionpack (6.0.3.1) lib/action_controller/metal/request_forgery_protection.rb, line 215
----------------------------------------------------------------------------------------

``` ruby
  210           def initialize(controller)
  211             @controller = controller
  212           end
  213   
  214           def handle_unverified_request
> 215             raise ActionController::InvalidAuthenticityToken
  216           end
  217         end
  218       end
  219   
  220       private

my application controller

# frozen_string_literal: true

class ApplicationController < ActionController::Base
  # skip_before_action :verify_authenticity_token
  protect_from_forgery with: :exception, prepend: true
end

Steps to reproduce

I installed this from scratch. I also have my own graphql API mounted at /graphql.
The auth one is the only one throwing the error unless I remove CSRF protection

Reconfirmable not setting unconfirmed_email

Describe the bug

So I have Devise.reconfirmable set to true and have the user.unconfirmed_email attribute. I've tried updating an email of a confirmed user and it doesn't set the unconfirmed_email attribute. I thought that this might be a compatibility issue with some gem, but I tried this on a fresh rails app with only graphql_devise installed and the issue still persists.

I thought that maybe I'm just doing this wrong and tried it on a fresh rails app, but this time with the devise gem only. Tried it again here, and it worked.

Is this a known issue?

I'm using Rails 6.0.3 and Ruby 2.6.6

Steps to reproduce

  1. Create a user
  2. Confirm the user
  3. Update the user's email
  4. The user.unconfirmed_email should be nil

Expected behavior

The user.unconfirmed_email should have the new email

Actual behavior

The user.unconfirmed_email returned nil

Could not find generator 'graphql_devise:install'. Maybe you meant "graphql:install"?

gems:

ruby '2.7.0'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.2', '>= 6.0.2.2'

gem "devise", "~> 4.7"
gem "graphql_devise", "~> 0.10.1"

gem "graphql", "~> 1.10"

following the gem's install instructions:

i do bundle add graphql_devise

then i run

rails g graphql_devise:install

output is :

could not find generator 'graphql_devise:install'. Maybe you meant "graphql:install"?
Run `rails generate --help` for more options.

when i run rails g --help i also do not see

Couldn't find anything here to indicate what could be the issue, other than update >0.9 which is not the problem here.

cheers.

Potential naming convention violation found

per @mcelicalderon 's request, I'm taking a stab at a ResendConfirmation mutation. I noticed in the routes.rb file an inconsistency that I think should be fixed before this gem gets popular.

Consider the following code from routes.rb:

default_mutations = {
  login:               GraphqlDevise::Mutations::Login,
  logout:              GraphqlDevise::Mutations::Logout,
  sign_up:             GraphqlDevise::Mutations::SignUp,
  update_password:     GraphqlDevise::Mutations::UpdatePassword,
  send_reset_password: GraphqlDevise::Mutations::SendPasswordReset,
  resend_confirmation: GraphqlDevise::Mutations::ResendConfirmation
}.freeze

I believe that the mutation class should be renamed from SendPasswordReset to SendResetPassword. The other option is to change the key from send_reset_password: to send_password_reset: but I think that would be a breaking change (which is why I said we should fix this immediately) but also I like verb send or in my case resend to be in the front as a convention and renaming the mutation class I think would prevent a breaking fix.

Let me know what you guys think. Also, if I have any other questions like this, should I post them here as issues? I think adding a custom question issue template would be useful. (see my other issue that I posted last week.)

How to get user data on login?

Question

I need to get user info when the user log in, but I dont want to call GraphQL server again.
So, I see on https://github.com/graphql-devise/graphql_devise/blob/master/spec/requests/mutations/login_spec.rb#L20 that the userLogin mutation can return user info, but when I try:
curl http://localhost:3001/graphql -H 'Content-Type: application/json' -d '{ "query": "mutation { userLogin( email: \"[email protected]\", password: \"123456\") { user { id email }, credentials { uid accessToken client expiry } } }" }'
I receive following message:
{"errors":[{"message":"Field 'user' doesn't exist on type 'UserLoginPayload'"

What is the right way to get that info? Another call to server?

Thank you.

Get the Mutations going

Hi all,

We are currently trying out this gem for a new project after some weeks of inquiries on GraphQL.

The migration part is not perfectly clear for us, we found some migration files in lib directory but thought it would be generated by the gem. Are we doing something wrong or are we supposed to add the mutations/resolvers manually ?

In case we have to do it manually does anyone has an example repo with this implemented for the User generated by the gem on which we could work ?

Thanks a lot in advance,

Regards,

Benoit

Add fields when user Sign Up

Hello !
I have setup graphql_devise on my server. Everything is working but I wish I could add fields when the user sign up. For example, I wish to add a field named "username" when I'm adding a new user with the mutation "userSignUp".
How can I do that ?
Thank you.

Tokens seem to have a very short lifespan

I have a react app and I use graphql_devise on a rails backend to authenticate.
Authentication works fine except that the token seem to last about a minute.
Is it the expected behaviour?

Here's how I use graphql_devise:

I use an apollo client for authentication and another apollo client for fetching the resources. Fetching resources requires authentication.

First I authenticate by using the userLogin mutation. This allows me to get credentials that I
put in localStorage.

mutation USER_LOGIN($email: String!, $password: String!) {
  userLogin(email: $email, password: $password) {
    credentials {
      accessToken
      uid
      tokenType
      client
      expiry
    }
  }
}

The client that fetches the resources digs into localStorage for each request, takes the credentials, and adds them to the headers of the request.

import {ApolloClient} from 'apollo-client';
import {createHttpLink} from 'apollo-link-http';
import {setContext} from 'apollo-link-context';
import {InMemoryCache} from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: 'http://localhost:3344/graphql',
});

const authLink = setContext((_, {headers}) => {
  // get the authentication token from local storage if it exists
  const accessToken = localStorage.getItem('accessToken');
  const uid = localStorage.getItem('uid');
  const tokenType = localStorage.getItem('tokenType');
  const client = localStorage.getItem('client');
  const expiry = localStorage.getItem('expiry');

  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      access_token: accessToken,
      uid: uid,
      token_type: tokenType,
      client: client,
      expiry: expiry
    }
  }
});

export const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

Everything works fine except that after about a minute all my requests end in a 401 error. I need the authenticate again. Am I using graphql_devise wrong ?

Also, something worth mentioning is that I removed devise's trackable module. It required some columns to be on the users table and those columns weren't present in the generated migration file.

app/model/user.rb

# frozen_string_literal: true

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :trackable, :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  include DeviseTokenAuth::Concerns::User
end

I reimplement the trackable module to see if that was the issue. It seems it wasn't. I get the same behavior.

I copied those lines from the migration files of another project.

t.integer  :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string   :current_sign_in_ip
t.string   :last_sign_in_ip

Another thing is that for now the client app and the server app run on 2 different ports of localhost. I use the rack_cors to authorize cors in my development environment. But I don't really think that's the issue. Otherwise I probably wouldn't be able to authenticate in the first place.

config/environments/development.rb

  config.middleware.insert_before 0, Rack::Cors do
    allow do
      origins '*'
      resource '*', headers: :any, methods: [:get, :post, :options]
    end
  end

Modify confirmation mailer

Hello,
I'd like to change the format of the confirmation URL link in the mail template. My current URL format is:
http://www.mydomain.com/graphql/auth?query=query($token:String!,$redirectUrl:String!){userConfirmAccount(confirmationToken:$token,redirectUrl:$redirectUrl){email}}&variables[redir$tokenectUrl]=<redirectUrl>&variables[token]=<token>
and I wish to replace it by
https://mydomain.com/auth/token=<token>&action=ConfirmEmail.
In the "confirmation_instructions.html.erb", I noticed this line which is actually generating the link to confirm the email:
<%= link_to t('.confirm_account_link'), url_for(controller: 'graphql_devise/graphql', action: :auth, **confirmation_query(resource_name: @resource.class.to_s, redirect_url: message['redirect-url'], token: @token)) %>
How do I have to change this line to get the URL format I want ?

Thank you !

Separate endpoint url for mailers even if mounting the gem in your own schema

Describe the bug

Mailers include a link to be clicked and the base url for these is always fixed to the gem's graphql controller. This won't work when you mount the auth schema in your very own GQL schema.

We need to find a way to capture the currentUrl on the signUp, sendPasswordReset and resendConfirmation mutations.

If anyone is facing an issue with this, until fixed I would recommend also mounting this gem in your routes file. This way the path will be available when you click on the links. You can pass the only option as you only need the query operations available.

mount_graphql_devise_for('User', only: [: check_password_token, : send_password_reset])

The route will be mounted at /graphql_auth but the mailer will pick this up and generate the right url.

Mutation documentation is missing in the README.md

Not sure how it happened, but the mutation documentation I added got removed/reverted and all that's left is from my last PR for the ResendConfirmation enhancement. That documentation update had some grammar errors that are back also. I checked to see if my PR reflected these changes but it doesn't. However, it looks like my PR broke this and I think this was my fault somehow. I shouldn't have rebased my feature branch when you guys updated master. I'll know not to do that again.

Also the the github custom issue templates were removed. I can resubmit my documentation changes as a new PR and I can add the github custom issue templates as a separate PR unless @00dav00 wants to do that.

image

Routes mount_graphql_devise_for with module not work

Describe the bug

I used mount_graphql_devise_for 'User::Customer' with struct models/user/customer. The error with message: :uninitialized constant UserCustomer

I tested with mount_devise_token_auth_for 'User::Customer' and it worked with devise_token_auth.

ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux]
rails (6.0.2.1)

Default `change_headers_on_each_request` to false

DTA's default configuration to change headers on each request might be too much as the most common scenario is to save tokens that will last longer than a single request. We can't change DTA (or maybe propose they change the default with a PR). But at least for this gem I propose the generator sets change_headers_on_each_request = false by default. WDYT, @00dav00 ?

Context

#73 shows this can happen. For me it's also more easy to assume tokens shouldn't expire on each request by default.

When using React, how do you solve the problem if needing two ApolloClients?

I'm starting to build out a react app and I'm coming across what seems like a potentially big road block. Having two ApolloClient components. Do you guys just nest them in your index.{tsx,jsx,js} file like so:

<ApolloProvider client={client}>
    <App/>
</ApolloProvider>

and then when you want to use authentication end point (inside App component):

<ApolloProvider client={authClient}>
  <Login />
</ApolloProvider>

what if you need to use both in the same component? I've been looking into this and there is apparently a solution called <ApolloMulipleClientsProvider> but all it does it what I think I should be doing in my above example. I know we have a dummy app in the spec directory for server side testing but as I'm working on a simple example with a React front end, it looks like there could be issues and that seems to be the whole point, right?

Add case insensitive fields to sign_up and login

Both Devise and Devise Token auth enable a mechanism to support case insensitive sign_up and login via configuration on Devise's initializer. We should honor that configuration and we currently don't.

Insecure send password reset mutation?

Hi there, first of all thank you for this amazing gem.

I was looking at the SendPasswordReset mutation (https://github.com/graphql-devise/graphql_devise/blob/master/lib/graphql_devise/mutations/send_password_reset.rb), and I can see that it returns an "authenticatable" instance.

Is this a security issue? Can somebody just request something like this and get private information about the user? (Asumming he knows the e-mail)

mutation {
userSendPasswordReset(email: "[email protected]", redirectUrl: "http://someurl.com") {
authenticatable {
email
id
firstName
lastName
...otherPrivateInfo
}
}
}

Let me know if I'm getting it right, so I can perform a pull request in order to fix this issue.
Thank you.

A way to support OTA in the GQL Devise Schema

Question

I'm looking at setting up some OTA for a subset of users, but I'm not sure how I can expand the GraphQL Devise schema to support this. We are current;y running side by side /graphql and /auth endpoints.

Basically looking for a way to pass an email address/phone number to the auth endpoint that would trigger the MFA to fire, and the other endpoint that would accept the 5 digit code.

Devise mapping error

Describe the bug

Hi,
I've been trying to install graphql_devise in a rails API app.
After initializing the gem to be mounted in the schema,
the before_action in graphql_controller set_resource_by_token(:user) fails with:

NoMethodError (undefined method `to' for nil:NilClass)

I suspect a failure in mounting devise or I misunderstood something.

Environment

Gemfile:
https://github.com/pelarejo/gql_devise_error_demo/blob/master/Gemfile

Gemfile.lock:
https://github.com/pelarejo/gql_devise_error_demo/blob/master/Gemfile.lock

Steps to reproduce

I have installed the gem as describe in the demo project's README.
Start the rails server and fetch the schema or launch the userLogin mutation.

More details below.

Expected behavior

I exepected to be able to login straight away.

Digging a little, this error comes from Devise.mappings being empty during devise_token_auth#resource_class after the controller execute set_resource_by_token(:user)

I expected the GraphqlDevise::ResourceLoader in the schema added through the generator to programatically mount the devise module. Isn't that why it's for ?

Actual behavior

The graphql_controller set_resource_by_token call fails with:
NoMethodError (undefined method `to' for nil:NilClass)

Here is the graphql stacktrace:
https://gist.github.com/pelarejo/4a3f9d58898ead574bf1552ae4ba331a

Reproducible demo

Clone this repo:
https://github.com/pelarejo/gql_devise_error_demo

Start the server:

$ bundle
$ rails db:migrate
$ rails server

Launch the query:

curl --request POST \
  --url http://localhost:3000/graphql \
  --header 'content-type: application/json' \
  --data '{"query":"mutation userLogin($email: String!, $password: String!) {\n  userLogin(email: $email, password: $password) {\n    credentials {\n      client\n      accessToken\n      expiry\n      tokenType\n      uid\n    }\n  }\n}","variables":{"email":"[email protected]","password":"password123"},"operationName":"userLogin"}'

change_headers_on_each_request question

Question

change_headers_on_each_request: This configurations defaults to false. This will allow you to store the credentials for as long as the token life_span permits. And you can send the same credentials in each request. Setting this to true means that tokens will change on each request you make, and the new values will be returned in the headers. So your client needs to handle this.

I see in the docs that we can change the token upon each request. Any idea of how to handle this in the client?

Could not find generator 'graphql_devise:install'

Hello,
I already posted here but I'm working on a second project and I'd like to implement this gem in it.
I'm having troubles to run this gem generator. I have installed the gem and bundled (the gem appear in the output) but every time I try to run the generator I'm having this error message:
Could not find generator 'graphql_devise:install'
Gem file and terminal
I'm pretty sure it's a dumb mistake from me but I can't figure out what it is.. Any ideas ?
If you want to check the code it's available here: https://github.com/Gakamine/PriviChat-Server
Thank you.

Gem isn't found in rubygems.org

Trying to run bundle with this gem in the Gemfile. Get the following error:

$> bundle
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Could not find gem 'graphql_devise' in any of the gem sources listed in your Gemfile.

Tried installing it like so also:

$> gem install graphql_devise
ERROR:  Could not find a valid gem 'graphql_devise' (>= 0) in any repository

I know I can reference it directly on github but maybe change the documentation to reflect this until its published on rubygems.

How would I go about sending my own custom email ?

I'm looking for a way to pull the reset password token into my own trigger. Im having a hard time being able to use find_resource in an Active Record Model.

something like this.

def send_complete_signup_email
    # redirect_url = "#{Rails.application.credentials.front_end_host}/case-management/reset-password"
    # auth_schema_url = "#{Rails.application.credentials.backend_end_host}/auth"

    resource = find_resource(:email, get_case_insensitive_field(:email, user.email))

    resource.send_reset_password_instructions(
        email: user.email,
        provider: 'email',
        redirect_url: redirect_url,
        template_path: ['case_manager_mailer'],
        schema_url: auth_schema_url
    )
  end

Checking for `performed?` when mounting into your graphql schema.

What is the problem the enhancement will solve?

I saw that in this gem's codebase that the controller checks for performed? since confirmAccount and checkPasswordToken calls redirect_to to the given redirectUrl or the default redirect url. Since by default, the graphql-ruby gem does not have this performed? check in the default graphql controller, this might look like a bug for graphql_devise and developers wouldn't know where that double rendering issue is being invoked unless they check graphql_devise's codebase.

Describe the solution you have in mind

I think it's worth noting in the documentation, around in this area, that when you mount this gem into your own graphql schema, that they should check for performed? inside their graphql controller before rendering the result since there are operations in the gem that uses controller.redirects_to

authenticable vs authenticatable

Question

Should we have a documentation/code naming standard for authenticable/authenticatable?

authenticatable has 14 results with only one in the documentation.
authenticable has 38 results with five in the documentation.

I did some googling and these mean the same thing with authenticable referencing authenticatable as being an alternate form of it (meaning authenticatable is the more standard form of this word). See:
https://en.wiktionary.org/wiki/authenticable

What's more is that Devise itself addresses this issue and the decision was to conform to authenticatable:

heartcombo/devise#4157

If we were to move to authenticatable this would be a breaking change so it would probably be good to do it as soon as possible before this library gets really popular.

Integration with graphql ruby gem

Question

I have to use the graphiql interface and for the time being, I have to switch between the /auth and /graphql route for graphiql.

So, I would like to ask if they both can be integrated as one single path or something.
Screenshot 2019-12-27 at 6 32 41 PM

Thanks.

NoMethodError generate_confirmation_token! but not supporting confirmable

I'm not using the confirmable plugin as you can see here:

user.rb:

class User < ApplicationRecord
  devise :database_authenticatable,
         :registerable,
         :recoverable,
         :rememberable,
         :validatable

  include GraphqlDevise::Concerns::Model
end

You can also see my schema.rb file to see that I'm not supporting it:

create_table "users", force: :cascade do |t|
    t.string "provider", default: "email", null: false
    t.string "uid", default: "", null: false
    t.string "name"
    t.string "nickname"
    t.string "image"
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.boolean "allow_password_change", default: false
    t.datetime "remember_created_at"
    t.json "tokens"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
    t.index ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true
  end

I go to run the following mutation:

mutation {
  userSignUp(email:"[email protected]", password:"123456", passwordConfirmation:"123456") {
    authenticable {
      id
      email
      name
    }
  }
}

The record gets created but then I get the following server error:

NoMethodError (undefined method `generate_confirmation_token!' for #<User:0x0000000004c589c0>):
  
activemodel (6.0.0) lib/active_model/attribute_methods.rb:431:in `method_missing'
devise_token_auth (1.1.2) app/models/devise_token_auth/concerns/user.rb:54:in `send_confirmation_instructions'
graphql_devise (0.4.0) app/graphql/graphql_devise/mutations/sign_up.rb:20:in `resolve'
graphql (1.9.14) lib/graphql/schema/resolver.rb:90:in `public_send'
graphql (1.9.14) lib/graphql/schema/resolver.rb:90:in `block (3 levels) in resolve_with_support'
.... (I can give you the full stack if you need it)
puma (3.12.1) lib/puma/thread_pool.rb:135:in `block in spawn_thread'

Looks like the error is caused by calling resource.send_confirmation_instructions but that's dependent upon the method requires_confirmation? to be true and I don't think it should be in this case.

Improve docs. Better reference to Devise and DTA.

What is the problem the enhancement will solve?

People might not be aware how closely related this gem is to DTA and Devise. Adding a better explanation will allow people to better configure this gem on their projects

Describe the solution you have in mind

Readme should have an entire section about configuration where we do give some direct examples, but mostly point in a clear way to DTA and Devise's configuration docs.

We should also give more explicit credit to these 2 gems in the readme file.

Additional context

#73 Is a clear example that docs are not clear enough if you are not very familiar with DTA.

Allow returning auth info as part to the response type

What is the problem the enhancement will solve?

Some gql clients expect the auth info (token, client id and expiration date) to be part of the return type instead of taking them from the response headers

Describe the solution you have in mind

Add a field to the login mutation that includes auth info, it can be something like:

field auth_info, Types::AuthInfo, null: true

And the auth info type can look like this:

class Types::AuthInfo < GraphQL::Schema::Object
      field :access_token, String, null: false
      field :token_type, String, null: false
      field :client, String, null: false
      field :expiry, Date, null: true
      field :uid, String, null: false
end

Trying to access /graphql#execute app claims action could not be found

Here is my routes.rb:

Rails.application.routes.draw do
  post "/graphql", to: "graphql#execute" 
  mount_graphql_devise_for 'User'
 
  #Do not place any routes below this one
  if Rails.env.production?
    get '*other', to: 'static#index'
  end
end

Here is my rake routes output:

prompt> rake routes | grep graphql
     graphql POST   /graphql(.:format)       graphql#execute
graphql_auth POST   /graphql_auth(.:format)  graphql_devise/graphql#auth
             GET    /graphql_auth(.:format)  graphql_devise/graphql#auth

Now we I go to http://localhost:3000/graphql I get the following server error:

Started POST "/graphql" for 127.0.0.1 at 2019-10-14 17:25:41 -0700

AbstractController::ActionNotFound (The action 'execute' could not be found for GraphqlController):
  
actionpack (6.0.0) lib/abstract_controller/base.rb:131:in `process'
(stack track continues)...

Any idea what I could be doing wrong? Meanwhile, I'm going to play with the dummy app and see if it works for me.

ActiveAdmin support

Question

Since activeadmin relies on ApplicationController the same with this gem, they're going to conflict given that activeadmin uses the standard devise while this gem relies on DTA. Is there a way where we can specify the controller that this gem uses?

.rubocop.yml showing warnings in VSCode.

Question

Not sure what IDE you guys are using. I've been using VSCode because its great for JS dev.
Anyway, VSCode alerted me of some warnings in our .rubocop.yml file:

.rubocop.yml:1: `require` is concealed by line 2
.rubocop.yml:46: `Style/MethodCalledOnDoEndBlock` is concealed by line 58
.rubocop.yml: Lint/EndAlignment has the wrong namespace - should be Layout
Warning: unrecognized cop RSpec/MultipleExpectations found in .rubocop.yml
Warning: unrecognized cop RSpec/ExampleLength found in .rubocop.yml
Warning: unrecognized cop RSpec/RepeatedDescription found in .rubocop.yml
Warning: unrecognized cop RSpec/MessageSpies found in .rubocop.yml
Warning: unrecognized cop RSpec/NestedGroups found in .rubocop.yml
Warning: unrecognized cop RSpec/ContextWording found in .rubocop.yml

Should I ignore this or do I need to install an extra extension or do some extra configuration?

Works with Rails 6 api only app?

Question

I am getting this response from graphiql-rails after sending userSignUp mutation.

  "status": 500,
  "error": "Internal Server Error",
  "exception": "#<ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true>",

no query string for email reset

Question

hey team. I'm hoping I'm just having a brain fart, but I am working through this email reset.

mutation {
  userSendPasswordReset(email: "[email protected]", redirectUrl: "http://localhost:5000/auth") {
    message
  }
}
{
errors: [
{
message: "No query string was present"
}
]
}
http://localhost:5000/auth?query=query%28%24token%3AString%21%2C%24redirectUrl%3AString%21%29%7BuserCheckPasswordToken%28resetPasswordToken%3A%24token%2CredirectUrl%3A%24redirectUrl%29%7Bemail%7D%7D&variables%5BredirectUrl%5D=http%3A%2F%2Flocalhost%3A5000%2Fauth&variables%5Btoken%5D=ETsb5W8xDqQQk8CjAiqs

decoded

http://localhost:5000/auth?query=query($token:String!,$redirectUrl:String!){userCheckPasswordToken(resetPasswordToken:$token,redirectUrl:$redirectUrl){email}}&variables[redirectUrl]=http://localhost:5000/auth&variables[token]=ETsb5W8xDqQQk8CjAiqs

It looks like a query string is in fact present in the uri however.

Am I just missing something?

How to get credentials from Mutations signUp.

Hi,
I have a question,
after SignUp, the database created new tokens, can Mutations signUp get credentials?
so we can save credentials and skip login action after Customer SignUp.

image
image

Fresh rails 6 install with graphql_devise fails to install graphql and devise.

Describe the bug

After a fresh install of rails app using the below command

Rails new test_app -T -d postgresql --skip-sprockets --skip-turbolinks --skip-actionmailer

the gem 'graphql_devise'

installs
Using devise 4.7.1
Using devise_token_auth 1.1.3
Using graphql 1.10.2
Using graphql_devise 0.9.1

when the install command is given an error is raised about the user.

rails generate graphql_devise:install User api/auth

Environment

Ubuntu 18.04
ruby 2.6.5
rails 6.0.2

Expected behavior

Should have installed graphql folder inside app. Should have placed devise initializers into config/initializers.

Actual behavior

Above error thrown and nothing is installed

Stacktrace

/home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/inflector/methods.rb:282:in const_get': uninitialized constant User (NameError) from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/inflector/methods.rb:282:in block in constantize'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/inflector/methods.rb:280:in each' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/inflector/methods.rb:280:in inject'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/inflector/methods.rb:280:in constantize' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/dependencies/zeitwerk_integration.rb:19:in constantize'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise.rb:320:in get' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/mapping.rb:83:in to'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/mapping.rb:78:in modules' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/mapping.rb:95:in routes'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/mapping.rb:162:in default_used_route' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/mapping.rb:72:in initialize'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise.rb:350:in new' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise.rb:350:in add_mapping'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/rails/routes.rb:243:in block in devise_for' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/rails/routes.rb:242:in each'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/devise-4.7.1/lib/devise/rails/routes.rb:242:in devise_for' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/graphql_devise-0.9.1/lib/graphql_devise/rails/routes.rb:36:in mount_graphql_devise_for'
from /home/devops/Documents/rylabs/rylabs-eqapp/config/routes.rb:2:in block in <main>' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/actionpack-6.0.2.1/lib/action_dispatch/routing/route_set.rb:429:in instance_exec'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/actionpack-6.0.2.1/lib/action_dispatch/routing/route_set.rb:429:in eval_block' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/actionpack-6.0.2.1/lib/action_dispatch/routing/route_set.rb:411:in draw'
from /home/devops/Documents/rylabs/rylabs-eqapp/config/routes.rb:1:in <main>' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:54:in load'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:54:in load' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/routes_reloader.rb:41:in block in load_paths'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/routes_reloader.rb:41:in each' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/routes_reloader.rb:41:in load_paths'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/routes_reloader.rb:20:in reload!' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/routes_reloader.rb:30:in block in updater'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/file_update_checker.rb:83:in execute' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/routes_reloader.rb:10:in execute'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application/finisher.rb:184:in block in <module:Finisher>' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/initializable.rb:32:in instance_exec'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/initializable.rb:32:in run' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/initializable.rb:61:in block in run_initializers'
from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:228:in block in tsort_each' from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:350:in block (2 levels) in each_strongly_connected_component'
from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:431:in each_strongly_connected_component_from' from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:349:in block in each_strongly_connected_component'
from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:347:in each' from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:347:in call'
from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:347:in each_strongly_connected_component' from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:226:in tsort_each'
from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/2.6.0/tsort.rb:205:in tsort_each' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/initializable.rb:60:in run_initializers'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/railties-6.0.2.1/lib/rails/application.rb:363:in initialize!' from /home/devops/Documents/rylabs/rylabs-eqapp/config/environment.rb:5:in

'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in require' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in block in require_with_bootsnap_lfi'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in register' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in require_with_bootsnap_lfi'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in require' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/zeitwerk-2.2.2/lib/zeitwerk/kernel.rb:23:in require'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in block in require' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:291:in load_dependency'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in require' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/spring-2.1.0/lib/spring/application.rb:106:in preload'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/spring-2.1.0/lib/spring/application.rb:157:in serve' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/spring-2.1.0/lib/spring/application.rb:145:in block in run'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/spring-2.1.0/lib/spring/application.rb:139:in loop' from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/spring-2.1.0/lib/spring/application.rb:139:in run'
from /home/devops/.rvm/gems/ruby-2.6.5@rylabs-eqapp/gems/spring-2.1.0/lib/spring/application/boot.rb:19:in <top (required)>' from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in require'
from /home/devops/.rvm/rubies/ruby-2.6.5/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in require' from -e:1:in '

Reproducible demo

https://github.com/scope2229/test_rails

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.