Accessing Variables in Rails 3 before_save Method - ruby-on-rails

I have the following before_save method:
def get_data
url = "http://www.api-fetching-url.com/where_my_data_input_is=#{self.my_data}&output=json"
new_data = HTTParty.get(url)
#field_to_update = new_data['one']['two']['here']
self.field_to_update = #field_to_update
end
Unfortunately, the self.my_data doesn't appear to be working, because the JSON url doesn't produce any result. But, when I substitute my_data in the hardcoded way, it works just fine. Moreover, I can do a find in the Rails console and get the my_data field just fine. So, it's not an issue with that field not saving or something on the form side.
Is there an issue inserting data this way in a before_save method? If not, is there a different way of doing this that I'm missing?

Some remarks:
You don't have to (and actually can't) always call methods with the self receiver. Private methods for example can only be called without an explicit receiver, so no self. for private methods...
Why don't you inspect the url and check whether it is correct? Just add puts url after the line where you assign the url, run your program and check the output. Is the url correct?
You probably use HTTParty not correctly: HTTParty.get('...') returns a response object and you probably have to parse the response's body properly.
An example for a JSON service:
url = 'http://service.com/path/to/resource.json'
response = HTTParty.get url
data = JSON.parse(response.body)
# now you can use the data, e.g.
# bla = data['one']['foo']

Related

How to pass large data set between controllers in Rails

Currently passing retrieved data using redirect_to which uses GET. Since in some cases data set is large, URI is too long and throws Bad Request error.
All online research says its a bad idea to pass data in GET body. Is there a better way to pass data to another controller?
Code Block
def create
response_body = http_get('/data/I/want')
parsed_result = JSON.parse(response_body)
check_response(parsed_result)
redirect_to controller: :search_results, action: :index, results: parsed_result
end
end point called in create is search results so need to check if results are empty before redirecting and passing the data. I omitted this part from the code block
Any reason to put these code in create method? From my point of view, your code doesn't really create anything. It is just get some JSON data from a remote URL and redirect to search_results#index. Why not just load the JSON in search_results#index directly?
Update
It is too generous to use more than 3 routes for a search action. I have two suggestions:
Search in remote JSON if you can control it. Just pass the searching keyword in URL and let remote resolve it.
If you cannot control the remote JSON, do the search with AJAX call. In your search_results#index, makes an AJAX call to your something like search#new JSON route and fetch the filtered result.

How to parse incoming JSON from my controller?

I am JSON posting the following JSON to my controller:
{"user_id": 234324, "user_action": 2, "updated_email": "asdf#asdf.com" }
In my controller I can see the JSON is correctly POSTED but I am not sure how to access it:
def update_email
puts request.body.read.html_safe
user_id = params[:user_id]
user = User.find(user_id)
end
I am testing this in my controller_spec and currently it is throwing an exception and is showing the id is empty.
This may be a duplicate - see: How do I parse JSON with Ruby on Rails?
I'm not sure how you're passing the JSON. Is it part of the POST params? In the header? Or something else. My guess is that you're either passing it as a param or should do so: e.g. myJson = {"user_id": 234324, "user_action": 2, "updated_email": "asdf#asdf.com" }
As far as parsing it goes, you should be able to use the built-in JSON class for this.
hash = JSON.parse params["myJson"]
Accessing it with params is the right way.
In your case:
params["user_id"] # => 234324
request.body.read shouldn't be used in real world, just for debugging, as action_dispatch does all the dispatch for you (like parse JSON or form data).
Note: you need to have the correct headers set, to let rails know that you're passing JSON.

Rails display JSON from an api GET request

I'm a rails beginner and I'm trying to display a json object I get back from an external api. I'm using HTTParty and I'm almost positive I have that set up correctly. I have a function in my HTTParty class called
self.get_all()
How would I go about making a new page on which to display the JSON I get back from that function?
It all pretty much depends on the json that comes back. Aside from it being 'JSON`, what does it look like? If you haven't even inspected it yet, maybe that's a good place to start. You can call your method like so: (pick one)
puts your_httparty_class.get_all.inpsect # will be displayed in your logs (most likely)
raise your_httparty_class.get_all.inspect # will raise the response to the view
You may find yourself needing to do something like this to ensure it's a hash.
response = HTTParty.get('https://api.somesite.com/some_endpoint')
body = JSON.parse(response.body)
Now that you know and can see that the JSON is just a hash you can access it like so:
something = body[:something] # accessing a hash
nested_something = body[:something][:nested_something] # accessing a nested hash
You can then move something and nested_something around your app. So, you could pass it from your controller to your view as instance variables:
# # makes it an instance variable and therefore accessible to your controller's views
#something = body[:something]
#nested_something = body[:something][:nested_something]

Ruby on Rails - Storing XML in a Temporary File

I want to be able to store my xml into a temporary file and then send it to another method in another controller to be processed. Currently it will not allow me to read the file, once sent, because it is a private method.
Controller #1
xml_doc = Nokogiri::XML(#builder.to_xml)
#tempfile = Tempfile.new('xml')
#tempfile.write(xml_doc)
redirect_to upload_xml_admin_events_path(:file => #tempfile)
Controller #2
Version #1
xml = params[:file].read
xmldoc = Nokogiri::XML(xml)
Gives me this error: undefined method `read' for "File:0x6ebfb00":String
Version #2
xml = params[:file]
xml.open
xmldoc = Nokogiri::XML(xml)
Gives me this error: private method `open' called for "#File:0x6a12bd8":String
It seems like you are thinking that params can be objects, which can be forgiven due to Rails magic. In reality all params are strings with a key in the key=value format.
So the issue here is that when you redirect with the parameter 'file', it turns your Tempfile object into a string. This is why the error is telling you that there are no accessible methods called read or open for a string. I see a few options:
Do whatever you are going to do with the file on Controller 1 instead of redirecting to Controller 2. You won't have to create extra objects, hit a database, or have crazy parameters in your URL.
If the XML can be really large, it might be better to make an AR object called XmlFile or something and write it to the database in Controller 1, then redirect with that id in the parameters. This way, you won't have to send crazy long XML strings in the URL (which is bad):
# Controller 1
#xml = XmlFile.new(#builder.to_xml)
redirect_to upload_xml_admin_events_path(:xml => #xml) #implicitly #xml.to_s
# Controller 2
#xml = XmlFile.find(params[:xml])
Nokogiri::XML(#xml)
If the XML is always (very) small, you can send the XML as a param in plain text (this seems to be closest to what you are currently doing, but strikes me as less elegant) You might run into URL encoding issues here though.
# Controller 1
xml = #builder.to_xml
redirect_to upload_xml_admin_events_path(:xml => xml)
# Controller 2
#xml = Nokogiri::XML(params[:xml])

Serializing Simple JSON String with Rails ActiveResource

I have a RESTful API call that acts like this:
HTTP GET http://addresss:port/settings/{setting}
which returns just the value of the setting specified as a simple string:
"settingValue"
I want to retrieve this value using a subclass of ActiveResource:Base
class Settings < ActiveResource:Base
self.site = CONFIG['uri']
self.collection_name = 'settings'
self.format = :json
...
end
But when I call Settings.find("Setting"), I get unexpected token at '"settingValue"'.
I could change the format of the data returned from the API, but is there anyway to get Rails to correctly handle this data?
Your api doesn't render json so Active Resource fails when it tries to parse a mere text.
Use another means to communicate with apis like restclient

Resources