0

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.

ylluminate
  • 12,102
  • 17
  • 78
  • 152
ClassyPimp
  • 715
  • 7
  • 20

2 Answers2

1

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.

Mitch VanDuyn
  • 2,838
  • 1
  • 22
  • 29
1

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