Passing JSON parameters to update Rails Model - ruby-on-rails

I am trying to update a model through JSON. Right now I am able to get the put method to execute.
From my browser console, I see this so I believed that my request did go through.
PUT http://localhost:3000/slot_allocations/1 [HTTP/1.1 200 OK 7ms]
However, I am not too sure how I could get Rails to accept the data I want to update and would appreciate it if someone could help me out.
This is my Jquery codes for Ajax request. dataToServer is the data I want to send to update the model.
var url = 'slot_allocations/'+alloc_id;
var dataToServer = {slot_allocation:{timeslot:timeslot, subject:subject,slot_allocation_id:alloc_id-1, group_id:"Group 2", lesson_type:"Tutorial"}}
$.ajax({
type: "PUT",
url: url,
dataType: "json",
data: JSON.stringify(dataToServer) , // message to send goes here
success: function (data)
{
}
});
In my update method in the controller I have the following codes.
def update
#slot_allocation = SlotAllocation.find(params[:id])
respond_to do |format|
if #slot_allocation.update_attributes(params[:slot_allocation])
format.html { redirect_to #slot_allocation, notice: 'Slot allocation was successfully updated.' }
format.json { render :json=>#slot_allocation.as_json }
else
format.html { render action: "edit" }
format.json { render json: #slot_allocation.errors, status: :unprocessable_entity }
format.js { render :js => #slot_allocation.errors, :status => :unprocessable_entity }
end
end
end
And this is my as_json method. I am using it for my send request from the server to the client side but I am not too sure if I could use the same method to send information from the client to the server side.
def as_json(options={})
{
:group_id =>self.group_index,
:lesson_type =>self.lesson_type,
:timeslot =>self.timeslot_id,
:subject =>self.subject_id,
:slot_allocation_id => self.slot_allocation_id
}
end
I would appreciate it if someone could guide me along as I am not too familiar with how I should get Rails to accept the parameters to update the model.

I believe you need to parse the JSON parameters first:
attributes = ActiveSupport::JSON.decode(params[:slot_allocation])
if #slot_allocation.update_attributes(attributes)
...
end
How do I parse JSON with Ruby on Rails?

Related

How do I tell my Rails controller to use the format.json part of my method instead of the format.html branch?

I'm running Rails and trying to set up an autocomplete on my text field. I want to submit to a controller method. If I'm submitting from my form (using the "Submit" button), I'd like to use the "format.html" branch. If I'm submitting using the autocomplete Ajax call, I'd like to use the "format.json" branch ...
def search
if params.has_key?("s")
search = params[:s].strip
#people = Person.where("name ilike ?", "%#{search.upcase}%")
respond_to do |format|
format.html {
if #people.size == 1
redirect_to controller: 'votes', action: 'show', id: #people.first.id
end
}
format.json { #people.map(&:name) }
end
end
end
I set up the autocomplete on my text field like so
$(function() {
return $('#s').autocomplete({
source: function(request, response) {
$.get('/people/search', { s: request.term }, function(data) {
alert(data)
response(data.split('\n'));
});
}
});
});
but what's happening is the value of "data" is an HTML page, as if I were submitting via the format.html method. How do I configure things so that my autocomplete call forces me to render the JSON response from my controller?
Specify .json format in the url like this -
$.get('/people/search.json', { s: request.term }, function(data) {
alert(data)
response(data.split('\n'));
});
To send raw json data In Controller change. Otherwise it will look for template to build json (by default rails will look for search.json.jbuilder)
format.json { render json: {people: #people.pluck(:name)} }

respond with redirect on json request

I am using a bootstrap typeahead plugin. Basically, it expects a json response when you click on one of the items in the dropdown menu. However, when the item is clicked, I want to redirect to a different page; I do not want to respond with json. I don't know how to handle this situation. This is what I have:
def populate_global_search
respond_to do |format|
if params[:name] && params[:name][:value]
model = Model.where(name: params[:name][:value]
else
model = nil
end
if model.present?
format.json { redirect_to model }
else
format.json { head :ok}
end
end
end
The action is triggered from an ajax call:
$(element).bind('typeahead:selected', function(obj, datum, name) {
$.ajax({
url: that.format_url(),
data: {
name : datum
}
}).done(function(data){
...
Since the redirect_to is not a json response, nothing happens when I click on the item. What can I do?
The main problem here, you call the populate_global_search action asynchronously, respond_to block unable to redirect an asynchronously call. To resolve your problem I suggest you render the path to redirect and change the location by window.location:
The javascript code(that's just an assumption):
$(element).bind('typeahead:selected', function(obj, datum, name) {
$.ajax({
url: that.format_url(),
data: {
name : datum
}
}).done(function(data){
// redirect to the desired path
window.location = data.location;
});
The Rails code(also assumption):
def populate_global_search
respond_to do |format|
if params[:name] && params[:name][:value]
# I use find_by, because where return a collection
model = Model.find_by(name: params[:name][:value])
else
model = nil
end
if model.present?
# render a json objects { location: '/some_path/12' }
# with path which you need
format.json { render json: { location: here_is_the_desired_path } }
else
format.json { head :ok }
end
end
end
Bonus, your can reduce your Rails code to, this also should works:
def populate_global_search
model = Model.find_by(name: params[:name].try(:[], :value))
if model.present?
render json: { location: here_is_the_desired_path }
else
head :ok
end
end

How to check if my server rollback transaction after ajax request from CoffeeScript, RoR

$.ajax
url: "/models"
type: "POST"
dataType: 'json'
data: {model: {name: "name", x: "x", y: "y"}}
Is there any way to check if my server eccepted this request and saved new element without making server request again?
Oh .. I figured it out.
Every time when ajax request is triggered it waits till server respond with some data. (in my example it is data in json format)
My ajax request in coffescript looks like this now:
$.ajax
url: "/models"
type: "POST"
dataType: 'json'
data: {model: {name: "name", x: "x", y: "y"}}
success: (data) ->
alert "Request was send to the server and server axcepted what I wanted to say … but I don't know if he do what I've told to him"
error: (data) ->
alert "The server says that he couldn't do what I've told him becouse of error number: #{JSON.stringify(data['status'])}"
And the most important in this case is to make server actually respond with some value of an expecting error.
So … some changes needs to be done in Controller.
I wanted to create some element so action "create" looks like this:
def create
#model = Model.new(model_params)
respond_to do |format|
if #model.save
format.html { render :nothing => true }
format.json { render :json => #model, :status => :ok}
else
format.html { ender :nothing => true }
format.json { render json: #model.errors, status: :unprocessable_entity }
end
end
end
:unprocessable_entity sends error #422

How to access the updated object in a javascript callback (instead of the old object)

Building on the helpful and working solution presented here, I'm trying to fix my update callback as well.
Problem is, the specific unit that I'm trying to extract data from is always the old cached version, even though this callback is triggered by a successful update action.
// callback triggered by the update action
$('.best_in_place').bind("ajax:success", function () {
...
console.log(unit.duration);
// which is exactly the same as
console.log(<%= Unit.find(unit.id).unit_users.pluck(:duration).sum %>);
// and both print the OLD duration val instead of the updated val which is in the database
});
and the unit_users_controller code...
def update
#unit = #unituser.unit
respond_to do |format|
if #unituser.update(unit_user_params)
#unit.reload
logger.info('-----------------------------------------------------------------')
logger.info('#unit.duration in the controller is ' + #unit.duration.to_s) # which is the correct value
logger.info('-----------------------------------------------------------------')
gon.unit_duration = #unit.duration # an experiment which didn't work for me
format.json {respond_with_bip(#unituser) }
else
# format.html { render :action => 'edit' }
format.json { respond_with_bip(#unituser) }
end
end
end
I've tried several versions of unit.reload, and nothing helps. Maybe I was putting it in the wrong place?
I did this one sometime ago here is my code, maybe it will help you:
Javascript:
$(document).ready(function() {
$('.price_bind').bind("ajax:success", function (event, data, status, xhr) {
var parsed_data = jQuery.parseJSON(data);
$(this).text(parsed_data.newprice);
$(this).parentsUntil('body').find(".totalpricep span").text(parsed_data.totalprice);
});
}
View:
<%= best_in_place detail, :price, :classes => 'price_bind', :path => purchase_detail_path(#purchase, detail)%>
Controller:
def update
respond_to do |format|
if #detail.update_attributes(params[:detail])
#n=#detail.mk_bal
#r=false
if #detail.purchase != nil
#p=#detail.purchase.totalprice
if params[:detail]['status'] && #purchase.step==1
#remdet = #purchase.details.where(:step => 1, :status => false)
if #remdet.empty?
#purchase.update_attribute(:step, 2)
#r=true
end
end
else
#p=nil
end
format.html { redirect_to #detail, notice: 'Detail was successfully updated.' }
format.json { render :json => {:newprice => #n, :totalprice => #p, :newstatus => #detail.status, :refresh => #r}}
else
format.html { render action: "edit" }
format.json { render json: #detail.errors, status: :unprocessable_entity }
end
end
end
This isn't about caching. Your Ruby code is evaluated server-side, before the JavaScript is ever send to the client, and it's only evaluated once, long before the AJAX request can happen.
The client never sees this line:
console.log(<%= Unit.find(unit.id).unit_users.pluck(:duration).sum %>);
All the client will see is something like:
console.log(32); // or whatever the sum is
You cannot use <%= %> here. That will always give you the original value. Instead, you need to send the new value to the client in response to the AJAX request.

Using Ajax to POST JSON object in rails, and save it to a database?

I've looked through a number of these types of problems, but i can't quite figure it out.I'm really new to ruby on rails. I'm creating an application in rails that administers a printer. Basically what I'm trying to do here is POST a json object using ajax from the frontend which is written in javascript to the backend which I'm writing in rails. Basically what happens is when a user decides to checkout and print something, the json object is sent to the server and a new rails object is created using the json object's data. I want to create a rails object containing the data from the json object.
My ajax, located in the frontend javascript. Note that this code is in a completely seperate application:
$.ajax({
beforeSend: function(xhr) {
toggleModal();
xhr.setRequestHeader("Authorization", "OAuth "+auth_header);
},
url:message.action,
async:true,
type:message.method,
dataType:'json',
contentType: 'application/json',
data: JSON.stringify(userSession),
error: function(data){
toggleModal();
$.mobile.changePage($("#page_thankyou"),{ transition: "slide"});
},
success: function(data){
toggleModal();
console.log(userSession);
$.mobile.changePage($("#page_thankyou"),{ transition: "slide"});
}
})
Here is the userSession Object:
userSession = {
"kiosk_session":{
"session_id":"",
"is_order":"",
"session_items":[]
}
};
In my Kiosk_session controller:
# POST /kiosk_sessions.json
def create
puts YAML::dump params
#kiosk_session = KioskSession.new(params[:kiosk_session])
respond_to do |format|
if #kiosk_session.save
format.html { redirect_to #kiosk_session, notice: 'Kiosk session was successfully created.' }
format.json { render json: #kiosk_session, status: :created, location: #kiosk_session }
else
format.html { render action: "new" }
format.json { render json: #kiosk_session.errors, status: :unprocessable_entity }
end
end
end
and my kiosk_session model:
class KioskSession < ActiveRecord::Base
attr_accessible :id, :is_order, :is_reprint, :reprint_reason, :price,
:paid, :printed, :print_date, :session_items_attributes, :kiosk_id
has_many :session_items
has_one :kiosk_kiosk_session
belongs_to :user
belongs_to :kiosk
accepts_nested_attributes_for :session_items
before_save :before_save_callback
def before_save_callback
new_KSS = KioskKioskSession.new(:kiosk_id => self.kiosk_id, :kiosk_session_id => self.id)
new_KSS.save
self.total_price
end
def total_price
#session_items.to_a.sum {|item| session_items.total_price}
#array to hold subtotals
price = 0.00
#finds each item in session
session_items = SessionItem.where(:kiosk_session_id => self.id)
#creates array of subtotals
session_items.each do |t|
#if t.price
t.set_price
price += t.price
end
self.price = price
end
end
oh and my POST route for creating a kiosk session is /kiosk_session#create
I know this code is a mess, but any help would be greatly appreciated.

Resources