Embedding serverside Ruby to opal files in rails - ruby-on-rails

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.

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.

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

Related

How can I get url of my attachment stored in active storage in my rails controller

How can I get url of my has_one model attachment stored in active storage in my rails controller. So, that I would be able to send it as full link as api in json.
So far, I have tried following methods but each of them are giving various issues:
current_user.image.service_url ---- undefined method `service_url' for #<ActiveStorage::Attached::One:0x....
Rails.application.routes.url_helpers.rails_disk_blob_path(current_user.image, only_path: true), it gives me an output like:
"/rails/blobs/%23%3CActiveStorage::Attached::One:0x007f991c7b41b8%3E"
but this is not a url, right? I am not able to hit and get image on browser.
url_for ----
undefined method `active_storage_attachment_url' for #<Api::V1::UsersController:0x007f991c1eaa98
Use the method rails_blob_path for attachements in a controller and models
For example, if you need to assign a variable (e.g. cover_url) in a controller, first you should include url_helpers and after use method rails_blob_path with some parameters. You can do the same in any model, worker etc.
Complete example below:
class ApplicationController < ActionController::Base
include Rails.application.routes.url_helpers
def index
#event = Event.first
cover_url = rails_blob_path(#event.cover, disposition: "attachment", only_path: true)
end
end
Sometimes, e.g. an API needs to return the full url with host / protocol for the clients (e.g. mobile phones etc.). In this case, passing the host parameter to all of the rails_blob_url calls is repetitive and not DRY. Even, you might need different settings in dev/test/prod to make it work.
If you are using ActionMailer and have already configuring that host/protocol in the environments/*.rb you can reuse the setting with rails_blob_url or rails_representation_url.
# in your config/environments/*.rb you might be already configuring ActionMailer
config.action_mailer.default_url_options = { host: 'www.my-site.com', protocol: 'https' }
I would recommend just calling the full Rails.application.url_helpers.rails_blob_url instead of dumping at least 50 methods into your model class (depending on your routes.rb), when you only need 2.
class MyModel < ApplicationModel
has_one_attached :logo
# linking to a variant full url
def logo_medium_variant_url
variant = logo.variant(resize: "1600x200>")
Rails.application.routes.url_helpers.rails_representation_url(
variant,
Rails.application.config.action_mailer.default_url_options
)
end
# linking to a original blob full url
def logo_blob_url
Rails.application.routes.url_helpers.rails_blob_url(
logo.blob,
Rails.application.config.action_mailer.default_url_options
)
end
end
I didn't have used rails active storage but what i have read in documentation this might help you
Try rails_blob_url(model.image)
For more http://edgeguides.rubyonrails.org/active_storage_overview.html
I was able to view the image in the browser using the following:
<%= link_to image_tag(upload.variant(resize: "100x100")), upload %>
Where upload is an attached image.

Displaying GET request from HTTparty on view

I currently have a simple ruby file named example.rb. How can I make a view that allows a user to submit information into a form and then have the information from the GET request returned to them? I understand how to use these requests from the console, but not from the front-end.
Resources on this topic would also be greatly appreciated.
require 'rubygems'
require 'httparty'
class StackExchange
include HTTParty
base_uri 'api.stackexchange.com'
def initialize(service, page)
#options = {query: {site: service}}
end
def questions
self.class.get('/2.2/questions', #options)
end
def users
self.class.get('/2.2/users', #options)
end
end
stack_exchange = StackExchange.new('stackoverflow',1)
puts stack_exchange.users
Make sure the HTTParty gem is in your application's Gemfile.
Take example.rb and put it in /app/models/stack_exchange.rb — yes the file name does matter[0] (this isn't the purists place to put this, but for beginners it's fine and perfectly acceptable). Remove the code at the bottom you're using to test it as well.
in routes.rb add this route: get '/test' => 'application#test'
in your application_controller.rb add this method:
def test
stack_client = StackExchange.new('stackoverflow', 1)
#users = stack_client.users
end
in app/views/application/test.html.erb put the following:
<% #users.each do |user| %><%=user.inspect%><br/><br/><% end %>
Note: I would otherwise recommend adding views to ApplicationController but because I don't know anything about your application, I'll default to it.
hit http://localhost:3000/test and you should see the expected result.
[0] Rails does a lot "magic" under the scenes — it's really not magic but metaprogramming — where it tries to assume a lot of things about your application structure and naming conventions. If your class was named Stackexchange (note the lowercase e), stackexchange.rb would be automatically "mapped" to the class Stackexchange. More info: http://guides.rubyonrails.org/autoloading_and_reloading_constants.html

Stuck in parsing URL and work with it in a view

Trying to parse a URL with this format http://landing.com?data=123 - I'm been able to get the Data through irb like:
require "addressable/uri"
uri = Addressable::URI.parse("http://landing.com?data=123")
uri.query_values['data']
=> '123'
But I'm stuck on how to interact with that 'data' within a Rails view. I have tried including it in Controller (pages_controller.rb in my sample) like:
class PagesController < InheritedResources::Base
def test
uri = Addressable::URI.parse("<%= request.original_url %>")
u = uri.query_values['data']
end
end
But no idea how can I extract that piece of data to be used within my Views. Any guidance on this?
If I open one of the views like where I call that 'test' method - I'm getting uninitialized constant PagesController::Addressable but made sure it's in my enviroment with gem which addressable/uri
Controllers have a lot of the query information already parsed. You can access it with params. In that case, you can use
u = params[:data]
As Sophie Déziel said, if it's under an app request, you can access to your query values through params hash. params is present in your controllers and views.
If you are talking about hardcoded URLs or URLS that you get from 3rd party sources, you will nee to create an instance variable in your controller (#u = ...) to be available in your views.
Note that you're not supposed to call action methods in your views, they are 'invoked' by Rails framework.
# controller
def my_action
# .....
#u = uri.query_values['data']
end
# view
<%= #u %>

How to translate email messages body using the I18n gem?

I am using Ruby on Rails 3.1.1 and I am trying to translate email messages body. I created/stated all necessary "things" (YAML files, key/value pairs, ...) to make the I18n gem to work: email messages are sent without problems using the default language (:en).
Then I added a new language and made all that had to be done to make the I18n gem to work with another language and to get always a locale=de parameter in URLs.
class ApplicationController < ActionController::Base
before_filter :set_locale
def set_locale
if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym)
I18n.locale = params[:locale]
end
end
...
end
However when I sent an email, even if the locale is properly set (eg: locale=de), sent email message are not translated (those still use the default :en language).
How can I make the I18n to translate email messages body?
I read the Localized ActionMailer Templates for Rails blog post
but it is old and I have not tested that...
I read the Rails I18n and emails blog post and I tested that. It works, but how can handle translation in my case (I am using the params method...)? Is there a better solution?
Solution
In your railsproject make a mailer (read http://guides.rubyonrails.org/action_mailer_basics.html how to make one). For example UserMailer.
rails g mailer UserMailer
Define a method for example mail_user.
def mail_user(user)
#user = user
mail(:to => "test example <testuser#testuser.com>", :subject => "hello")
end
Now define views. For example: mail_user.de.html.erb and mail_user.en.html.erb. Put your translations in there. If you want to translate variables seperatly use:
<%= I18n.t("foo.bar") %>
When you do this, ensure you have a en.yml and de.yml translation! Define a translation like the following example:
foo:
bar: hello
You should be ready to go.
How this works
ActionMailer works the following way. You can create mailer models which inherit from ActionMailer::Base. Like ActionController the models have associated views (templates) in the /app/views/ directory.
Now here is the technical part and why this all magicly works. ActionController and ActionMailer default include AbstractController::Rendering directly or indirectly (ActionController::Metal::Rendering). AbstractController::Rendering uses ActionView as default library for its template rendering engine and includes AbstractController::ViewPaths and an instance of I18n proxy to find localized views. To learn more i'd like to refer to the ActionPack source code on github.
To get to the point. ActionView allows you to use localisation in your templates: See Rails guide: Action View Overview , Chapter Localized views.

Undefined method 'url_for' while rendering a Rails 2.3.x template inside a ActiveRecord model

I know that this not an "acceptable" practice but as a background process I am caching a rendered Rails partial into the database for faster output via JSONP. I have found many resources on the topic and successfully output a Rails 2.3.x partial within a ActiveRecord model, BUT if I use dynamic URLs within a partial Rails blows up.
I get a successful output (minus the dynamic URLs) with this...
def self.compile_html
viewer = Class.new(ApplicationController)
path = ActionController::Base.view_paths rescue ActionController::Base.view_root
Question.all.each do |q|
q.html = ActionView::Base.new(path, {}, viewer).render(:partial => "questions/cached_output", :locals => { :question => q })
sleep 1 # hold for complete output and debugging only
q.save( false ) # bypass validations
end
return "Caching complete"
end
I have tried including ActionController::UrlWriter Modules and ActionView::Helpers::UrlHelper with no luck. I cannot seems to find the instantiation/inclusion order to allow the partial to access ActionController::Base.new.url_for() to write the dynamic routes to the partial.
I did attempt a similar process as RoR: undefined method `url_for' for nil:NilClass without luck
I know that render_anywhere is a solution for Rails 3.x apps, but I am working in Rails 2.3.11
Thoughts?
I have an old app that I had to do something similar (but made use of polymorphic_path and polymorphic_url) in a model.
The following includes gave me access to url_for and polymorphic_path etc.
include ActionView::Helpers::UrlHelper
include ActionView::Helpers::TagHelper
include ActionController::PolymorphicRoutes
include ActionController::UrlWriter

Resources