0

I am trying to follow an action cable tutorial that I believe was done on an older version of rails. They used the function below in CoffeeScript. However, when I try to run it, the console prints out the error appended to the code block of the respective attempts. The first block is the tutorial, the second block is me trying to work around the problem.

The thing is that the tutorial doesn't explicitly explain the purpose of APP or what it represents.

(function() {
    this.App || (this.App = {});
    App.cable = ActionCable.createConsumer();
}).call(this);

Error:
CoffeeScriptError: C:\Users\User\Documents\Projects\ror\ror-portfolio-1-dev-match-master\app\javascript\packs\application_coffee.coffee:23:2: error: reserved word 'function'
(function() {
cableFunc {
    this.App || (this.App = {});
    App.cable = ActionCable.createConsumer();
}

cableFunc()

Error:
CoffeeScriptError: C:\Users\User\Documents\Projects\ror\ror-portfolio-1-dev-match-master\app\javascript\packs\application_coffee.coffee:24:2: error: unexpected this
    this.App || (this.App = {});

If someone could tell me why this isn't compiling, cause as far as it goes the CoffeScript should not be throwing the error it is throwing, I would be grateful.

Also, I used webpacker:install:coffee to setup CoffeeScript in my application.

2
  • yikes, which tutorial are you following? Commented Jun 4, 2020 at 14:42
  • @Thankyou https://www.sitepoint.com/rails-and-actioncable-adding-advanced-features/ I believe it is an old one. Commented Jun 5, 2020 at 20:51

1 Answer 1

2

A simple js2coffee conversion will yield:

(->
  @App or (@App = {})
  App.cable = ActionCable.createConsumer()
).call this

The pattern:

(function() {
    this.App || (this.App = {});
    App.cable = ActionCable.createConsumer();
}).call(this);

Is a dated but pretty common JS idiom for defining globals. Altough using an IIFE (Immediately Invoked Function Expression) is found more oftenly then the use of call and this.

(function(global) {
  global.App || (global.App = {});
  App.cable = ActionCable.createConsumer();
}(window));

The idea was that instead of each library pulting the global scope with its functions (or augmenting built in objects like Prototype did) it sticks to its own object in the global scope. Wrapping the declaration in a function creates a scope where you can declare "private" functions and variables without them leaking into the global scope.

This idiom predates true javascript modules and the exports and imports keywords. Its about as hip in 2020 as the <marquee> element and will not work as intended with webpack.

This is because webpacker will actually treat imports as modules and this is not treated as the global scope as it was in spockets that just concatenated the file contents together.

Instead you need to explicitly pass the global scope.

(->
  @App or (@App = {})
  App.cable = ActionCable.createConsumer()
).call window
Sign up to request clarification or add additional context in comments.

1 Comment

Great explanation. Just to add the reason for the specific error from the question is wrong syntax for a function in coffeescript. It should be cableFunc = -> ... instead of cableFunc {...}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.