Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement for project/Inspiration for others(?): Stimulus Controller #45

Open
fluser opened this issue Nov 5, 2023 · 1 comment
Open

Comments

@fluser
Copy link

fluser commented Nov 5, 2023

Hello and thank you very much for this gem.

This is not a bug - it is more kind of a documentation improvement or suggestion to create a Node.js package.

I am using Rails 7.1 with Hotwire Stimulus-Rails/Turbo-Rails and ended up writing my own Stimulus controller for AutoSessionTimeout, based on the provided JS.

I experimented a bit with Stimulus and came up with this solution.

My Stimulus controller provides:

This is my first attempt to dig into JS - if there are any mistakes or possible improvements, please let me know :-)

Stimulus controllers customizations (thanks to #16):

app/javascript/controllers/index.js

[...]
import AutoSessionTimeoutController from "./auto_session_timeout_controller"
application.register("auto-session-timeout", AutoSessionTimeoutController)
[...]

app/javascript/controllers/auto_session_timeout_controller.js

import {Controller} from "@hotwired/stimulus"

// Connects to data-controller="auto-session-timeout"
export default class extends Controller {

    initialize() {
        this.intervalId = 0;
        this.waitUntil = 0

        this.frequency = Number(this.element.dataset.astFrequency) || 60;
        this.active_path = String(this.element.dataset.astActivePath)
        this.keep_alive_path = String(this.element.dataset.astKeepAlivePath)

        super.initialize();
    }

    connect() {
        if (this.active_path === 'undefined') {
            console.log('auto-session-timeout message:')
            console.log('ast-active-path is not defined - value: ' + this.active_path);
            return;
        }

        if (this.keep_alive_path === 'undefined') {
            console.log('auto-session-timeout message:')
            console.log('ast-ping-path is not defined - value: ' + this.keep_alive_path);
            return;
        }

        this.intervalId = setInterval(this.check_timeout.bind(this), (this.frequency * 1000));
    }

    disconnect() {
        clearInterval(this.intervalId);
    }

    check_return_value(event) {
        var status = event.target.status;
        var response = event.target.response;

        if (status === 200 && (response === false || response === 'false' || response === null)) {
            location.reload();
        }
    }

    check_timeout() {
        const request = new XMLHttpRequest();

        request.onload = this.check_return_value.bind(this);

        request.open('GET', this.active_path, true);
        request.responseType = 'json';
        request.send();
    }

    keep_alive() {
        const request = new XMLHttpRequest();

        if (Date.now() >= this.waitUntil) {
            this.waitUntil = Date.now() + 1000 * this.frequency;
        } else {
            return;
        }

        request.onload = this.check_return_value.bind(this);

        request.open('GET', this.keep_alive_path, true);
        request.responseType = 'json';
        request.send();
    }
}

Helper method:

app/helpers/application_helper.rb

  def auto_session_timeout_settings
    if user_signed_in?
      data_action = [
        'keypress->auto-session-timeout#keep_alive',
        'scroll@window->auto-session-timeout#keep_alive'
      ]

      {
        data: {
          controller: 'auto-session-timeout',
          'ast-frequency': 5,
          'ast-active-path': active_path,
          'ast-keep-alive-path': keep_alive_path,
          action: data_action.join(' ')
        }
      }
    else
      {}
    end
  end

View:

app/views/layouts/application.html.slim

[...]
body *auto_session_timeout_settings
  [...]

Routes:

config/routes.rb

[...]
  devise_for :users, controllers: { sessions: "users/sessions" }

  devise_scope :user do
    get "active", to: "users/sessions#active"
    get "keep-alive", to: "users/sessions#active"
    # Not used - just for completion
    # get "timeout", to: "users/sessions#timeout"
  end
[...]

Application Controller (thanks to #16 )

[...]
  # has to be after auto_session_timeout so that prepend will not be overwritten.                                                                                                                                  
  # Required: Login will not work without
  # > Can't verify CSRF token authenticity.
  protect_from_forgery with: :exception, prepend: true
[...]
@pelargir
Copy link
Owner

pelargir commented Nov 20, 2023

Thanks! This is great stuff. I'm not really sure how/where to incorporate this into the project, though. Perhaps you could fork the project, modify it, and create a Node.js package yourself?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants