Coder Social home page Coder Social logo

Comments (30)

palkan avatar palkan commented on May 23, 2024 6

Hey everyone!

I've release the first preview version of the upcoming AnyCable v1.0, which includes the PR mentioned above and other changes which improve StimulusReflex compatibility.

You can give it a try by doing the following:

  • Add gem "anycable-rails", "1.0.0.preview1" to the Gemfile.
  • (required) Install anycable-go v1.0.0.preview (binaries available here, Docker images are also available).
  • If you use session in your reflexes to keep some state, add persistent_session_enabled: true to anycable.yml (or run our brand new installation wizard rails g anycable:setup which should do that for you).

This version successfully runs all StimulusReflexExpo demos but one ("snake" is hardly possible to implement with short-lived connections, since it spawns tons of threads; I don't think it makes a lot of sense to spend a lot of time to make it compatible with AnyCable, 'cause I hope you do not do stuff like that in production ๐Ÿ™‚).

And feedback is appreciated!

/cc @daya @leastbad

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024 2

Vladimir will know what to do!

I hope so) Thanks for pinging me.

Worm 1: ApplicationCable::Connection.env returns nil

Interesting:

Need to do some debugging.

Worm 2: session.id...

Yep, session is not supported out-of-the-box.

There is a way to do that like this (from this comment):

env['rack.session'] = cookies.encrypted[Rails.application.config.session_options[:key]]

That's just an example, a universal solution would be more complicated.

I wonder if it's possible to fix this by switching to using Redis instead of cookies?

Take a look at: anycable/anycable-rails#95 (comment)

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024 2

What is the specific reason that snake doesn't work?

It relies on the session object: every thread uses the same session as a state store. The problem is that AnyCable "free" all the connection data after every command (i.e., there is not long-lived objects). Thus, when we trigger a turn, the session from the background thread is not getting updatedโ€”these are two different objects.

So, it's OK to use session in threads if you're not going to update it (the example from the documentation would work fine).

Another option is to reload the session before reading it from the thread (you can do that by calling session.send(:load!)). That would only work with sessions stored in a cache store (e.g., Redis). Actually, I made snake work by adding reload to the reflex, but due to the high update frequency there still were lags.

from stimulus_reflex.

hopsoft avatar hopsoft commented on May 23, 2024 1

This may prove helpful. https://www.driftingruby.com/episodes/plugging-in-anycable

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024 1

๐Ÿ ๐Ÿ ๐Ÿ

You don't like snakes!?

Thank you so much for getting this out the door and your advice along the way, Vladimir. You rock.

from stimulus_reflex.

pbhogan avatar pbhogan commented on May 23, 2024 1

I'm getting a similar error using AnyCable:

StimulusReflex::Channel Failed to re-render http://localhost:3000/ undefined method `load!' for {}:Hash

Which is happening here, in reflex.rb:37:

req.tap { |r| r.session.send :load! }

stimulus_reflex 3.1.4

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024 1

It seems that Rails' .delegate_missing_to doesn't allow calling private methods.

Fixed in anycable-rails (branch 1.0-dev). See the commit link above.

from stimulus_reflex.

anaice avatar anaice commented on May 23, 2024 1

Hi,
Could you help me to setup anycable with stimulus_reflex?

When performing an action my reflex is being executed, but I get an error:

