How do I get environment variables in Rails from inside a gem? - ruby-on-rails

I'm making a Ruby on Rails gem and need access to variables like cookie or the query parameters. How do I get this from inside a gem?
module MyModule
def self.my_method
# need access to cookies, query params, etc
end
end
So that from a controller or view, I can call
MyModule.my_method
and it'll have the access it needs.

You need to pass in what you want. Whether you want to pass in each individually or pass in the request object and pull out what you want depends on how/where you'll use your gem. I would lean towards passing in each individually in a well defined format so there aren't any surprises b/n rails servers and what the request object looks like.

Related

How to access params hash in lib directory rails 6

In my rails app, I am using Kramdown to parse Markdown. I want to extend the functionality of the convert_a method in the HTML converter. Part of this involves accessing the database, but it is dependent on a parameter in the URL. Because I am not directly calling the method that I am overriding I cannot simply pass the method the params hash. Is there a way to access this hash, or even just get the current URL in a module in the lib directory?
to give a bit more context, the method call is in a helper method here:
# in app/helpers/myhelper.rb
def to_html(text)
Kramdown::Document.new(text, parse_block_html: true).to_custom_html
end
and here is the file in which I override the convert_a:
# in lib/custom_html.rb
class CustomHtml < Kramdown::Converter::Html
def convert_a(el, indent)
# use params[:foo] to make query
format_as_span_html(el.type, el.attr, inner(el, indent))
end
end
Edit:
To give a bit more context on where the overrided method is called. I am not extremely familiar with the Kramdown codebase, however it seems that when to_custom_html is called the following bit of code is run inside of Kramdown.rb:
output, warnings = Converter.const_get(name).convert(#root, #options)
which subsequently calls convert_#{el.type} on the internal kramdown elements.
You can pass additional options in Kramdown::Document#new, so just do something like Kramdown::Document.new(text, my_params: params). Then you can use the #options method of the converter to access your params.

Does rails provide a request context?

I'm new to rails, I'm trying to figure out if rails have a request context where I can store variables and access them across the context of the request? I'm using rails 4.2.11.
I've tried to have a before filter in
class ApplicationController < ActionController::Base
before_action :set_request_context
def set_request_context
Thread.current[:request_context] = {:correlation_id => "some_unique_id"}
end
end
And then I'm accessing this variable else where in code. I'm sure this is not the right way because the application runs on ngnix and it may not guarantee that a request would be served by a single thread throughout.
When a request is processed within the method of the mapped controller a new object of a class is instantiated which needs access to this request_context.
class CreditCardPaymentsController < ApplicationController
def new
#paypage_id=PaypageIdRequest.new(:merchant_id => merchant_id)
end
end
Within the methods of PaypageIdRequest class I need to access the correlation_id I've set in :request_context.
Please note that I cannot send the variable to PaypageIdRequest class at the time of initialisation because there are so many places I'll have to send this variable and it would be bad practice to send it at all places considering Aspect Oriented Programming.
In Rails (and Rack applications in general) you have env which is a hash like object that contains the request object. env is used by middleware like Warden to inject themselves into your application.
However this is not a global. It is available in the routes, the controller and in views but not in models which are not request aware, neither is it available on whatever else you add to the MVC model like service objects or decorators unless you pass it.
If you want it to be available in your PaypageIdRequest class you need to use constuctor or method injection or make whatever you are saving a global.
Yes, Rails offers this functionality through it's CurrentAttributes API.
https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html

ACRCloud webapi in Rails

I'm a newb hobbyist developer. Can I just throw this repo of their ACRCloud's ruby example code into a controller? I'd like to use an audio fingerprinting song recognition database as a name validation for songs users are uploading using paperclip. Not sure if it's possible, just starting to research it, any hints or suggestions would be appreciated.
Obviously I'd have to replace
file_name = ARGV[0]
etc, but I'm also wondering about the require 'openssl' etc
Definitely! But there are few points to be taken care of. That's a pure ruby script, when it comes to rails there are certain rules/best practices. One of which is thin controller and fat model..
You need to create a route/action in your app which will ask the app to execute this request with required params.
Write a method in your model which contains the code and call it from controller and pass the permitted params to it.
Instead of hardcoding your credentials in the model, make them environment variables.
Would suggest using Httparty gem wgich will reduce many lines of your code and you just need to pass headers, params, etc. as hash in the arguments.
Last, but not the least...if you notice..there's a puts in the end however, rails uses mvc and so you need to have a view for the controller action you created in step1. Return and save the response.body in the class variable like #response = res.body and you can play with the body depending on the response type.
Hope it helps..
P.S. I wish I could write few lines of code/optimise it for you but i m using my mobile right now. But I think this much information should be enough to convert that script to mvc rails structure..

How can I make session data available to my ruby gem in a thread safe way?

I have a API gem which is a public helper library that uses faraday to make resourceful requests to my API. I would like to make a middleware that checks if session data is present (in the form of a hash) and if so would merge these values into the arguments of any request that faraday makes.
My initial attempt involved setting a metaclass attr_accessor (global_params) in the gem's top level class (i.e. MyGem.global_params). The middleware could check this variable for necessary data. This meant that any ApplicationController that had access to my library could implement a before_filter that would set the global_params based on session data and an after_filter could clear it.. so that all faraday requests made by that instance of ApplicationController would share the same global_params set form the session data.
I now wonder if this is thread safe.. and if not what another way I could handle this is?
As for your other question, globals are almost always a sign of doing it wrong and should be avoided whenever possible.
What you need here is a factory method that can customize your context as required.
For example, you're probably doing something like this:
MyGem.global_arg = :foo
MyGem.new(...)
What you could do instead is this:
factory = MyGem.factory(:global_arg => :foo)
factory.new(...)
Or, to preserve a similar sort of feel:
factory = MyGem.factory do |factory|
factory.global_arg = :foo
end
Instead of creating a mattr_accessor in MyGem, you'd create one as an independent object of which MyGem could have a default instance of.

Make Rails return response from other local URL

I want a /plan method to return a json object that's itself returned by another local (but belonging to another web app in java) URL (let's call it /plan2 for the sake of this question).
What I want is not a redirect but really to have /plan return the data as it is returned by /plan2, to which I'm appending a bunch of other keys. Since the request is local, would using Net::HTTP be overkill? What are my options, considering I'd also like to send an HTTP Accept header along.
Shooting in the dark here, but I am assuming that /plan belongs to public Rails app and the /plan2 is the url from another web app (maybe not even Rails) on the same server accessible by Rails app but not publicly available. If this is the case, then yes, you can get the response, but I would suggest rather OpenURI or Mechanize than Net::HTTP. If you put it in respond_to JSON format block then everything should be fine with Accept header also.
are you speaking of re-using functionality of another controller-method?
there is no standard way of doing this in rails. you could either put the common functionality into a module and include it this way, or use inheritance if the functionality is in another controller. if it's the same controller class, you could just call the method.
if it's a "private" url, how are you going to call it via http?!
I would suggest encapsulating whatever functionality /plan2 uses and simply re-use that in /plan1
But if you just want to get it to work...
class PlanController < ApplicationController
def plan1
plan2(extra_parameter_1: true, extra_parameter_2: 'hello')
end
def plan2(extra = {})
params.merge!(extra)
# Whatever your code was before...
end
end

Resources