How to pass large data set between controllers in Rails - ruby-on-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.

Related

How param works in rails views

I have an old app running in rails 2.3.5
In customizing, I stuck when i find a param keyword being used in views
i.e in views I can see stuffs like
unless params[:fee_collection].nil?
can someone explain to me in what context is param keyword used in rail views rather than controllers
params is a hash that contains parameters sent with the HTTP request.
You can access to this object as well from your controller or from a view. Although, the convention is to access to an instance variable (defined in your controller, e.g : #fee_collection = params[:fee_collection]) from your view.
The params variable stores a hash which contains the http parameters received in the request to this route (controller#action)
If you have a UserController with the show method, you should receive the param[:id] to identify the resource you're looking for.
If you want to send parameters, it would be either via url in a GET or a data payload on a POST request, on the most common cases.

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]

Which HTTP method should I use for request that can create or simply read a resource?

In my Rails application I have an url routed to an action in charged of showing or creating (if not existing) e resource. What is the appropriate http verb to use for this kind of request?
To be more precise, in my method I don't directly access the resource but I use a library which has that behavior: first search and then create the resource if not exiting. My method, in the end, always provide the resource returned by the library either a brand new one or an old one. Hence I cannot split into two requests.
According to this and considering my method always returns the same resource (idempotent) it seems that PUT should be the right one. I just wonder whether PUT can be used in case where e resource is actually just retrieved (get) and anything is not even updated
tnx
POST for creating, GET for showing is automatically used by rails. But I hope you can do all sorts of things with custom programming as data will be available to you in form of params[]
According to Ruby on Rails guides, you should use GET and POST verbs. More information here: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
You use GET to retrieve.
If resource found return 200 with resource.
If resource not found let it return 404 and check the error code and use POST and create the resource.
If you donot need any parameter while creating resource then you should use GET request Else if you need params while creating resource , then you should make separate action for creating(Post request with params) and showing(GET request) resource.

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.

Rails: Routes, Controllers, Views, Oh My(exclamation)

I'm failing to understand the correlation between routes, controllers, and views (and how they connect to each other).
So, I've got my controller with the index,show,new,create,destroy methods. And the corresponding
GET /entries(.:format) entries#index
POST /entries(.:format) entries#create
GET /entries/new(.:format) entries#new
GET /entries/:id/edit(.:format) entries#edit
GET /entries/:id(.:format) entries#show
PUT /entries/:id(.:format) entries#update
DELETE /entries/:id(.:format) entries#destroy
How come if I add a new method vote_up or vote_down, for example, and the views with matching action names, it doesn't work.
1) What is the proper way to add new actions and connect them to views?
2) Bonus What is the proper way to make these methods ajax-compatible (render a partial with ajax)? What happens if the user doesn't have js enabled?
I may expand/evolve this question based on the answers I get.
I'm tired of googling things like custom action route rails and the like to hodge-podge my apps. It's draining and poor form and I'm finally getting to the level to comprehend the lingo--I've been self taught 100%...so please try to be understanding if you can for a young padawan.
Here's how to think of it, from the beginning:
1) The one and only thing your app does is respond to HTTP REQUESTS.
The most typical kinds of requests are:
GET - the user types something into the URL bar of their browser and hits enter.
POST - the user submits a form.
There are also other kinds of HTTP requests, most importantly PUT, PATCH and DELETE. Rails follows the REST pattern, which means it assigns specific meanings to these HTTP verbs.
2) When any request comes into your app, it has to be routed to a Controller Action.
Your routes.rb file is a set of instructions for the Rails Router (ActionDispatch) that tells the router where to send requests. The "standard" rails resource is given as a shortcut, like this:
resources :things
This means the following:
GET /things => things#index
GET /things/:id => things#show
GET /things/new => things#new
GET /things/edit/:id => things#edit
POST /things => things#create
PUT /things/:id => things#update
DELETE /things/:id => things#destroy
These are considered the standard RESTful actions - nothing else is set by your resources :things declaration. So, if you want the controller to perform other non-standard actions, you have to add them manually.
If you want to perform an action on a specific record, the best way is to use:
resources :things do
member do
get 'vote_up'
end
end
This tells the router that if someone makes a GET request to /things/123/vote_up that it should trigger the ThingsController vote_up action.
All of this is spelled out in great detail in the Rails Guide, you should read the whole thing.
3) Your controller's job is to send a response to the request.
Normally this means something like loading a record from the database and rendering the view for that record.
Each controller action ends by sending the response back to the incoming request. This response can be either a render call - which means send back some data in some format - or a redirect call - which basically makes a new request for you and therefore you get the response of that other request.
In Rails a redirect is effectively sending the request to a different controller action.
A Render call sends data as a response to the request.
When you call render :new, this is a shortcut to render :template => :new, which loads the app/views/things/new.html.erb (or whatever) template, sends it the data from the controller (normally your instance variables) and evaluates this using the template language (erb, haml, etc.) This results in a big string of HTML, which the controller then delivers to the browser.
Want to see what this for yourself? Try ending a controller with render :text => 'Hello World', or even:
render :inline => '<!DOCTYPE html><head><title>Inline Wow!</title></head><body>Mind blown.</body></html>'
See what happens.
When responding (rendering) you can send "normal" HTML templates, with a whole page worth of information in it (head, body, etc.), or a partial that is used by Ajax. You can also send raw data such as JSON or XML. It's all actually just text, and depending on the content of that text (and the HTTP headers that come with it) the browser, script, or client application handles it accordingly.
Again, see the Rails Guide.
4) When the request is made by a browser you probably want to send back HTML. If the request is made by Ajax you probably want to send back JSON.
In the case of a custom action like vote_up you might not want to show a template at all, but just redirect. So, you might have something like this:
ThingsController < ApplicationController
def vote_up
#thing = Thing.find(params[:id])
#thing.vote_up
redirect_to #thing
end
end
Now, one of the benefits of the router is it will give you URL helpers. If you've created the route and action as shown before, on your "show thing" page you could have a URL like this:
link_to 'Vote up this thing!', vote_up_thing_path(#thing)
That would create a link to things/123/vote_up, and if someone clicked on it it would run the code in the vote_up action on the ThingsController, and then redirect back to the show thing view.
5) Your templates send messages to the controllers using links and forms. Links make GET requests, forms make POST requests.
If you want to start having AJAX requests, that's fine. In that case, you just need to make the request in Javascript, and handle the response. So, for instance, you could put something like this in your template:
= link_to 'Vote up this thing', vote_up_thing_path(#thing), :id => 'vote-up-button'
Then in Javascript (with jQuery) you could have a function like this:
$(function(){
$('a#vote-up-button').click( function(event){
event.preventDefault();
$.ajax({
url: this.attr('href'),
type: 'GET',
success: function(){...},
error: function(){...}
});
});
});
In this case the jQuery Ajax method is just making a get request, and then running a callback function based on the response it got.
6) The structure of your controller/routes does not affect what kind of requests you can make, only what action will respond to what HTTP method on what URL.
What you do INSIDE your controller action determines whether you are ready to respond to javascript or html requests etc.
While rails is certainly able to handle multiple request formats in a single controller action, using the respond_to block, as a matter of practicality I find things work much more smoothly when you choose to have routes only respond to one format or another.
IE: I would make your normal page load requests (index, show, new, edit) just HTML requests, and then I would make any additional AJAX actions you want to add be Javascript only -- ie. they respond with JSON instead of HTML. You don't have to do this, of course, but your life will be easier if you do.
I hope this gives you a clearer sense of what is happening in your app. Welcome to Rails, you're joining a great community!
Welcome to the ROR world. :)
Routes, controllers, and views work together to translate a HTTP request into a response of some kind (be it HTML, JSON, or XML). Each attacks a different piece of the problem.
Starting from the end, views are the templates in the rails world and they typically are ERB. ERB is just one templating system, others can be used as well, like haml. Their job is to take some data given to them by the controller and produce formatted output, again typically HTML, JSON, or XML.
But how do you know which view to render for a particular request? How do you get data into your view so that it can do all the fancy dynamic stuff you need? This is where controllers come in. Controllers are ruby classes with the job of examining the parsed HTTP request and any related parameters, fetching data from the database (or wherever), and then passing that data to a view. A controller will typically have several different methods, each corresponding to a different task (e.g. create, show, update, etc).
Lastly, Routes are a DSL for parsing HTTP requests and dispatching a parsed HTTP request to a particular controller method. They are the glue that Rails uses to route URLs to methods, hence the name, routes.
Regarding your specific questions:
1) To create a new action, you have to add a route, a controller method, and a view. So for instance if you wanted to get a count of your entries, you could add a route like:
get '/entries/count' => "entries#count"
This tells ROR to call the count method in the entries controller when that URL is received. Your controller method in this case would be something simple like:
def count
#cnt = Entries.count
end
Then last, you'd make a view in app/views/entries/count.html.erb that had something like:
<p>Count: <%= #cnt %></p>
2) Ajax compatible code really just a way of asking "what if the requested format for this request is JSON?". For this, you'll want to use respond_to method. In a way, respond_to is a formal way of specifying a different view to handle the formatting of the request. To continue with the example above, you could do:
def count
#cnt = Entries.count
respond_to do |fmt|
fmt.html # This just renders the default template
fmt.json { render json: { count: #cnt } }
end
end
N.b. - All code above freehanded. :)
If you have the RESTful controller:
resources :entries do
collection do
get :vote_down
get :vote_up
end
end
this will generate 2 additional routes:
GET /entries/:id/vote_up(.:format) entries#vote_up
GET /entries/:id/vote_down(.:format) entries#vote_down
You can easily change HTTP method to GET, POST, PUT and DELETE.
Also, check "Adding More RESTful Actions" in the routes documentation.

Resources