cco-web-anycable-rpc    | [AnyCable sid=Pwu_q_n3fYm_u5RwA1Jrl] StimulusReflex::Channel#receive({"target"=>"PartnerArea::ExampleReflex#example_action", "args"=>[], "url"=>"http://web.cco.local/partner_area", "attrs"=>{"class"=>"btn btn-link", "data-action"=>"click->partner-area--example#example_stimulus", "data-controller"=>"partner-area--example", "checked"=>false, "selected"=>false, "tag_name"=>"A"}, "dataset"=>{"data-action"=>"click->partner-area--example#example_stimulus", "data-controller"=>"partner-area--example"}, "selectors"=>[], "permanent_attribute_name"=>"data-reflex-permanent", "reflexId"=>"658747d0-3298-4e67-9f56-6eaab9a964cf", "params"=>{}})
cco-web-anycable-rpc    | example_action REFLEX action running
cco-web-anycable-rpc    | current_user.id=a6cca6b6-6a22-4d62-9539-2a8eebc805c3
cco-web-anycable-rpc    | [AnyCable sid=Pwu_q_n3fYm_u5RwA1Jrl] StimulusReflex::Channel Failed to re-render http://web.cco.local/partner_area Devise could not find the `Warden::Proxy` instance on your request environment.
cco-web-anycable-rpc    | Make sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack.
cco-web-anycable-rpc    | If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you. /usr/local/bundle/ruby/2.6.0/gems/devise-4.7.1/lib/devise/controllers/helpers.rb:143:in `warden'
cco-anycable-go         | D 2020-06-12T15:45:41.500Z context=pubsub Incoming pubsub message from Redis: {"stream":"StimulusReflex::Channel:a6cca6b6-6a22-4d62-9539-2a8eebc805c3","data":"{\"cableReady\":true,\"operations\":{\"dispatchEvent\":[{\"name\":\"stimulus-reflex:server-message\",\"detail\":{\"stimulusReflex\":{\"target\":\"PartnerArea::ExampleReflex#example_action\",\"args\":[],\"url\":\"http://web.cco.local/partner_area\",\"attrs\":{\"class\":\"btn btn-link\",\"data-action\":\"click-\\u003epartner-area--example#example_stimulus\",\"data-controller\":\"partner-area--example\",\"checked\":false,\"selected\":false,\"tagName\":\"A\"},\"dataset\":{\"data-action\":\"click-\\u003epartner-area--example#example_stimulus\",\"data-controller\":\"partner-area--example\"},\"selectors\":[\"body\"],\"permanentAttributeName\":\"data-reflex-permanent\",\"reflexId\":\"658747d0-3298-4e67-9f56-6eaab9a964cf\",\"params\":{},\"serverMessage\":{\"subject\":\"error\",\"body\":\"StimulusReflex::Channel Failed to re-render http://web.cco.local/partner_area Devise could not find the `Warden::Proxy` instance on your request environment.\\nMake sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack.\\nIf you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you. /usr/local/bundle/ruby/2.6.0/gems/devise-4.7.1/lib/devise/controllers/helpers.rb:143:in `warden'\"}}}}]}}"}

any idea how to solve this?

#app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user

    end

    private

    def find_verified_user
      ckey = Rails.application.config.session_options[:key] || raise("No cookies key in config")
      redis_key =  "#{ENV['APP_SESSION_REDIS_PREFIX']}#{cookies[ckey]}"
      env["rack.session"] = JSON.parse(REDIS_SESSIONS.get(redis_key))
      user = Warden::SessionSerializer.new(env).fetch(:user)
      reject_unauthorized_connection unless user
      User.where(id: user.id).first
    end

  end
end
# my example reflex
class PartnerArea::ExampleReflex < ApplicationReflex
  delegate :current_user, to: :connection

  def example_action
    puts "example_action REFLEX action running".green
    puts "current_user.id=#{current_user.id}"
  end
end

Thank you for your help!

Hey guys,

I finally managed to make it work. It was missing to configure the middleware:

#config/environment/development.rb

# https://github.com/anycable/anycable-rails/issues/127#issue-624598894
  AnyCable::Rails::Rack.middleware.use Warden::Manager do |config|
    Devise.warden_config = config
  end

Thanks.

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024 1

Sorry you had trouble, but thanks for documenting this (however unintentionally). I've borrowed the link to the AnyCable issue for the next release of the SR docs.

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024 1

@leastbad You can also add a link to the corresponding AnyCable documentation article ๐Ÿ˜‰: https://docs.anycable.io/v1/#/ruby/authentication

Also, please, check out the doc on Stimulus Reflex (itโ€™s a very simple early version Iโ€™ve just pushed yesterday), maybe, you have something to add: https://docs.anycable.io/v1/#/ruby/stimulus_reflex

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024 1

@palkan please let me know ASAP if you ever find out that the option is causing harm.

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

That video is great! Unfortunately, it doesn't address either of the two issues I outlined, I don't think.

I was able to get AnyCable running in the general sense after some trial and error; in other words, it functions well as a drop-in enhancement to ActionCable. However, in the context of StimulusReflex, we need a workaround for what I describe as "Worm 1"... consider it a "10/10 flames" category blocker.

We might be able to get around the session (aka "Worm 2") but we do rely on it heavily for most of our apps. I hope to be able to dig in deeper on this later in the month.

However, nothing can really move forward until I get some help on the 1st concern.

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024

We're currently working on the out-of-the-box session support. That should eliminate the ๐Ÿ› โ„–2 (if we work it out).

As for the first one, I figured out why it's nil: we only provided env for connect and disconnect actions but not for channel interactions. Just pushed a quick fix to master, please, check it.

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

Great news, @palkan! Whatever you did seemed to work. I have SR + AnyCable up and running with local source versions of whatever was current last night.

