rails post request - ruby-on-rails

I'm not quite understanding how requests are handled in rails, in my controller, I have something like this:
def method_to_handle_request
# do stuff
end
Then in the view I have this JavaScript:
$.post("/", {method_to_handle_request: "value"}, function(data) {
// do something with data
});
This is wrong: data in the JavaScript ends up just being the page. Thus, my question is: how do I handle requests in rails? I've been reading "Agile Web Development With Rails", and the section there doesn't make too much sense to me.
Thanks

Rails uses configured routes to point to the appropriate controller action. You have to specify a route in your config/routes.rb file to send your request through the desired action. In your controller, you've defined the method_to_handle_request. You have to make sure that you define a route for that. There are many ways to do this within the routes.rb file and those are well documented in this guide.
Then in your method_to_handle_request you should render/format your output as JSON or XML or whatever you want your view to consume. If you don't do this you'll end up just getting the flat templated HTML back. Here's a good resource for rendering views that has a section on JSON in particular.
So here's a quick example of what I mean:
in config/routes.rb
resources :foos do
member do
post 'do_my_foo'
end
end
in foos_controller.rb
def do_my_foo
foo = Foo.find(params[:id])
# do some things to poor ole foo
some_cool_data_about_foo = ...
respond_to do |format|
format.json { render :json => some_cool_data_about_foo }
end
end
Then when you call it with ajax you'll get the JSONified data in your handler.
Geeze, I hope this is what you were asking...

Related

How to render a different controller / action from within an action in Rails 4.2?

I know this is possible but I want to render a controller / action in response to a different action like in my routes.rb, I have:
get ':handle' => 'handler#index'
and in handler_controller, I have:
def index
handle=Handle.where('handle=?',params[:handle]).first
if handle.handle_type=='Location'
# call location / show with id from handle
else
render text: "not found"
end
end
How would I do this? I should mention, I don't want to do a redirect.
Maybe this can help:
def action_that_calls_one_from_another_controller
controller_you_want = ControllerYouWant.new
controller_you_want.request = request
controller_you_want.response = response
controller_you_want.action_you_want
end
You can solve this by using an "internal redirect" approach.
Inside rails this can be done via middleware that calls #app again and tracks redirect loops. See tutorial here
Also can be done by utilizing nginx's X-Accel-Redirect: make a regular routes for referenced resources, but instead of regular redirect issue a X-Accel-Redirect header, for user it will be like your page rendered without redirect.

How to add a custom route, controller, and action in Ruby on Rails?

I have a Ruby on Rails and ActiveAdmin application. I didn't basically change any default configuration except adding and registering a few models.
I want to enable my application with a route like GET /heartbeat and respond with a simple string to client/user. I'm wondering how could I do the following steps:
Add a custom route to my routes.rb file.
Add a custom controller under app/controllers path.
Implement a custom action and respond to user directly without any view.
routes.rb:
get 'heartbeat' => "custom_controller#heartbeat"
custom_controller.rb:
class CustomController < ApplicationController
def heartbeat
render inline: "Some string to the client/user"
end
end
Avoiding the Rails render stack will save you some processing and be faster. You can do this at the router level via a simple Rack "application" that returns a response code:
get 'heartbeat', to: proc { [204, {}, []] }
Anything that responds to call and returns [status, headers, body] is rack compliant so you can leverage a proc to do just that, right in the router. In this case, we send a 204 No Content which should be sufficient for a heartbeat, but you can always return custom data/headers.
Update:
I can only imagine that this was downvoted because people don't understand why this is better. Here's a quick attempt to explain:
In case it wasn't clear, you don't need a controller action at all with this method. Here's the equivalent solution to the accepted answer:
get 'heartbeat', to: proc { [200, {}, ['Some string to the client/user']] }
Sticking that line in your Rails routes.rb file will be equivalent to creating a new controller, view and route entry, with one key difference: It avoids the Rails response rendering stack so should be much faster than the accepted solution.

Rails controller action duplication

