Make Rails return response from other local URL - ruby-on-rails

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

Related

How to get the myshopify_domain from a ShopifyApp::Authenticated controller without an API call

I am trying to reduce unnecessary calls to the Shopify API from a controller that inherits from ShopifyApp::AuthenticatedController, for example to get the myshopify_domain:
myshopify_domain = ShopifyAPI::Shop.current.myshopify_domain
Is there some method in ShopifyApp::SessionRepository or somewhere else in the ShopifyApp that I can call to retrieve Shop.current.myshopify_domain without making an actual call to the Shopify API webservice? If not, can I store the myshopify_domain, once retrieved, in the ShopifyApp::SessionRepository?
If you are in the AuthenticatedController, dump the following to the console:
session.to_json
You will see that you can access all sorts of stuff about the current session, such as:
session["shopify_domain"]
session["shop_id"]
I had the same problem with a muli-store app, where I needed to pull data tied to a specific store. ShopifyAPI::Shop.current.myshopify_domain is redundant in that you are slowing down the controller waiting for Shopify's response, and you are tinking down the api bucket limit. The session object is the superior method to avoid all of that, and should be accessible from any controller which inherits the ShopifyApp::Authenticated controller.
Your question is confusing. At the point where you are doing calls to the API, you clearly already know the myshopify_domain, as you cannot do API calls with that the shops name and token.
So now we're past that point, and you are asking how you can somehow have the myshopify_domain be more convenient for you to use? Just make yourself a little helper so that when you open a session, you have access to shop_name or whatever you want.
Shopify always sends you shop name in their requests, so you're covered there as it's a param, and your own interface code and calls will also be setting up the shop name too, so you're really now into some pretty esoteric territory to need anything else.
Seem like you're caught in a classic "the dog chasing its own tail", but why?
The myshopify_domain is usually available in the session parameters:
if !session[:myshopify_domain].nil? && !session[:myshopify_domain].empty?
session[:myshopify_domain]
else
session[:myshopify_domain] = ShopifyAPI::Shop.current.myshopify_domain
end

How to make a rails server wide object?

I am using the RedditKit gem and in order to access certain elements, I need to send a request to reddit api to create a "client" object. Below is my current logic:
## application_controller
before_action :redditkit_login
private
def redditkit_login
#client = RedditKit::Client.new ENV["reddit_username"], ENV["reddit_password"]
end
As you can see in my logic here, before EVERY REQUEST, I am subsequently making a new client object and then using that everywhere.
My question is, how do I only make one client object which can be used to serve ALL requests from anywhere?
My motive behind this is speed. For every request to server, I am making a new request to reddit and then responding to the original request. I want to have the client object readily available at all times.
You have a lot of options. A simple one would be to create a config/initializers/reddit_client.rb file and put in there:
RedditClient = RedditKit::Client.new ENV.fetch("reddit_username"), ENV("reddit_password")
(note I switched to ENV.fetch because it will error if the key is not found, which can be helpful).
You could also rename the file as app/models/reddit_client.rb. Although it's not really a model, that folder is also autoloaded so it should work as well.

Rails API and Strong PARAMS

I am trying to create an api to create record Foo using the rails-api gem.
I initially ran the generator command to tell rails to create a controller for me and it created this:
def create
#foo = Foo.new(foo_params)
#foo.save
respond_with(#foo)
end
And this (Strong params):
def foo_params
params.require(:foo).permit(:bar)
end
This is pretty standard stuff and will work when using form_for to submit data to the create method.
In my case, I'm creating a stand-alone API web service that will only interact via external API calls.
So the issue that I'm experiencing, is I don't know how to post the :bar param via API. I tried posting a :bar param, but this leads to a 'param is missing or the value is empty: foo' error. I understand why this is happening, but I have no idea how to get around this...
Is there a better way to do this or should I provide the api param in a different way?
PS. Currently my api POST call looks like this:
http://localhost:3000/api/v1/foo.json?bar=test#mail.com
you cannot use the ?+argument at the end of the url for a POST HTTP request, it's only for a GET request.
You must use the data component of the HTTP call, that is not embedded in the URL
therefore, you cannot just make this from your browser address bar and must use curl or a great tool as Postman (free on the chrome App Store)
and in this data field, you can include the object you want to post (postman gives you a neat key value interface to do so)
let me know if you need more details on the curl function for command line calls, but I recommend that you use a nice tool as Postman, so useful if you're not used to these calls
EDIT : this is the URL to get Postman : https://www.getpostman.com

Generate XML dynamically and post it to a web service in Rails

I am currently developing a Rails app in which I need to dynamically send XML request to an external web service. I've never done this before and I a bit lost.
More precisely I need to send requests to my logistic partner when the status of an order is updated. For instance when an order is confirmed I need to send data such as the customer's address, the pickup address, etc...
I intended to use the XML builder to dynamically generate the request and Net:HTTP or HTTParty to post the request, based on this example.
Is that the right way to do so? How can I generate the XML request outside the controller and then use it in HTTParty or Net:HTTP?
Thanks for your help,
Clem
That method will work just fine.
As for how to get the XML where you need it, just pass it around like any other data. You can use the Builder representation, which will automatically convert to a String as appropriate, or you can pass around a stringified (to_s) version of the Builder object.
If, for example, it makes sense for your model (which we'll call OrderStatus) to generate the XML, and for your controller to post the request:
# Model (order_status.rb)
def to_xml
xml = Builder::XmlMarkup.new
... # Your code here
xml
end
# Controller (order_statuses_controller.rb)
def some_method
#order_status = OrderStatus.find(:some_criteria)
... # Your code here
http = Net::HTTP.new("www.thewebservicedomain.com")
response = http.post("/some/path/here", #order_status.to_xml)
end
You may want to wrap the HTTP calls in a begin/rescue/end block and do something with the response, but otherwise it's all pretty straightforward and simple.
Make XML with Builder, then send it down the wire.
In your case it sounds like you may need to send several different requests as the order evolves; in that case:
Plan out what your possible order states are.
Determine what data needs to be sent for each state.
Decide how to represent that state within your models, so you can send the appropriate request when the state changes.
Where my example uses one method to generate XML, maybe you'll want 5 methods to handle 5 possible order states.

Encrypting Parameters across controllers

I need to pass a parameter from one method in a controller to another.
From my understanding I have to pass the parameters as a GET exposing it in the url string.
What is the best way to encrypt the data so no one can see what is actually getting passed in the string? Also, is there a way to pass it via POST or is my original understanding correct?
I haven't used RoR, but in the web world, this problem is solved with sessions. Using sessions you can store the parameters on the server and avoid sending sensitive data with GET or POST (both are insecure).
The Ruby on Rails Security Guide looks like a great read related to this.
I suggest you abstract your code into lib/ so that you don't have to call additional methods. Instead of making a new HTTP request, just put the code in a central place and call it from there.
class MyController < ApplicationController
def index
MyLibrary::Thing.do_stuff
end
def show
MyLibrary::Thing.do_stuff
end
end
# lib/my_library/thing.rb
module MyLibrary
module Thing
def self.do_stuff
# do stuff!
end
end
end
That way you can access the same code in multiple actions, without doing extra HTTP requests.

Resources