I am currently attempting to figure out how to access ActionController.cookies outside of a controller, if anyone has any magic scrolls handy. Rails source is clear as mud.

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

So far, I've been able to get to:

ActionDispatch::Request.new(Rails.application.env_config.merge(connection.env)).cookie_jar.encrypted[Rails.application.config.session_options[:key]]

This returns nil, which is an improvement on all of the other things I've tried. Help! ๐Ÿ˜€

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024

You can try this branch: anycable/anycable-rails#111

It makes using sessions transparent (it's currently under review and will be merged into v1.0 development branch soon).
It would be great if you give it a try and come back with the feedback ๐Ÿ™‚

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

@palkan hey again!

Thanks for the PR. I checked it out and so far Iโ€™m not seeing what weโ€™re looking for. Is there something I could be missing, like obvious in hindsight gotchas? Itโ€™s just returning nil.

Thereโ€™s a second issue as well: in the code itโ€™s clear you have to call session.fetch(โ€œvalueโ€, nil) instead of session.value.

This would still be a successful outcome: we could explain to people that if they want to use session, they have to convert their code to use fetch. However, is not a โ€œdrop-inโ€. Is it possible to also support the shorthand syntax?

from stimulus_reflex.

daya avatar daya commented on May 23, 2024

@palkan any plans to release new version of AnyCable with anycable/anycable-rails#111 seems like this will be important fix for those of us running into the same issue and would make AnyCable as a drop-in replacement for SR

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

@palkan a quick follow-up question: you mentioned that snake won't work because it spawns tons of threads. What is the specific reason that snake doesn't work? Is it because it's spawning threads or some other factor? eg. Can I spawn one thread? Can I spawn n threads slowly?

Obviously the goal isn't to fix ๐Ÿ but I do need to document any caveats for people using the libraries together.

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

@palkan perfect answer. Thank you again!

from stimulus_reflex.

vitobotta avatar vitobotta commented on May 23, 2024

Hi @palkan I am testing something with Stimulus Reflex, and for me the session.send(:load!) doesn't work, I get undefined method load!' for #<AnyCable::Rails::SessionProxy`. What am I missing? Thanks!

from stimulus_reflex.

anaice avatar anaice commented on May 23, 2024

Hi,
Could you help me to setup anycable with stimulus_reflex?

When performing an action my reflex is being executed, but I get an error:

cco-web-anycable-rpc    | [AnyCable sid=Pwu_q_n3fYm_u5RwA1Jrl] StimulusReflex::Channel#receive({"target"=>"PartnerArea::ExampleReflex#example_action", "args"=>[], "url"=>"http://web.cco.local/partner_area", "attrs"=>{"class"=>"btn btn-link", "data-action"=>"click->partner-area--example#example_stimulus", "data-controller"=>"partner-area--example", "checked"=>false, "selected"=>false, "tag_name"=>"A"}, "dataset"=>{"data-action"=>"click->partner-area--example#example_stimulus", "data-controller"=>"partner-area--example"}, "selectors"=>[], "permanent_attribute_name"=>"data-reflex-permanent", "reflexId"=>"658747d0-3298-4e67-9f56-6eaab9a964cf", "params"=>{}})
cco-web-anycable-rpc    | example_action REFLEX action running
cco-web-anycable-rpc    | current_user.id=a6cca6b6-6a22-4d62-9539-2a8eebc805c3
cco-web-anycable-rpc    | [AnyCable sid=Pwu_q_n3fYm_u5RwA1Jrl] StimulusReflex::Channel Failed to re-render http://web.cco.local/partner_area Devise could not find the `Warden::Proxy` instance on your request environment.
cco-web-anycable-rpc    | Make sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack.
cco-web-anycable-rpc    | If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you. /usr/local/bundle/ruby/2.6.0/gems/devise-4.7.1/lib/devise/controllers/helpers.rb:143:in `warden'
cco-anycable-go         | D 2020-06-12T15:45:41.500Z context=pubsub Incoming pubsub message from Redis: {"stream":"StimulusReflex::Channel:a6cca6b6-6a22-4d62-9539-2a8eebc805c3","data":"{\"cableReady\":true,\"operations\":{\"dispatchEvent\":[{\"name\":\"stimulus-reflex:server-message\",\"detail\":{\"stimulusReflex\":{\"target\":\"PartnerArea::ExampleReflex#example_action\",\"args\":[],\"url\":\"http://web.cco.local/partner_area\",\"attrs\":{\"class\":\"btn btn-link\",\"data-action\":\"click-\\u003epartner-area--example#example_stimulus\",\"data-controller\":\"partner-area--example\",\"checked\":false,\"selected\":false,\"tagName\":\"A\"},\"dataset\":{\"data-action\":\"click-\\u003epartner-area--example#example_stimulus\",\"data-controller\":\"partner-area--example\"},\"selectors\":[\"body\"],\"permanentAttributeName\":\"data-reflex-permanent\",\"reflexId\":\"658747d0-3298-4e67-9f56-6eaab9a964cf\",\"params\":{},\"serverMessage\":{\"subject\":\"error\",\"body\":\"StimulusReflex::Channel Failed to re-render http://web.cco.local/partner_area Devise could not find the `Warden::Proxy` instance on your request environment.\\nMake sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack.\\nIf you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you. /usr/local/bundle/ruby/2.6.0/gems/devise-4.7.1/lib/devise/controllers/helpers.rb:143:in `warden'\"}}}}]}}"}

any idea how to solve this?

#app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user

    end

    private

    def find_verified_user
      ckey = Rails.application.config.session_options[:key] || raise("No cookies key in config")
      redis_key =  "#{ENV['APP_SESSION_REDIS_PREFIX']}#{cookies[ckey]}"
      env["rack.session"] = JSON.parse(REDIS_SESSIONS.get(redis_key))
      user = Warden::SessionSerializer.new(env).fetch(:user)
      reject_unauthorized_connection unless user
      User.where(id: user.id).first
    end

  end
end
# my example reflex
class PartnerArea::ExampleReflex < ApplicationReflex
  delegate :current_user, to: :connection

  def example_action
    puts "example_action REFLEX action running".green
    puts "current_user.id=#{current_user.id}"
  end
end

Thank you for your help!

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

@palkan thanks so much for writing that up! I had no idea you'd done that. I have done my best to work in the details to https://docs.stimulusreflex.com/deployment#anycable as well.

I'm a bit fuzzy on persistent_session_enabled: true - did this become unnecessary as of v3 of SR?

Truth be told, I don't have any specific feedback re: the instructions you gave beyond that you should feel welcome to borrow anything on our page for yours. I'm not concerned if they are basically mirror images of each other... both serve to advertise the other regardless of how people find them.

Finally, give us a heads-up when you're pushing a new version! You're always welcome on Discord but even a note here helps us keep things from falling through the cracks.

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024

did this become unnecessary as of v3 of SR?

TBH, I haven't check v3 yet. Add added this feature while making stimulus_reflex_expo work with AnyCable a while ago. From what I understand, Stimulus Reflex v3+ commits session after each reflex interaction, so the option should be unnecessary (and even could lead to unexpected results: anycable/anycable-rails#129).

https://docs.stimulusreflex.com/deployment#anycable

Awesome!

I'm not concerned if they are basically mirror images of each other... both serve to advertise the other regardless of how people find them.

Agree. I think, cross-linking them would be a good idea.

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024

Here is the Expo running on AnyCable: https://github.com/anycable/stimulus_reflex_expo

I found one bug (so, 1.0.0.rc1 could not work correctly, anycable-rails#master has a fix), checked with both persistent_session_enabled: true and persistent_session_enabled: false โ€” all demos work. Hence, this option is not needed for Reflex v3.

from stimulus_reflex.

leastbad avatar leastbad commented on May 23, 2024

@palkan yikes!

I took out the reference to persistent_session_enabled (thanks for investigating!) but this news about rc1 not working is troubling. I don't mind telling people to draw off master, but does it make sense to cut an rc2? Also... is the bug in anycable-rails or anycable-go?

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024

does it make sense to cut an rc2?

Agree, it makes sense. Released.

is the bug in anycable-rails or anycable-go?

Only anycable-rails. Other libraries are still rc1.

from stimulus_reflex.

matedemorphy avatar matedemorphy commented on May 23, 2024

First time a Reflex is invoked i'm getting this error Perform error: Application error: undefined method rescue_with_handler' for nil:NilClassand second time No route matches`.

from stimulus_reflex.

palkan avatar palkan commented on May 23, 2024

@matedemorphy Could you please provide a bit more context? Do you use Rails 6.1 (and rescue_from in a connection class)?

from stimulus_reflex.

matedemorphy avatar matedemorphy commented on May 23, 2024

@palkan i'm usinig rails 6.0.3. But this is related to that is a multi-tenant app, and i'm using the Apartment gem, there are some additional configurations that should be done, but i couldn't figure out yet, like make it work with dynamic subdomains, among others.

from stimulus_reflex.

Related Issues (20)

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.