DEV Community

Cover image for Rails, Hotwire, CableReady, and StimulusReflex are BFFs

Posted on • Updated on

Rails, Hotwire, CableReady, and StimulusReflex are BFFs

Enforcing strict RESTful routes and controllers is perhaps the most impactful technique that influenced my usage of Ruby on Rails for the better. I cannot overstate how much I love traditional REST semantics and encourage their usage on every team that I have influence over.

Having said that, I also think rigidly applying this pattern to smaller and smaller use cases has diminishing returns. One example of a smaller use case is TurboFrames. TurboFrames are great and I use them along with their attendant REST semantics, but I try to be very thoughtful about how far I take this approach.

For example, libs like CableReady and Futurism can lazy load partials so unobtrusively that the notion of adhering to the formality of REST, with the required new routes, controllers, etc..., would be far too much ceremony for such small use cases.

One of the original goals of CableReady and StimulusReflex was to work seamlessly with traditional HTTP server rendered Rails apps (pre Hotwire) without requiring significant architectural changes or forcing a proliferation of new routes, controllers, or views/partials etc... We basically wanted a way to gradually introduce robust real-time and reactive behavior into traditional Rails apps with as little friction as possible. The idea being to allow people to leverage the work that had already been done rather than forcing a rethinking of the app. I view CableReady/StimulusReflex as: REST + RPC sprinkles + async server triggered DOM behavior.

Hotwire, while very cool, introduces new concepts that impose a higher cognitive cost and forces you to rethink how to best structure a Rails app. I view Hotwire as: REST semantics for everything + async server triggered CRUD updates.

There are pros and cons to each approach. Hotwire has more obvious and strict conventions, while CableReady and StimulusReflex adhere more to Ruby's philosophy of flexibility and expressiveness.

For me, using both Hotwire and CableReady + StimulusReflex techniques together is like "having my cake and eating it too." Admitedly, this is a power move and requires some experience to know when to apply each approach.

FYI - There are some great conversations on the StimulusReflex Discord server about this stuff. We'd love it if you joined us.

Also, I should note how much I dislike the umbrella marketing term "Hotwire" as it forces a false dichotomy in this conversation. Both CableReady and StimulusReflex are designed to work well with Hotwire libs and even have hard dependencies on some of them.

Top comments (4)

existentialmutt profile image
Rafe Rosen • Edited

I believe Rails uses a digest of the file contents as part of the cache key for partial templates, so any changes to templates will invalidate the cache if the templates are being cached directly.

I'll also keep a rails console open and call Rails.cache.clear when I need to reset things.

leastbad profile image

Great question! The quick answer is technically no, but almost certainly you'll turn it on.

Most SR devs will have caching enabled, because if you think about it, to not have it enabled means that you are hiding potential errors and undesirable behaviours that only manifest in production. The decision to turn off caching by default in Rails is one that has - in my opinion - done a lot of harm while creating a near-superstition that turning it on is somehow problematic or leaving the golden path.

I promise you that I can say confidently that turning on caching just means that you're able to use caching, including the low-level Rails.cache, which used to be a go-to for power users... at least until Kredis was released. If you turn on caching and don't use caching, it is exactly the same as not turning it on.

The bigger context here is really Redis and cookie-based sessions. Over time, it's become increasingly clear that Redis is one of the most powerful tools in our stack. If you're working with ActionCable, you 100% want to use Redis as your subscription manager (in config/cable.yml). Not only is it great for caching, the redis-session-store gem is vastly superior to storing sessions in Postgres - which Heroku users report can cause strange, intermittent logouts when Devise is in the picture. When you factor in the raw opportunity power of Kredis, doubling down on Redis becomes a no-brainer.

The real question, then, is why SR doesn't support cookie-based sessions. Websockets cannot write secure cookies, which get set during HTTP responses. The request that is available in an ActionCable Connection is the request that was used to upgrade the HTTP connection to WS. This means that when using cookie sessions inside the Connection, the session accessor that is provided by ActionDispatch is a cold snapshot. You can read values that were set before the WS connection was established, but newer changes are not available and worse, attempts to write to the session appear to succeed but are not committed to the real user session.

When all of this is considered, we decided to double-down, lead by example and march our developers to a better place: Redis-based caching enabled, Redis-backed sessions, using Kredis instead of the session object because it's 100x more useful, using Redis as the subscription adapter, using Sidekiq-backed ActiveJobs. All of these things make building asynch UIs with tools like CableReady smooth as butter.

hopsoft profile image

For the best experience, we recommend using the :cache_store for config.session_store (and enabling caching) in the development environment.

hopsoft profile image

Looks like @existentialmutt has the answer covered here: