In modern web development, reactive programming has become a popular paradigm for handling asynchronous data and event-driven systems. Observables, a key concept in reactive programming, allow developers to efficiently manage complex event flows and data streams. While Rails is traditionally used in a synchronous, request-response model, integrating observables into your application can significantly improve how you handle data updates, form submissions, and external events.

In this post, we will explore:
✔️ What observables are and how they work
✔️ How to integrate RxJS and ReactiveX with Rails
✔️ The benefits of using observables for asynchronous operations
✔️ Practical examples of applying observables in Rails applications


1. What are Observables?

An observable is a data structure that allows you to subscribe to and observe changes or events over time. It can represent a stream of values or events that can be observed by other parts of your application. In simple terms, an observable is a stream of data that you can react to as it changes.

Observables are commonly used to handle:

  • Asynchronous data (e.g., API calls)
  • User interactions (e.g., button clicks, form submissions)
  • Event-driven architectures

They allow you to write cleaner, more maintainable code by decoupling data sources from consumers and providing tools to handle data changes efficiently.


2. Why Use Observables in Rails?

Rails is primarily a server-side framework that follows a request-response cycle, which can sometimes feel limiting when dealing with complex, asynchronous operations. Observables help address this limitation by allowing you to react to data changes and events in real-time without blocking other parts of your application.

Some key benefits of integrating observables in Rails applications:

  • Asynchronous data handling: Easily manage async operations such as fetching data from APIs, processing user inputs, or waiting for events
  • Simplified event-driven architecture: Use observables to handle complex event flows, such as reacting to button clicks or real-time data updates
  • Improved UI responsiveness: Using observables in conjunction with front-end libraries like Vue.js or React enables smooth UI updates without reloading the page

3. Integrating RxJS with Rails

RxJS is a popular JavaScript library that provides powerful tools for working with observables. While Rails is a server-side framework, you can easily integrate RxJS with your front-end JavaScript to handle asynchronous operations.

Setting Up RxJS in a Rails Project

To integrate RxJS into your Rails application, first, install it via Webpack or yarn. Here’s how you can add RxJS to your project:

yarn add rxjs  

Once RxJS is installed, you can start using it in your JavaScript packs. Here’s a basic example of creating an observable for handling button click events:

import { fromEvent } from 'rxjs';

const button = document.querySelector('#myButton');  
const clickObservable = fromEvent(button, 'click');

clickObservable.subscribe(() => {  
console.log('Button clicked!');  
});  

In this example, every time the button is clicked, the event is emitted, and the observer responds by logging a message. This pattern can be extended to handle more complex event flows.


4. Using Observables for Real-Time Data Updates

One of the primary use cases for observables in Rails is real-time data updates. For instance, you can use an observable to listen to changes in data and update the UI accordingly without having to reload the page.

Example: Real-Time Notifications with ActionCable and RxJS

Rails’ ActionCable provides WebSocket support for real-time features, which works perfectly with observables. Here’s an example of using RxJS with ActionCable to handle real-time notifications:

import { createConsumer } from '@rails/actioncable';  
import { Observable } from 'rxjs';

const consumer = createConsumer('ws://localhost:3000/cable');

const channel = consumer.subscriptions.create({ channel: "NotificationsChannel" }, {  
received(data) {  
console.log('Received notification:', data);  
notificationObservable.next(data);  
}  
});

const notificationObservable = new Observable(observer => {  
observer.next('Initial notification');  
});

notificationObservable.subscribe(notification => {  
console.log('New notification:', notification);  
// update UI with the new notification  
});  

In this setup, when a new notification is received from the server, the observable pushes the data to all subscribers, who can then update the UI.


5. Managing Form Submissions with Observables

Another area where observables shine is in handling form submissions. Instead of using traditional synchronous form submission techniques, you can use observables to manage form data dynamically, validate inputs in real-time, and trigger asynchronous actions upon submission.

Example: Form Validation Using RxJS

In a Rails app, you can use RxJS to validate form fields in real time, reducing the need for page reloads or redundant form submissions. Here’s an example of how to validate an email field:

import { fromEvent } from 'rxjs';  
import { debounceTime, map, distinctUntilChanged } from 'rxjs/operators';

const emailInput = document.querySelector('#email');

const emailObservable = fromEvent(emailInput, 'input').pipe(  
debounceTime(300),  
map(event => event.target.value),  
distinctUntilChanged()  
);

emailObservable.subscribe(email => {  
const isValid = validateEmail(email);  
if (isValid) {  
console.log('Valid email');  
} else {  
console.log('Invalid email');  
}  
});

function validateEmail(email) {  
const regex = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;  
return regex.test(email);  
}  

This example shows how you can use RxJS to validate email input fields and prevent unnecessary form submissions.


6. Combining Observables with Background Jobs

Rails’ background job systems like Sidekiq or Resque work well with observables to manage complex workflows. You can emit events from background jobs and subscribe to those events in your frontend or other parts of your application, allowing you to track job progress, handle success/failure states, and update the UI.

Example: Job Progress with Observables

Let’s say you want to track the progress of a background job in real-time. You could use ActionCable and RxJS to achieve this:

const jobObservable = new Observable(observer => {  
// simulate job progress updates from ActionCable  
setInterval(() => {  
const progress = Math.floor(Math.random() * 100);  
observer.next(progress);  
}, 1000);  
});

jobObservable.subscribe(progress => {  
console.log(`Job progress: ${progress}%`);  
// update progress bar UI  
});  

In this example, the job’s progress is emitted every second, and the observer reacts by updating the progress bar in the UI.


7. Conclusion

Observables offer a powerful way to manage asynchronous data and event-driven architectures in your Rails applications. By integrating RxJS and ActionCable, you can easily handle real-time data updates, manage form validations, and react to complex workflows dynamically.

Whether you’re dealing with complex user interactions, real-time notifications, or asynchronous background jobs, integrating observables into your Rails application will help you manage data flows more efficiently, keeping your codebase clean and maintainable.

Start exploring reactive programming with observables today, and see how it can enhance your Rails applications!