diff --git a/.rspec b/.rspec index 8c18f1ab..42fde7df 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ --format documentation --color +--order random diff --git a/.travis.yml b/.travis.yml index 87657838..0ce5fabf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,13 +47,19 @@ jobs: rvm: 2.7.1 - gemfile: gemfiles/rails6.0_graphql_edge.gemfile rvm: 2.6.6 - env: SKIP_COVERALLS=true + env: + - SKIP_COVERALLS=true + - EAGER_LOAD=true - gemfile: gemfiles/rails6.0_graphql_edge.gemfile rvm: 2.7.1 - env: SKIP_COVERALLS=true + env: + - SKIP_COVERALLS=true + - EAGER_LOAD=true - gemfile: gemfiles/rails_edge_graphql_edge.gemfile rvm: 2.7.1 - env: SKIP_COVERALLS=true + env: + - SKIP_COVERALLS=true + - EAGER_LOAD=true exclude: - gemfile: gemfiles/rails4.2_graphql1.8.gemfile rvm: 2.7.1 diff --git a/README.md b/README.md index 56f728ab..b498a824 100644 --- a/README.md +++ b/README.md @@ -193,16 +193,12 @@ class User < ApplicationRecord :confirmable # including after calling the `devise` method is important. - # include DeviseTokenAuth::Concerns::User # is also valid (generator includes this one). include GraphqlDevise::Concerns::Model end ``` The install generator can do this for you if you specify the `user_class` option. See [Installation](#installation) for details. -The generator will include a different module in your model, `DeviseTokenAuth::Concerns::User` which is also correct, -we just made an alias on our namespace for consistency and possible extension. -Generators have to be updated to generate our module. ### 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`, @@ -226,7 +222,6 @@ In our example our model is `User`, so it would look like this: # app/controllers/my_controller.rb class MyController < ApplicationController - # include DeviseTokenAuth::Concerns::SetUserByToken # is also valid (generator includes this one). include GraphqlDevise::Concerns::SetUserByToken before_action :authenticate_user! @@ -239,9 +234,6 @@ end The install generator can do this for you because it executes DTA installer. See [Installation](#Installation) for details. -The generator will include a different module in your model, `DeviseTokenAuth::Concerns::SetUserByToken` which is also correct, -we just made an alias on our namespace for consistency and possible extension. -Generators have to be updated to generate our module. ### Making Requests Here is a list of the available mutations and queries assuming your mounted model is `User`. @@ -290,10 +282,10 @@ as comments. You can also use **[DTA's docs](https://devise-token-auth.gitbook.io/devise-token-auth/config/initialization)** as a reference. In this section the most important configurations will be highlighted. -- **change_headers_on_each_request:** This configurations defaults to `true`. This 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. - Setting this to `false` 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. +- **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. diff --git a/lib/generators/graphql_devise/install_generator.rb b/lib/generators/graphql_devise/install_generator.rb index 73163404..ee5305eb 100644 --- a/lib/generators/graphql_devise/install_generator.rb +++ b/lib/generators/graphql_devise/install_generator.rb @@ -10,57 +10,67 @@ def execute_devise_installer end def execute_dta_installer + # Necessary in case of a re-run of the generator, for DTA to detect concerns already included + if File.exist?(File.expand_path("app/models/#{user_class.underscore}.rb", destination_root)) + gsub_file( + "app/models/#{user_class.underscore}.rb", + 'GraphqlDevise::Concerns::Model', + 'DeviseTokenAuth::Concerns::User' + ) + end + gsub_file( + 'app/controllers/application_controller.rb', + 'GraphqlDevise::Concerns::SetUserByToken', + 'DeviseTokenAuth::Concerns::SetUserByToken' + ) + generate 'devise_token_auth:install', "#{user_class} #{mount_path}" end def mount_resource_route routes_file = 'config/routes.rb' - routes_path = File.join(destination_root, routes_file) - gem_helper = 'mount_graphql_devise_for' - gem_route = "#{gem_helper} '#{user_class}', at: '#{mount_path}'" + gem_route = "mount_graphql_devise_for '#{user_class}', at: '#{mount_path}'" dta_route = "mount_devise_token_auth_for '#{user_class}', at: '#{mount_path}'" - file_start = 'Rails.application.routes.draw do' - - if File.exist?(routes_path) - current_route = parse_file_for_line(routes_path, gem_route) - if current_route.present? - say_status('skipped', "Routes already exist for #{user_class} at #{mount_path}") - else - current_dta_route = parse_file_for_line(routes_path, dta_route) + if file_contains_str?(routes_file, gem_route) + gsub_file(routes_file, /^\s+#{Regexp.escape(dta_route + "\n")}/i, '') - if current_dta_route.present? - replace_line(routes_path, dta_route, gem_route) - else - insert_text_after_line(routes_path, file_start, gem_route) - end - end + say_status('skipped', "Routes already exist for #{user_class} at #{mount_path}") else - say_status('skipped', "#{routes_file} not found. Add \"#{gem_route}\" to your routes file.") + gsub_file(routes_file, /#{Regexp.escape(dta_route)}/i, gem_route) end end - private + def replace_model_concern + gsub_file( + "app/models/#{user_class.underscore}.rb", + /^\s+include DeviseTokenAuth::Concerns::User/, + ' include GraphqlDevise::Concerns::Model' + ) + end - def insert_text_after_line(filename, line, str) - gsub_file(filename, /(#{Regexp.escape(line)})/mi) do |match| - "#{match}\n #{str}" - end + def replace_controller_concern + gsub_file( + 'app/controllers/application_controller.rb', + /^\s+include DeviseTokenAuth::Concerns::SetUserByToken/, + ' include GraphqlDevise::Concerns::SetUserByToken' + ) end - def replace_line(filename, old_line, new_line) - gsub_file(filename, /(#{Regexp.escape(old_line)})/mi, " #{new_line}") + def set_change_headers_on_each_request_false + gsub_file( + 'config/initializers/devise_token_auth.rb', + '# config.change_headers_on_each_request = true', + 'config.change_headers_on_each_request = false' + ) end - def parse_file_for_line(filename, str) - match = false + private + + def file_contains_str?(filename, regex_str) + path = File.join(destination_root, filename) - File.open(filename) do |f| - f.each_line do |line| - match = line if line =~ /(#{Regexp.escape(str)})/mi - end - end - match + File.read(path) =~ /(#{Regexp.escape(regex_str)})/i end end end diff --git a/spec/fixtures/rails b/spec/fixtures/rails deleted file mode 100755 index 03b8d5b5..00000000 --- a/spec/fixtures/rails +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env ruby -# This command will automatically be run when you run "rails" with Rails gems -# installed from the root of your application. - -APP_PATH = File.expand_path('../../../../spec/dummy/config/application', __dir__) - -require 'rails/all' diff --git a/spec/generators/graphql_devise/install_generator_spec.rb b/spec/generators/graphql_devise/install_generator_spec.rb index 6a6484ca..5b4fb368 100644 --- a/spec/generators/graphql_devise/install_generator_spec.rb +++ b/spec/generators/graphql_devise/install_generator_spec.rb @@ -3,56 +3,61 @@ require 'generators/graphql_devise/install_generator' RSpec.describe GraphqlDevise::InstallGenerator, type: :generator do - destination File.expand_path('../../../tmp/dummy', __dir__) + destination File.expand_path('../../../../gqld_dummy', __dir__) + + let(:routes_path) { "#{destination_root}/config/routes.rb" } + let(:routes_content) { File.read(routes_path) } + let(:dta_route) { 'mount_devise_token_auth_for' } + + after(:all) { FileUtils.rm_rf(destination_root) } before do prepare_destination - copy_rails_bin + create_rails_project + run_generator(args) end - let(:routes_path) { "#{destination_root}/config/routes.rb" } - let(:routes_content) { File.read(routes_path) } - let(:dta_route) { "mount_devise_token_auth_for 'User', at: 'auth'" } - - context 'when the file exists' do - before do - create_file_with_content( - routes_path, - "Rails.application.routes.draw do\n#{dta_route}\nend" - ) - end + context 'when passing no params to the generator' do + let(:args) { [] } - context 'when passing no params to the generator' do - before { run_generator } + it 'creates and updated required files' do + assert_file 'config/routes.rb', /^\s{2}mount_graphql_devise_for 'User', at: 'auth'/ + expect(routes_content).not_to match(dta_route) - it 'replaces dta route using the default values for class and path' do - generator_added_route = / mount_graphql_devise_for 'User', at: 'auth'/ - expect(routes_content).to match(generator_added_route) - expect(routes_content).not_to match(dta_route) - end - end + assert_file 'config/initializers/devise.rb' + assert_file 'config/initializers/devise_token_auth.rb', /^\s{2}#{Regexp.escape('config.change_headers_on_each_request = false')}/ + assert_file 'config/locales/devise.en.yml' + + assert_migration 'db/migrate/devise_token_auth_create_users.rb' - context 'when passing custom params to the generator' do - before { run_generator %w[Admin api] } + assert_file 'app/models/user.rb', /^\s{2}devise :.+include GraphqlDevise::Concerns::Model/m - it 'add the routes using the provided values for class and path and keeps dta route' do - generator_added_route = / mount_graphql_devise_for 'Admin', at: 'api'/ - expect(routes_content).to match(generator_added_route) - expect(routes_content).to match(dta_route) - end + assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetUserByToken/ end end - context 'when file does *NOT* exist' do - before { run_generator } + context 'when passing custom params to the generator' do + let(:args) { %w[Admin api] } + + it 'creates and updated required files' do + assert_file 'config/routes.rb', /^\s{2}mount_graphql_devise_for 'Admin', at: 'api'/ + expect(routes_content).not_to match(dta_route) + + assert_file 'config/initializers/devise.rb' + assert_file 'config/initializers/devise_token_auth.rb', /^\s{2}#{Regexp.escape('config.change_headers_on_each_request = false')}/ + assert_file 'config/locales/devise.en.yml' - it 'does *NOT* create the file and throw no exception' do - expect(File).not_to exist(routes_path) + assert_migration 'db/migrate/devise_token_auth_create_admins.rb' + + assert_file 'app/models/admin.rb', /^\s{2}devise :.+include GraphqlDevise::Concerns::Model/m + + assert_file 'app/controllers/application_controller.rb', /^\s{2}include GraphqlDevise::Concerns::SetUserByToken/ end end - def copy_rails_bin - FileUtils.mkdir_p(File.join(destination_root, 'bin')) - FileUtils.copy_file('spec/fixtures/rails', File.join(destination_root, 'bin/rails')) + def create_rails_project + FileUtils.cd(File.join(destination_root, '..')) do + `rails new gqld_dummy -S -C --skip-action-mailbox --skip-action-text -T --skip-spring --skip-bundle --skip-keeps -G --skip-active-storage -J --skip-listen --skip-bootsnap` + end end end