Skip to content

josephschito/opal_stimulus

Repository files navigation

Opal Stimulus for Rails

Write your Stimulus controllers in Ruby instead of JavaScript! πŸŽ‰

Opal Stimulus uses the Opal Ruby-to-JavaScript compiler to bring the elegance of Ruby to your frontend controllers. If you love Ruby and prefer its syntax over JavaScript, this gem is for you.

Compatibility: Rails >= 7.2

Ruby

Click here to watch the walkthrough! πŸ‘‡

opal stimulus

Quick Start

Add to your Rails app and get started in seconds:

bundle add opal_stimulus
rails opal_stimulus:install
bin/dev

Generate your first Ruby controller:

bin/rails generate opal_stimulus hello

This creates app/opal/controllers/hello_controller.rb. If you have an existing JavaScript controller, you can remove it:

bin/rails destroy stimulus hello  # removes app/javascript/controllers/hello_controller.js

Example: Hello World

Here's the classic Stimulus example, but in Ruby! Compare with the JavaScript version.

Ruby Controller (app/opal/controllers/hello_controller.rb):

class HelloController < StimulusController
  self.targets = ["name", "output"]

  def greet
    output_target.text_content = "Hello, #{name_target.value}!"
  end
end

HTML (unchanged from regular Stimulus):

<div data-controller="hello">
  <input data-hello-target="name" type="text">
  <button data-action="click->hello#greet">Greet</button>
  <span data-hello-target="output"></span>
</div>

Key Differences from JavaScript Stimulus

  • Snake case: JavaScript's containerTarget becomes container_target in Ruby
  • DOM objects: All target, element, document, window, and event objects are JS::Proxy instances that provide Ruby-friendly access to JavaScript APIs
  • HTML stays the same: Your templates and data attributes work exactly like regular Stimulus

Reference Examples

Based on the Stimulus Reference, here's how common patterns work in Ruby:

Lifecycle Callbacks

πŸ“š Stimulus Lifecycle Callbacks Reference

class AlertController < StimulusController
  def initialize; end
  def connect; end
  def disconnect; end
end

Actions & Events

πŸ“š Stimulus Actions Reference

class WindowResizeController < StimulusController
  def resized(event)
    if !@resized && event.target.inner_width >= 1080
      puts "Full HD detected!"
      @resized = true
    end
  end
end

Targets

πŸ“š Stimulus Targets Reference

class ContainerController < StimulusController
  self.targets = ["container"]

  def container_target_connected
    container_target.inner_html = <<~HTML
      <h1>Test connected!</h1>
    HTML
  end

  def container_target_disconnected
    puts "Container disconnected!"
  end
end

Outlets

πŸ“š Stimulus Outlets Reference

class ChatController < StimulusController
  self.outlets = [ "user-status" ]

  def connect
    user_status_outlets.each do |status|
      puts status
    end
  end
end

Values

πŸ“š Stimulus Values Reference

class LoaderController < StimulusController
  self.values = { url: :string }

  def connect
    window.fetch(url_value).then do |response|
      response.json().then do |data|
        load_data(data)
      end
    end
  end

  private

  def load_data(data)
    # ...
  end
end

CSS Classes

πŸ“š Stimulus CSS Classes Reference

class SearchController < StimulusController
  self.classes = ["loading"]

  def load_results
    element.class_list.add(loading_class)
  end
end

Working with the DOM

Opal Stimulus gives you Ruby-friendly access to all the browser APIs you know and love:

window

class WindowController < StimulusController
  def connect
    window.alert "Hello world!"
    window.set_timeout(-> {
      puts "1. Timeout test OK (1s delay)"
    }, 1000)
  end
end

document

class DocumentController < StimulusController
  def connect
    document.querySelectorAll("h1").each do |h1|
      h1.text_content = "Opal is great!"
    end
  end
end

Development

Run the test suite:

bundle exec rake

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/josephschito/opal_stimulus.

License

The gem is available as open source under the terms of the MIT License.