Is it possible to embed serverside ruby to Opal .js.rb files?
In other words I need to access for example User.find(1)
in some opal file in Rails, like one would do with .erb.

- 12,102
- 17
- 78
- 152

- 715
- 7
- 20
2 Answers
Works like this out of the box in Reactive-Record. Otherwise you have to build some kind of api between the client + v8 prerendering engine and the server to get the data (which is what reactive-record does.) You can look at reactive-ruby and reactive-record's code in the files labeled "isomorphic..." See the React.rb Reactive-Ruby branch readme for more info.

- 2,838
- 1
- 22
- 29
It sounds like you're looking for a way to pass data to the client in the initial request. If you load the data in the server app and just want to pass it along, you can look into the gon
gem.
TL;DR version
Here's enough to get your feet wet
# Gemfile
gem 'gon'
# app/controllers/my_controller.rb
class MyController < ApplicationController
before_action { gon.push current_user: User.find(session[:user_id]) }
end
# app/views/layouts/application.html.erb
<head>
<%= include_gon %>
</head>
# app/assets/javascripts/application.rb
require 'native' # To be able to convert JS objects to hashes.
current_user = User.new(Hash.new(`gon.current_user`))
The explanation:
The gon
gem sets up a hash that will be JS-objectified and placed into your JS runtime in the browser. For more info on that, see the Railscast about it (it's still mostly relevant, not much has changed).
In the browser, that JS object is also named gon
, so gon.current_user
would be whatever you set in gon.push current_user: some_user
in the controller action (or before_action callback).
But we'll need to convert that from a JS object to a Ruby hash using Hash.new(gon.current_user)
, then you can pass that resulting hash to a User.new
call.
The important part: you'll need to have a User
class in your Opal app. If your Rails app sets up User
an ActiveRecord model, you won't be able to reuse it, so you'll need to create a new one, but if it's just a PORO (plain-old Ruby object), you can add the following line to an initializer:
Opal.append_path Rails.root.join('app', 'shared')
Then you can put Ruby code that you want available in both your Rails app and your Opal app in app/shared
. For example, you could do this in app/shared/user.rb
:
class User
attr_reader :id, :name, :email
def initialize(attributes={})
attributes.each do |attr, value|
instance_variable_set "@#{attr}", value
end
end
end

- 106
- 3