I have a controller show action which does some stuff and renders a view but due to some custom routing, I need a totally different action in a totally different controller to perform the same stuff and render the same view.
I don't really wish to duplicate the code. Is there somewhere I can put it and call it from both locations?
Edit:
I basically need to run the following from Collection#Show AND also from Gallery#SplitUrl:
#collection = Collection.find_by_id(params[:id])
if #collection.has_children?
#collections = #collection.children
else
redirect_to [#collection, :albums]
end
I cannot just redirect_to Collection#Show at the end of Gallery#SplitUrl as the redirect causes my custom URL's to be lost as it's a new request.
You could put the view content into a partial (/app/views/home/_example.html.erb) and then use the render "example" command in the HomeController.
The "some stuff" code you talk about could be put into a helper file /app/helpers/... to save you from duplicating code in the two separate controllers although it could depend on what the code is trying to do in the first place.
http://guides.rubyonrails.org/layouts_and_rendering.html
This might provide more information on the subject in general.
I think the simplest approach would be to add a route definition for your new url and map that to your existing controller's action.
Something like follows:
# config/routes.rb
# Existing resource
resources :foos
# The resource in question
resources :bars do
get :show, controller: 'foos', action: 'show', as: bar_foo_common_show
end
Note that this will give you /bar/:id, where id represents a bar resource. So in your foo#show action, your finder needs to be executed on appropriate class. This is when a few lines of hacky codes get added, for e.g. checking for request referer.
I think moving the common code to a function in possibly application_controller and calling that function from both show action would be cleaner approach, but based on my understanding you already have a similar scenario except for the common code in application_controller, and would like to try out a different approach!

ajax get data from a rails controller

I am trying to use ajax to get information from my controller. Basically I want to know if a data already exists in the DB or not, so my controller will return either true or false.
At the moment I am just trying to set the basic ajax call
in my js file I have the following ajax call, as you can see at the moment I am not really doing any logic because my data is just a placeholder. Later I will add the information I want to query
$.ajax({
type: "GET",
url: "/locations/exists",
dataType: "JSON",
data: { 'locition_exist': loc_exit },
success: function(data) {
console.log(data);
}
});
In my controller I have
def exists
location_exists = true
respond_to do |format|
format.html
format.json {render json: location_exists }
end
end
Later value will go into a method in the model that will query the DB and return true/false.
In my routes I have
resources :locations
get 'locations/exists', to: 'locations#exists'
This code results in the following error
The action 'show' could not be found for LocationsController
I am new to rails and ajax , and I based my code on different examples that I read here, so I am probably just doing a stupid noob mistake.
Thank you very much for your help
When using get or match in routes, you need to define the controller method mapped
get 'locations/value', to: 'locations#value'
update
You saw the same error after updating routes. There are two reasons of this error:
You defined resources :location at first. The url locations/exists itself matches "show" method within resources, with Routes taking 'exists' as the id in #show.
You have not defined show within LocationsController
So, Routes will firstly map the url to locations#show with the :id as 'exists', then hits the controller and found #show does not exist.
The solution after your updating
Of course you can put get 'exists'... before resources but that looks ugly.
Since 'exists' requires no id, it is a collection method. So you can use Routes built-in ways to do that.
resources :locations do
collection do
get 'exists'
end
end
By this all your resources and 'exists' can live.

RESTful API in rails

I am very new to rails and following a tutorial for RESTful API so let me excuse if it is of not very good quality as I am equally a starter for these kind of terminologies as well.
I created a controller kitten with a command rails g controller kitten index
and in the index method I posted this code -
class KittenController < ApplicationController
def index
require 'open-uri'
kittens = open('http://placekitten.com/')
response_status = kittens.status
response_body = kittens.read[559, 441]
puts response_status
puts response_body
end
end
and un commented match ':controller(/:action(/:id))(.:format)' in routes.rb
When i navigate through this - http://localhost:3000/kitten
this is what i am getting in my browser -
Kitten#index
Find me in app/views/kitten/index.html.erb
and this in my command line -->
Now my question why it so although i am expecting it in my browser but the cat is shown in command prompt instead of browser ..i am new to rest resource so please excuse if it is a bad one :(
I don't know what tutorial you're following, but doing this seems like a very odd thing to do for Rails in general and learning RESTful APIs in particular.
Anyway, the puts in your controller outputs text to Ruby's standard out, which is going to be the terminal where the server started. That's why this is appearing in the console rather than in your browser: puts is putting it there.
If you want this to appear in a web page, you'll need to make a view for that controller action. Perhaps following further along your tutorial will get you there: if not, you might want to find a better one.
You should read the Model-View-Controller rails guide.
Controllers provide the “glue” between models and views. In Rails, controllers are responsible for processing the incoming requests from the web browser, interrogating the models for data, and passing that data on to the views for presentation.
Define your variable in the controller and display it in the view:
class KittenController < ApplicationController
def index
#variable = 'Hello World'
end
end
In your view (app/views/kitten/index.html.erb):
<%= #variable %>
Rails controllers setup responses with a render call.
When the call is not performed it instantiates the appropriate view and renders that view. In your case that is index.html.erb
Try this:
render :text => kittens.read[559, 441], :status => kittens.status

Resources