stimulusreflex / stimulus_reflex

Build reactive applications with the Rails tooling you already know and love.
https://docs.stimulusreflex.com
MIT License
2.27k stars 171 forks source link

Unexplained error with basic scenario #562

Closed pitosalas closed 2 years ago

pitosalas commented 2 years ago

cable_ready 4.5.0 rails 6.1.4.1 ruby 3.0.2p107

This is a simple example from the basic tutorial (https://www.youtube.com/watch?v=F5hA79vKE_E) I suspect the error I am getting is because either cable_ready or rails evolved a little and created a tiny incompatibility.

I get this error in the JS console:

enter image description here

It is triggered when in my controller I ask cable ready to:

cable_ready["timeline"].console_log(message: "***** cable ready post created")

Which leads to my timeline_channel to:

received(data) {
    console.log("******** Received data:", data.operations)
    if (data.cableReady) CableReady.perform(data.operations)
  }

My interpretation is perform causes this line in cable_ready.js line 13:

  operations.forEach(function (operation) {
    if (!!operation.batch) batches[operation.batch] = batches[operation.batch] ? ++batches[operation.batch] : 1;
  });

Is finding something in the received data that it doesn't like.

That's where my trail ends. Can someone see what I am doing wrong, or tell me what other code you'd like me to include?

leastbad commented 2 years ago

Hi there!

Can you please confirm the gem and npm package versions for both StimulusReflex and CableReady in your project?

Just to preview: each one needs to be an exact 1:1 match.

pitosalas commented 2 years ago

I checked by looking at yarn.lock and gemfile.lock and they do match:

StimulusReflex 3.4.1 in both CableReady 4.5.0 in both

leastbad commented 2 years ago

Here's the thing... the batches code wasn't in CableReady 4.5. It was only introduced just a few months ago.

Please make sure there's an entry in package.json for each library locked to the specific version, and run yarn again.

pitosalas commented 2 years ago

Thanks, sounds like it’s a solution!

But as I am not so sophisticated yet on the interactions between yarn, bundler, gems, rails etc. could you give me a more specific recommendation?

Pito Salas Faculty, Computer Science Brandeis University

On Nov 18, 2021, at 3:23 PM, leastbad @.***> wrote:

Here's the thing... the batches code wasn't in CableReady 4.5. It was only introduced just a few months ago.

Please make sure there's an entry in package.json for each library locked to the specific version, and run yarn again.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

leastbad commented 2 years ago

No problem at all; we're happy to help.

Could you please attach or gist the following files:

Gemfile package.json app/javascript/packs/application.js app/javascript/controllers/index.js

Note that I'm likely going to upgrade you to the latest and greatest, which is a very good thing. Lots of new features and bug fixes.

pitosalas commented 2 years ago

Thanks I really appreciate it, as I've spent quite a bit of time on this. On the other hand I've learned a lot in the process...

I don't have a app/javascript/controllers/index.js file. I guess I was just following the tutorial and stopped when I found these errors. But here are the other two:


//application.js // This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled.

import Rails from @./ujs" import Turbolinks from "turbolinks" import as ActiveStorage from **@.***/activestorage" import "channels"

Rails.start() Turbolinks.start() ActiveStorage.start()


//package.json { "name": "ajax-play", "private": true, "dependencies": { @./actioncable": "^6.0.0", @./activestorage": "^6.0.0", @./ujs": "^6.0.0", @./webpacker": "5.4.3", "turbolinks": "^5.2.0", "webpack": "^4.46.0", "webpack-cli": "^3.3.12" }, "version": "0.1.0", "devDependencies": { "webpack-dev-server": "^3" } }

I am curious whether I made a mistake in following the tutorial or that the tutorial is just a little old and some changes in rails or stimulus reflex or one of the other bits caused it to break?

So if you can give me just a little bit of explanation that would be so great.Thanks!

Pito Salas Faculty, Computer Science Brandeis University

On Nov 18, 2021, at 5:40 PM, leastbad @.***> wrote:

No problem at all; we're happy to help.

Could you please attach or gist the following files:

Gemfile package.json app/javascript/packs/application.js app/javascript/controllers/index.js

Note that I'm likely going to upgrade you to the latest and greatest, which is a very good thing. Lots of new features and bug fixes.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

pitosalas commented 2 years ago

Whoops, forgot the gem file:

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

ruby '3.0.2'

Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'

gem 'rails', '~> 6.1.4', '>= 6.1.4.1'

Use postgresql as the database for Active Record

gem 'pg', '~> 1.1'

Use Puma as the app server

gem 'puma', '~> 5.0'

Use SCSS for stylesheets

gem 'sass-rails', '>= 6'

Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker

gem 'webpacker', '~> 5.0'

Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks

gem 'turbolinks', '~> 5'

Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder

gem 'jbuilder', '~> 2.7'

Use Redis adapter to run Action Cable in production

gem 'redis', '~> 4.0'

Use Active Model has_secure_password

gem 'bcrypt', '~> 3.1.7'

Use Active Storage variant

gem 'image_processing', '~> 1.2'

Reduces boot times through caching; required in config/boot.rb

gem 'bootsnap', '>= 1.4.4', require: false

group :development, :test do

Call 'byebug' anywhere in the code to stop execution and get a debugger console

gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end

group :development do

Access an interactive console on exception pages or by calling 'console' anywhere in the code.

gem 'web-console', '>= 4.1.0'

Display performance information such as SQL time and flame graphs for each request in your browser.

Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md

gem 'rack-mini-profiler', '~> 2.0' gem 'listen', '~> 3.3'

Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring

gem 'spring' end

group :test do

Adds support for Capybara system testing and selenium driver

gem 'capybara', '>= 3.26' gem 'selenium-webdriver'

Easy installation and use of web drivers to run system tests with browsers

gem 'webdrivers' end

Windows does not include zoneinfo files, so bundle the tzinfo-data gem

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

leastbad commented 2 years ago

Okay, let's do this!

Gemfile:

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

ruby '3.0.2'

gem 'rails', '~> 6.1.4', '>= 6.1.4.1'
gem 'pg', '~> 1.1'
gem 'puma', '~> 5.2.1'
gem 'webpacker', '~> 5.4.3'
gem 'jbuilder', '~> 2.7'
gem 'redis', '~> 4.2.5'

gem 'cable_ready', '5.0.0.pre7'
gem 'stimulus_reflex', '3.5.0.pre7'

# gem 'bcrypt', '~> 3.1.7'
# gem 'image_processing', '~> 1.2'

gem 'bootsnap', '>= 1.4.4', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 4.1.0'
  gem 'rack-mini-profiler', '~> 2.0'
  gem 'listen', '~> 3.3'
  gem 'pry-rails'
  gem 'better_errors'
  gem 'binding_of_caller'
end

group :test do
  gem 'capybara', '>= 3.26'
  gem 'selenium-webdriver'
  gem 'webdrivers'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

package.json:

{
  "name": "ajax-play",
  "private": true,
  "dependencies": {
    "@rails/actioncable": "^6.1.2-1",
    "@rails/activestorage": "^6.1.3",
    "@rails/webpacker": "5.4.3",
    "@hotwired/turbo": "^7.0.1",
    "cable_ready": "5.0.0-pre7",
    "mrujs": "^0.6.0",
    "sass": "^1.32.12",
    "sass-loader": "^10",
    "stimulus": "^3.0.1",
    "stimulus_reflex": "3.5.0-pre7",
    "webpack": "^4.46.0",
    "webpack-cli": "^3.3.12"
  },
  "version": "0.1.0",
  "devDependencies": {
    "webpack-dev-server": "^3.11.2"
  }
}

At this point, you need to run bundle and yarn, then run the rake webpacker:install:stimulus task. The honest truth is that I don't know where things went wrong in the tutorial that you were following. I'm here to get you back on track today!

So once you've hopefully gotten your gems and packages up to date - it's okay to delete your Gemfile.lock and yarn.lock if they are giving you trouble - and initialized Webpacker with Stimulus, we can move on to next steps.

app/javascript/packs/application.js:

import Rails from 'mrujs'
import { CableCar } from 'mrujs/plugins'
import * as Turbo from '@hotwired/turbo'
import * as ActiveStorage from '@rails/activestorage'
import CableReady from 'cable_ready'

window.Turbo = Turbo

import 'controllers'
import 'channels'

const images = require.context('../images', true)
// const imagePath = name => images(name, true)

Rails.start({
  plugins: [new CableCar(CableReady)]
})

ActiveStorage.start()

A few things:

app/javascript/controllers/index.js:

import { Application } from 'stimulus'
import { definitionsFromContext } from 'stimulus/webpack-helpers'
import StimulusReflex from 'stimulus_reflex'
import consumer from '../channels/consumer'
import controller from '../controllers/application_controller'

const app = require.context('controllers', true, /_controller\.js$/)

const application = Application.start()
application.load(definitionsFromContext(app))
application.consumer = consumer

StimulusReflex.initialize(application, {
  controller,
  isolate: true,
  debug: process.env.RAILS_ENV === 'development'
})

CableReady.initialize({ consumer })

Now, at this point I'm assuming things might start getting a bit fuzzy. For example, it's not clear how far you got in the StimulusReflex setup, but at some point you need to follow the steps, and that includes creating an ApplicationController if one doesn't already exist.

app/javascript/controllers/application_controller.js:

import { Controller } from 'stimulus'
import StimulusReflex from 'stimulus_reflex'

export default class extends Controller {
  connect () {
    StimulusReflex.register(this)
  }
}

Another thing that trips people up is that they don't set their ActionCable subscription adapter to use Redis: config/cable.yml:

development:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/0" } %>

test:
  adapter: test

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/0" } %>

Last thing I can think of, for now, is that you need to enable that Sass npm package: config/webpack/environment.js:

const { environment } = require('@rails/webpacker')

const sassLoader = environment.loaders.get('sass')
const sassLoaderConfig = sassLoader.use.find(function (element) {
  return element.loader == 'sass-loader'
})

const options = sassLoaderConfig.options
options.implementation = require('sass')

module.exports = environment

I know that's a lot to take in all at once. My suggestions:

  1. Put your project up on Github so that we can see what's up, as it's 100% easier for us to help.
  2. With all of the above out of the way, the fastest path to success is to jump on Discord as this isn't really an issue. There are folks on Discord 24/7 who will help you with any Rails-adjacent issue you might have.
leastbad commented 2 years ago

I almost forgot: the instructions above half-remove the spring gem, which is the source of countless issues. Let's finish the job:

  1. Run pkill -f spring
  2. Edit your Gemfile and comment out spring and spring-watcher-listen (should already be done!)
  3. Run bin/spring binstub --remove --all
  4. Comment out the line in bin/rails which says: load File.expandpath("spring", _dir)
pitosalas commented 2 years ago

Wow, thank you for taking all the time to write that up! I am wondering how stimulus reflex compares with / overlaps with the new hotwired stuff from DHH. Also it is confusing that the batches code was being invoked by the tutorial, even though the tutorial didn't (say that it) required the newest cable ready. In other words, if I re-do the tutorial but force the versions of cable ready and stimulus reflex to be the latest ones you recommended, should it work? (By the way, I am curious if you are the author or a major contributor to stimulus reflex?

leastbad commented 2 years ago

I am on the SR/CR core team, yes.

An excellent summary on how Hotwired and SR/CR interact is here: https://dev.to/hopsoft/rails-hotwire-cableready-and-stimulusreflex-are-bffs-4a89

The Twitter in 10 minutes video has an amazing legacy. It really woke people up to the possibilities of a reactive server-side solution based on Rails. However, it's over 18 months old at this point, and the libraries have figuratively exploded in functionality, userbase, documentation, and tooling ecosystem. We're now at the point where there's a double-digit number of serious tools that are built on SR/CR.

Unfortunately, YouTube videos are forever - so it's effectively four major releases behind.

As for the batches code, I say this with utmost respect: it's being invoked because that's what is installed in your project. I don't know how, I don't know why... but the only reason it could be there is because you put it there, even if you didn't realize that you were doing it.

That's okay, it's why I wrote out detailed instructions for you to fix it.

FWIW, most folks go to https://docs.stimulusreflex.com and follow the setup process to install. I can only hope that would have worked out better for you. It's important to note that Nate's video was a demo that was never described as a tutorial, no matter how approachable he succeeded in making it.

pitosalas commented 2 years ago

I can't thank you enough for your generosity in time and effort. If there was a tip jar I would use it!

An excellent summary on how Hotwired and SR/CR interact is here: https://dev.to/hopsoft/rails-hotwire-cableready-and-stimulusreflex-are-bffs-4a89 https://dev.to/hopsoft/rails-hotwire-cableready-and-stimulusreflex-are-bffs-4a89I will definitely study it in detail.

The Twitter in 10 minutes video has an amazing legacy. It really woke people up to the possibilities of a reactive server-side solution based on Rails. However, it's over 18 months old at this point, and the libraries have figuratively exploded in functionality, userbase, documentation, and tooling ecosystem. We're now at the point where there's a double-digit number of serious tools that are built on SR/CR.

Unfortunately, YouTube videos are forever - so it's effectively four major releases behin

Ok so I will stop worrying about it not working since I am fighting last years battle. It would be nice though if somehow the video can be deprecated or at least given a disclaimer banner in the front ("the concepts are correct but the detailed instructions don't work anymore" or something like that.

As for the batches code, I say this with utmost respect: it's being invoked because that's what is installed in your project. I don't know how, I don't know why... but the only reason it could be there is because you put it there, even if you didn't realize that you were doing it.

Yeah that's of course the case! I've been around this block often enough to not be surprised. That's okay, it's why I wrote out detailed instructions for you to fix it.

FWIW, most folks go to https://docs.stimulusreflex.com https://docs.stimulusreflex.com/ and follow the setup process to install. I can only hope that would have worked out better for you. It's important to note that Nate's video was a demo that was never described as a tutorial, no matter how approachable he succeeded in making it.

Ah yes. Good point. Can you recommend something in the form of a tutorial that is more up to date?

Thanks again! Let me know if I can ever return a favor :)

Pito Salas

leastbad commented 2 years ago

Amending YouTube videos - not a thing, so far as I know. Nate might be able to update the title and description, though... I'll bring it up with him.

https://courses.jasoncharnes.com/stimulus-reflex is excellent, though already a year behind (time flies!).

I honestly hope/believe/recommend that reading the docs should get you a long way. They are dense but well-written and comprehensive, hopefully even funny sometimes.

It's easy to repay me: learn SR/CR, build awesome stuff, tell your friends.

See you on Discord!

pitosalas commented 2 years ago

Excellent advice.

The video is actually still on your home page though: https://docs.stimulusreflex.com

How do I get an invite to the discord channel? I am facing the question now of what to use. There is stuff that is officially supported parts of Rails (active cable) and packages who have a good chance of getting into rails (hotwired) and excellent and super popular packages like stimulus reflex. I tend to advise my students to “stay near the center line” meaning, the further you stray from the “defaults” the more risk you are taking on.

And then there’s Rails 7. It’s already the case that hot-wired has at least two very confusing error messages during install for Rails 6 because it is already assuming Rails 7. Its a small thing but it shakes my confidence in hot-wired as to what other super subtle problems lurk if I am “just” using Rails 6. Those troubleshooting issues have to be traded off against the convenience and what my very specific requirements are.

Again, thanks!

Pito Salas Faculty, Computer Science Brandeis University

On Nov 19, 2021, at 9:47 AM, leastbad @.***> wrote:

Amending YouTube videos - not a thing, so far as I know. Nate might be able to update the title and description, though... I'll bring it up with him.

https://courses.jasoncharnes.com/stimulus-reflex is excellent, though already a year behind (time flies!).

I honestly hope/believe/recommend that reading the docs should get you a long way. They are dense but well-written and comprehensive, hopefully even funny sometimes.

It's easy to repay me: learn SR/CR, build awesome stuff, tell your friends.

See you on Discord!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

leastbad commented 2 years ago

Hi @pitosalas,

The video is on the homepage because it's still popular as a demo. The simple truth is that we don't have a massive rash of people interpreting it as a follow-along demo. I'm not saying that you were wrong-headed for doing so, just that the magic of evolution has led to a broad surface area neural possibility. 😉 Like I said, I am going to seriously discuss altering the description to prevent future misunderstanding. It's not under my direct control at this time.

I've included the Discord link a few times, and it's on the GitHub homepage and project docs: https://discord.gg/stimulus-reflex

Are you saying that it is asking you for something to sign up? That would be a huge problem, but we've had two more people this afternoon sign up... so I hope if you try the link again, it'll work this time.

StimulusReflex is an RPC framework that sits on top of ActionCable. It has an entirely different mental model than TurboFrames. TurboFrames is entirely based on form submission and largely works over HTTP fetch. SR doesn't just significantly predate Frames, it has a dramatically larger possibility space based on the nature of the tool... whereas the further your app is from Hey.com, the faster you will hit conceptual ceilings with Frames alone.

SR/CR also has excellent documentation, 24/7 live support, and a friendly, responsive team behind it.

If you're interested in seeing the kind of codebase that powers a real Reflex-powered app, check out a preview of this upcoming article and demo.