I'm trying to retrieve some information calling a method through ajax. It seems I'm missing something on my code, because when troubleshooting from chrome inspect I get an "url not found" error. My Models are Warehouse & Product. What i would like to accomplish is when a product is selected from the select_tag field, populate a text_field with a default price for that product. This is what I have so far:
1. select_tag view:
<%= select_tag "product_selection", options_from_collection_for_select(Product.all, "id", "name") %>
2. warehouses.js
$(document).on("change", '#product_selection', function() {
$.ajax({
url: "/warehouses/get_price",
type: "GET",
dataType: "json",
data: { product_id: $('#product_selection option:selected').value() }, // This goes to Controller in params hash, i.e. params[:file_name]
complete: function() {},
success: function(data, textStatus, xhr) {
// Do something with the response here
document.getElementById("default_price").value = data.default_price;
},
error: function() {
alert("Ajax error!")
}
});
});
3. warehouses_controller.rb
def get_price
#price = Product.find(params[:product_id]).price
if request.xhr?
render :json => { :default_price => #price }
end
end
4. routes.rb
resources :products
resources :warehouses
resources :warehouses do
member do
get 'get_price'
end
The message I get from Chrome Inspect:
jquery.self-c64a743….js?body=1:10244 GET http://localhost:3000/warehouses/get_price?product_id=2 404 (Not Found)
Check out Rails routing here: Rails Routes
Routes are read from the top down, and so it looks for :get_price in the first reference to warehouses. One choice is Combine the routes:
resources :products
resources :warehouses do
member do
get 'get price'
end
end
That will actually point to
/warehouses/{:id}/get_price
To lose the restful id, you could try
resources :products
resources :warehouses do
collection do
get 'get price'
end
end
That should respond to
/warehouses/get_price
and then pass the appropriate parameter.
Alternatively, To get the route that you are looking for, you could
get 'warehouses/get_price', to: 'warehouses#get_price'
resources :products
resources :warehouses
Notice the custom route is above the resources.
The Ajax call to the method (url: "warehoueses/get_price") was failing because I generated the get_price method inside the private methods section on warehouses_controller.rb so that was basically my mistake. Thanks anyway for the help!
Related
I want to update elements in the page to tell a user in real-time how many objects will be affected by their choice of criteria in a form.
For an example to work with, the form asks for a number and the django logic will delete any model instance with a pk less than that value once the submit button is clicked - but before clicking the user wants to know how many they will be deleting:
<span id="number-changed">NULL</span> objects will be deleted
so the end result I want is that #number-changed will be populated by a value like MyModel.objects.filter(pk__lt=input_number).count().
I have set up an AJAX call on changes to the input via:
$("input").change( function() {
$.ajax({
type: "GET",
url: "{% url 'myapp:bulkdelete' %}",
data: {
csrfmiddlewaretoken: $("input[name='csrfmiddlewaretoken']").val(),
},
success: function (data) {
// code to update #number-changed
}
I am wondering how I implement in the view so that on successful GET the success function can use the value I retrieve. Some pseudo-code:
# views.py
class MyView(FormView):
# ...
def get(self, request, *args, **kwargs):
input_number = ???
number_changed = MyModel.objects.filter(pk__lt=input_number).count()
# presumably some super().get() call here
return ???
Questions:
Can I retrieve the current input_number via request or does it need to be passed as a url parameter when making the AJAX request?
How can I add my required information, number_changed in this case, to the return of the get() method, and how to access this inside success?
The way I have implemented AJAX with django before has being using POST requests and I simply return a JsonResponse with my required data. However, an initial get() is called when loading the page and needs to return a full HttpResponse - so ultimately is there a way to add my additional information into this, or am I going about it completely wrong.
An Ajax request is exactly the same as any other request from the point of view of the server. You can just include the data in the querystring, which you then access in the view via the request.GET dict.
jQuery will generate that querystring for you from the data parameter; note, you don't need a csrf token for a GET request. So:
type: "GET",
url: "{% url 'myapp:bulkdelete' %}",
data: {
input_number: $(this).val(),
},
...
And in the view:
def get(self, request, *args, **kwargs):
input_number = request.GET["input_number"]
In my scenario in rails application after sharing content to facebook i will get a response object with post id
post_id: "mypostidhere"
If its not successful i will get response object with an error message.
So according to the response i want to change a boolean column of last row for the current user in my database table. And for this in my .js.erb file i tried to access current_user.model.last but it throws the following error.
undefined local variable or method `current_user' for
So how can i change the boolean column in database according to the response?
UPDATED
Ajax code
$.ajax({
type: "POST",
url: "/action"
});
Controller code
def action
current_user.modal.last.toggle!(:boolean-column-name)
end
It changes the table column successfully. But after that i am receiving an error in browser CONSOLE as below
POST http://URL/action
500 (Internal Server Error)
I am new to AJAX. What i am doing wrong in ajax request? Thanks in advance.
current_user is not a local variable to your JS function/file, it is a helper provided and available in your rails application.
So, what I will like to ask is:
How are you using current_user in the JS file?
What you can do is to make an ajax call to a controller method, and then access current_user directly from the controller.
If you want to change the db, you're going to have to communicate with your Rails app, which is done with ajax:
#app/assets/javascripts/application.js
... // your events will fire
$.ajax({
url: "/users/update",
method: "PUT",
data: { param: "value" }
success: function(data) {
// do something here
};
});
This will allow you to do the following:
#config/routes.rb
resources :users do
put :update, on: :collection
end
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def update
current_user.update(update_params)
end
private
def update_params
params.permit(:param)
end
end
I've looked at quite a few other answers on here, but I'm still struggling a bit to figure out how to set up my Rails widget.
I have this code in my widget controller:
def widget
status = Company.friendly.find(params[:id]).widget.active
body = to_json_value(render_to_string('companies/_widget', locals: { profile: self.profile }))
respond_to do |format|
format.js { render json: { status: status, html: body }, callback: params[:callback] }
end
end
private
def to_json_value(str)
str.gsub!("\"", "\\\"")
str.gsub!(/\n+/, " ")
str
end
The self.profile method just sets up a list of variables that get passed to the partial.
What I want to do is give a user a Javascript script tag that they can embed on their (external) website. When a user hits that page, the script will make an AJAX call to the widget controller and if the widget is turned on, it will receive a string of html to be rendered on the page.
So far I've got the widget controller to return a json object with the status and the html string. The problem is when I paste the localhost url into jsonlint.com, it says it is invalid. This is also confirmed when I insert a script tag into an html file and then open it in Chrome. I get an error saying there was an unexpected token :. So I then changed my controller and widget.js.erb to include a callback function. I added , callback: params[:callback] to my controller.
I also set up a callback function (doesn't do anything yet) in my widget.js.erb file. I then embed this file using a script tag in an html file and load that in Chrome. When I do, I get an error saying that showWidget is undefined.
I'm struggling to find resources that explain how to load data over jsonp from a rails app, and how callback functions come into play.
Here is my widget.js.erb:
function showWidget();
$.ajax({
type: 'GET',
url: 'http://localhost:3000/<%= params[:company] %>/widget?callback=?',
jsonpCallback: 'showWidget',
contentType: "application/json",
crossDomain: true,
dataType: 'JSONP',
success: function (data) {
var result = JSON.parse(data);
$('#company-widget').html(result.html);
},
error: function(e) {
console.log(e.message);
}
});
Here is my test.html:
<div id="company-widget"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" type="text/javascript"></script>
<script src="http://localhost:3000/taco-corp/widget.js?callback=showWidget" type="text/javascript"></script>
I'm also not sure where this widget.js.erb script should live in my rails app. Here is what I have so far for my widget.js.erb:
I figured out what the problem was. I needed to add a callback to my rails controller and to my $.ajax method. I didn't have the callback set up correctly in my ajax call. I also needed to specify the correct header (contentType) to get around an HTTP 406 error. Here is the working jQuery code below for reference:
$(document).ready(function(){
var company = 'taco-corp';
$.ajax({
type: 'GET',
url: 'http://localhost:3000/' + company + '/widget.js?callback=?',
contentType: "application/javascript",
crossDomain: true,
dataType: 'JSONP',
success: function(data) {
$('#company-widget').html(data.html);
},
error: function(e) {
console.log(e.message);
}
});
});
And here is my rails controller:
def widget
status = Company.friendly.find(params[:id]).widget.active
body = render_to_string('companies/_widget', layout: false, locals: { profile: self.profile })
respond_to do |format|
format.js { render json: { status: status, html: body }, callback: params[:callback] }
end
end
I'm trying to send an AJAX request to my rails controller (the make_suggestion method in the items controller).
I have the following javascript:
$.ajax({
url: "/items/make_suggestion", // pass to make_suggestions in recipes controller
type: "POST",
dataType: 'json',
data: parsed_data // a Javascript object/data hash
});
With debug(params) on, I'm not seeing any of the parsed_data in the params.
Can anyone please point out what is wrong? And how do I create symbols in the params in Rails through firing AJAX?
UPDATES
In my controller, I have
def make_suggestion
respond_to do |format|
format.html
format.json { render :json => params }
end
end
My ajax code:
$.ajax({
url: "http://localhost:3000/items/make_suggestion", // I'm doing the proper routing later, since '/make_suggestion' routes to 'items/1/make_suggestion'
type: "POST",
dataType: 'json',
data: parsed_data,
success: function(returned_value){
if(returned_value)
alert('true');
$('.test').append(returned_value);
},
error: function(returned_value){
$('.test').html('<p>Error in AJAX request</p>');
alert('Not working');
}
});
And my parsed_data looks like this:
Parameters: {"data1"=>{"position"=>"1", "item_id"=>"item_1",
"to_do"=>"unknown ", "selected"=>"false"}, "data2"=>{"position"=>"2",
"item_id"=>"item_2", "to_do"
=>"unknown", "selected"=>"false"}, "data3"=>{"position"=>"3", "item_id"=>"item_3 ", "to_do"=>"unknown", "selected"=>"false"},
"data4"=>{"position"=>"4", "item_id "=>"item_4", "to_do"=>"unknown",
"selected"=>"false"}, "data5"=>{"position"=>"5" , "item_id"=>"item_5",
"to_do"=>"unknown", "selected"=>"false"}}
But when I went to /items/make_suggestion.json, it's only showing the following:
{"action":"make_suggestion","controller":"recipes","format":"json"}
You can view / trace parameters in multiple ways
1) tail your rails log file tail -f log/development.log, note that the rails web server usually starts tailing to the console once started
2) raise exceptions and view debug output in the browser
3) use the javascript console in your browser (some are built-in), also consider Firefox with Firebug plug (use the 'console') tab
Tailing the rails log
every single request made to your rails server will show all of the parameters passed, as well as the controller and action which received the request and all sql statements generated
consider adding the 'awesome_print' gem to your application for better logging output, once installed logger.ap params will give you a nice readable output
Raise exceptions
not needed very often but if you add raise "ZOMG" as the first line of your controller action, it will render html output and show all the parameters passed. This is almost useless for ajax calls
Javascript Console
This will show all ajax requests and all parameters that javascript is sending to the rails server and all data being returned as well, very useful
Rails will map the javascript ajax parameters to a ruby hash, this is very nice as these data structures are almost exactly the same in the browser as they are in rails, i.e.
// javascript data structure
var parsed_data = {
foo: "FOO",
bar: "BAR",
person: {
first_name: "Joe",
last_name: "Smith"
}
}
output to the log using awesome_print would result in a ruby hash something along the lines of
logger.ap params
{
:foo => "FOO",
:bar => "BAR",
:person => {
:first_name => "Joe",
:last_name => "Smith"
}
}
# access the data
params[:foo]
# => "FOO"
params[:person][:first_name]
# => "Joe"
Your data post to controller not detail.
look my example :
$.ajax({
url:'/contact/new',
type:'get',
data:{object_param:{
first_name:'zainulmasadi',
last_name:'masadi ganteng',
phone_number:'089745674119541'}},
dataType:'json',
success:function(returned_value){
if(returned_value)
alert('true');
}
})
and my controller
def new
#contact = ContactPhone.create(params[:object_param])
if #contact.save
respond_to do |format|
format.html
format.json {render :json => #contact}
end
end
end
I´m trying to route an array of parameters in my Rails 3 app but i keep getting a 404 error.
Here´s the ajax request in my JS file:
var url = '/arrayquery?kind[]=startup&kind[]=investor'
$.ajax({
url: url,
dataType: "text"
}).done(function(data) {
console.log(data)
})
My routing:
match 'arrayquery/:kind', :to => 'home#arrayquery'
And my controller method:
def arrayquery
#players = Player.where("kind = ?", params[:kind])
end
My browser keep throwing this line:
"NetworkError: 404 Not Found - http://localhost:3000/arrayquery?kind[]=startup&kind[]=investor"
Does anybody know why there´s no matching route for the request?
The route you've defined in your routes file is looking for,
http://localhost:3000/arrayquery/KIND?param=value¶m=value
Try changing the route to,
match 'arrayquery', :to => 'home#arrayquery'