cable_car aka 'Ajax mode'#108
Conversation
|
@leastbad Coming into this with very little context (looks like a killer API so far!) — if update: ah, I just noticed you did have |
|
Thanks! I'm just building on what was already here, and borrowing good ideas from @julianrubisch. The short answer is that the reason (I think) a terminating verb is necessary is that a render action is not the only place you might call this. In fact, the whole impetus behind doing it is to rework the backend so that there's a consistent queueing API and then loads of syntactic sugar (like the implicit render stuff) to keep up our BMW 7 Series vibe. The other wildcard is that @joshleblanc made a PR on this PR which I haven't had a chance to review, but my spidey sense tells me is going to have a major impact on what's already been done. |
|
This is exciting. I love the wordplay but would like to propose different semantics. operations = cable_car.inner_html(...).console_log(...).enqueued_operations
cable_car.dispatch # vs "ride", flushes enqueued_operations
cable_car.append(operations) # vs "apply", appends operations to enqueued_operations (alt option: enqueue) |
|
The new renderer also opens the door for ActionCable based responses. What do you think about this proposal? ActionController::Renderers.add :cable_car do
render json: cable_car.dispatch
end
ActionController::Renderers.add :cable_ready do
cable_ready.broadcast
head :ok
endclass HomeController < ApplicationController
def index
cable_car.console_log(message: "hi")
render :cable_car
end
def show
cable_ready.console_log(message: "hi")
render :cable_ready
end
endThat's not a complete example, but it communicates the idea. Let's go for the land grab and add support for a |
|
Exciting! I haven't watched closely but am thrilled to read all the docs afterwards 😜 |
|
You're not proposing that we make people put I prefer
I think that your I don't totally understand what you're proposing with |
Correct. This is already supported (but not required). I was just using it as an example of how to get a reference to some operations.
Good catch on cable_car.merge! operationsLet me expand on the renderers API a bit and see if we can land on something that everyone likes. The CableReady renderers are more challenging because CR is so incredibly flexible. cable_car# multi line example
def index
cable_car.console_log(message: "hi")
cable_car.console_log(message: "hi again")
render :cable_car
end
# single line example
def index
render cable_car: cable_car.console_log(message: "hi")
endcable_readydef index
render broadcast: cable_ready['string-identifier'].console_log(message: "hello world ")
end
def index
render broadcast: [
cable_ready['one'].console_log(message: "hello world from one"),
cable_ready['two'].console_log(message: "hello world from two")
]
end
def index
render broadcast_to: Helen.find(30), cable_ready[HelensChannel].console_log(message: "hello helen")
end
def index
render broadcast_to: Helen.find(30), [
cable_ready[HelensChannel1].console_log(message: "hello helen from 1"),
cable_ready[HelensChannel2].console_log(message: "hello helen from 2")
]
end |
|
I don't love Anything jump out at you here? https://www.merriam-webster.com/thesaurus/ingest Naming is super hard. The While I'm ultimately fine with switching from I understand the "what" for a From an implementation perspective, I agree that introducing a I would advise putting the resource after the I like the single-line forms (1 and 3, above) but the array-based multiple channel approach makes me hate the way 2 and 4 look. I might be biased because I still don't understand what this is for, but it just seems like one too-many permutations of syntax for my train to track effectively. 🧠 I feel like the same naming lens critique applies to I don't want to sound negative! I do want to carefully weigh every new code path for benefits vs the perceived complexity and decision fatigue of the library. |
|
standardrb is automatically converting @operation_builder.merge!(foobar: [{name: "passed_option"}])to @operation_builder[:foobar] = [{name: "passed_option"}]Which is definitely not what we want. Should we consider this a standardrb bug, or look at different names? |
|
Actually, maybe we should just get operation builder to respond to [] and []=. That would solve our problem and make it behave like one might expect? |
People have started to notice that you can call
CableReady.performanywhere, including outside of anActionCable#receivedcallback. @jonsgreen calls it inside of a custom CR operation, transforming it into a DSL for DOM manipulation. All you need is a viable JSON payload and you're good to go.As we prepare for a multi-transport future in SR, so too must CR adapt to non-ActionCable usage cases. This PR proposes
cable_car: a simplified, transport-agnostic class used for generating CableReady-compliant JSON payloads.cable_carhas an almost identical usage pattern as string identifier channels inside Reflex classes, except that instead ofbroadcast, chains are terminated by.dispatch.cable_caris a Singleton likecable_ready, and chains the same operations list from theconfigclass. Callingdispatchclears out the enqueued operations unless you call it withclear: false. It should be completely fine to usecable_readyandcable_caralongside each other simultaneously.Thanks to @joshleblanc, the Channel and CableCar are both subclasses that inherit from a new common superclass called OperationBuilder. This means that there is no duplicated code and further changes to OperationBuilder will benefit both.
I also removed what I believe were vestigal references to
@operationsfrom theChannelsclass.# {"innerHtml":[{"selector":"#users","html":"\u003cspan\u003ewinning\u003c/span\u003e"}],"setFocus":[{"selector":"#users"}],"playSound":[{"src":"song.mp3"}]}Serialized operations via the
apply!methodThere needs to be a simple way to turn serialized operations into enqueued operations.
The
apply!concept was lifted from @julianrubisch'scable_ready_callbacksgem, (where it was originallyapply).Keep in mind that while
dispatchreturns a Hash,apply!will accept both a Hash or a JSON string.I also made it so that both
channelsandcable_carnow have ato_jsonthat returns the JSON forenqueued_operationsinstead of the whole object, and this, too, can be passed intoapply!.Custom ActionController Renderer
Once again thanks to @joshleblanc, controllers can now respond with a CableReady JSON payload, ready to be passed into
CableReady.perform().