I am trying to use yrb-actioncable on Rails with yjs on Angular to have a collaborative text editor, I've never used ActionCable, Angular, Y.js, or CodeMirror before so I faced a lot of errors trying to make it work, I finally thought I had it when I stopped seeing any errors, but actually it still doesn't work.
I can see the editor on the screen and I can use collaborative editing between tabs of the same browser, I can see the requests to and from actioncable, but nothing else.
This is the whole repository, it's kind of a mess but I don't really know Angular and it's just a proof of concept to try and make things work. The DocumentChannel is the ActionCable part, the code-editor is the Angular component part. I'll paste them below too removing the commented and unused parts
require 'y-rb'
module ApplicationCable
class DocumentChannel < ApplicationCable::Channel
include Y::Actioncable::Sync
def initialize(connection, identifier, params = nil)
super
load { |id| load_doc 1 }
end
def subscribed
sync_from("document-1")
end
def receive(data)
sync_to("document-1", data)
end
def unsubscribed
end
private
def load_doc(id)
doc_content = Document.first.content
ydoc = Y::Doc.new
ytext = ydoc.get_text('mine')
ytext << doc_content
data = []
data = ydoc.diff unless doc_content.nil?
data
end
end
end
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'
import { OnInit } from '@angular/core';
import * as Y from "yjs";
import { WebsocketProvider } from "@y-rb/actioncable";
import CodeMirror from "codemirror";
import { CodeMirrorBinding } from 'y-codemirror'
import ActionCable from 'actioncable'
@Component({
selector: 'code-editor',
templateUrl: './code-editor.component.html',
styleUrls: ['./code-editor.component.scss']
})
export class CodeEditorComponent implements OnInit {
constructor(private http: HttpClient) {
}
ngOnInit() {
const accessToken = localStorage.getItem('accessToken')
const uid = localStorage.getItem('uid')
const client = localStorage.getItem('client')
const yDocument = new Y.Doc();
const consumer = ActionCable.createConsumer(`ws://localhost:3000/cable?uid=${uid}&access-token=${accessToken}&client=${client}`);
const provider = new WebsocketProvider(
yDocument,
consumer,
"ApplicationCable::DocumentChannel",
{}
);
const yText = yDocument.getText('codemirror')
const yUndoManager = new Y.UndoManager(yText)
const editorContainer = document.createElement('div')
editorContainer.setAttribute('id', 'editor')
document.body.insertBefore(editorContainer, null)
const editor = CodeMirror(editorContainer, {
mode: 'javascript',
lineNumbers: true,
})
const binding = new CodeMirrorBinding(yText, editor, provider.awareness, { yUndoManager })
// @ts-ignore
//window.example = { provider, ydoc, yText, binding, Y }
}
}
I can't seem to find what's wrong with it as I don't get any actual error, nor have I been able to get any more help from online guides nor the official docs that I've tried following. Could anyone guide me on this?
So, I managed to make it work, my frontend code didn't change much, but my backend code did, you can see the end result in this link, but I'll paste the channel here so you can see the differences.
Now I'm glad to say it works just fine ^^