$.AJAX for creating multiple records in rails - ruby-on-rails

I'm using Ruby on Rails, and I have a button that can create a post through AJAX, using this:
$.ajax({
beforeSend: function(xhr) {
xhr.setRequestHeader(
'X-CSRF-Token',
$('meta[name="csrf-token"]').attr('content'))},
url: "/posts/",
type: "POST",
data: {
post: {
title: "Cheese",
content: "Cake",
}
}
});
How do I format the data to create multiple posts at once, for example
posts = [
{
title: "Cheese",
content: "Cake"
},
{
title: "Key Lime",
content: "Pie"
}
]
so I can insert multiple objects with one POST?
I have a list of titles and contents. Might I have to construct a JSON object out of these?
Regardless of whether this is good Rails practice, how do I do this? Also, where might I look for how to format such HTTP requests?

Your jQuery call won't change much:
$.ajax({
beforeSend: function(xhr) {
xhr.setRequestHeader(
'X-CSRF-Token',
$('meta[name="csrf-token"]').attr('content'))},
url: "/posts/",
type: "POST",
contentType: "application/json",
data: JSON.stringify({
posts: [
{
title: "Cheese",
content: "Cake",
},
{
title: "Key Lime",
content: "Pie"
}
]
})
});
In your Rails action, you will be able to access your posts as an array of hashes via params[:posts].
class ThingsController < ApplicationController
def batch_create
params[:posts].each do |post|
Post.create post
end
end
end
Explanation
Using JSON.stringify causes your data to be serialized as JSON. Set contentType to application/json to add the "Content-Type: 'application/json'" header to your POST. That will clue Rails to interpret your POST as JSON.

Related

Passing Json response to view in Rails Ajax Datatable

I have an index method that respond with Json call to Datatable such as:
respond_to do |format|
format.html
format.json { render json: PeopleDatatable.new(params, user: current_user, view_context: view_context) }
end
I would like to be able to pass an array of all the IDs in the response to a dom in my view such as <div id: "people">1,2,3,4</div>
As per the gem description, the People records are generated in the
app/datatables/people_datatable.rb
using:
def get_raw_records
User.all
end
I tried adding the following in the view's script:
$(document).ready(function () {
$.ajax({
type: "GET",
url: "<%= peoples_path(format: :json) %>",
dataType: "json",
success: function(data) {
alert(data.name)
$('#bouba').html(data);
}
});
});
but the result is an undefined object class.
What would be the easiest way to do so please?
I am using the following gem for my datatable Rails ajax Datatable
Open /people.json and see what you get as a response, it looks something like this:
{
"recordsTotal": 2,
"recordsFiltered": 2,
"data": [
{
"id": "1",
"name": ""
},
{
"id": "2",
"name": ""
},
]
}
Now that you know what the structure looks like, send ajax request to that url:
<div id="people-ids"></div>
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "GET",
// send request to the correct url: "/people.json"
url: "<%= people_path(format: :json) %>",
dataType: "json",
success: function({data}) {
// ^
// extract "data" attribute from the response
console.log(data) // you can see what you get in the console
// extract ids
const user_ids = data.map(user => user.id)
// do what you like with the ids
$("#people-ids").html(user_ids.join());
}
});
});
</script>

How to reload particular partial value with response from rails api?

I have set up a rails api and it only response in the following format which is done through the serializer:
data: { user_name: 'Test User' }
And on the view side, I have got the following partial:
.user-change
= render partial: 'test_user', locals: {user_name: current_user.name}
What would be the correct way to change the user_name as per the API response from the following successful ajax request?
$("#change-me").click(function() {
var user_id;
user_id = $("#user_id").val();
$.ajax({
url: "/api/v1/user/change/" + user_id,
method: "POST",
dataType: "json",
data: JSON.stringify({
{
user_id: user_id,
}
}),
success: function(res, status, xhr) {
let response = res.data;
let userName = response.user_name;
// Update user_name after this event on the partial?
}
},
error: function(res) {
}
});
})
Partial code: _test_user.html.haml
.col-md-9
%p= "Hi! This is the request change from #{user_name}."

Passing nested parameters to an ajax get request

In a Rails 5.1 app (without jQuery) how can I pass nested params via a GET ajax request?
I have the following
Rails.ajax({
url: select.getAttribute('data-url') + "?xxx",
type: "GET"
});
If I replace xxx with, for instance, pippo=pluto, in my controller
params[:name] #=> "pluto"
However, in my controller, I need to be able to access a nested param as below.
params[:user][:name] #=> "pluto"
It seems a simple problem but I cannot find a solution.
Here my JS
document.addEventListener('turbolinks:load', function() {
var select = document.querySelector("select[name='user[name]']")
if(select.options[select.selectedIndex].value) {
Rails.ajax({
url: select.getAttribute('data-url'),
type: "GET",
data: {
user: {
name: select.options[select.selectedIndex].value
}
}
});
}
});
Which produces (user[:name] is always selected)
{"object Object"=>nil, "controller"=>"steps", "action"=>"index"} permitted: false>
The query string works fine (but is ugly)
Rails.ajax({
url: select.getAttribute('data-url') + '?user[name]=' + select.options[select.selectedIndex].value,
type: "GET"
});
SIDE QUESTION: To avoid the ajax request in the first place is there an alternative way to automatically trigger the request of the select below when the page is loaded? Currently, it is triggered only when the selected option changes
<%= f.select :user, MyUsers.all,
{ data: { remote: true, url: duplicate_users_path } } %>
use data option in ajax (recommended)
Rails.ajax({
url: select.getAttribute('data-url'),
type: 'GET',
data: {
users: {
pippo: 'pluto',
pippo2: 'pluto2'
}
}
});
or query string as array
Rails.ajax({
url: select.getAttribute('data-url') + '?users[pippo]=pluto&users[pippo2]=pluto2',
type: 'GET'
});

Strong parameters with JSON request

I thought that Rails automatically identifies/parses JSON params if the request is recognized as JSON. But the request below:
Processing by Api::V1::LinksController#create as JSON
Parameters: {"link"=>"{\"title\":\"My first title\"}"}
And the following params method:
def link_params
params.require(:link).permit(:title)
end
Results in this error:
NoMethodError (undefined method `permit' for "{\"title\":\"My first title\"}":String):
Any ideas what the convention here is to get strong params + json working would be much appreciated.
Update
Here's the code that makes the request (with the http client axios):
axios({
method: 'post',
url: '/api/v1/links.json',
responseType: 'json',
params: {
link: {
title: "My first title"
}
},
})
.then( (response) => {
});
As per the docs here
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
Replace params: with data:.

How to send params from nested forms?

I'm making a POST request from a nested form which is written in reactjs such that it is making an ajax request to create method of the products controller.
React Code:
I have an empty object in the getInitialState like this
getInitialState: function() {
return {
products: [{name: '', price: '', quantity: ''}],
count: 1
};
},
When i submit the form,
handleSubmit: function(e) {
e.preventDefault();
var productsArray = this.state.products;
$.ajax({
data: {
product: productsArray
},
url: '',
type: "POST",
dataType: "json",
success: function ( data ) {
console.log(data);
// this.setState({ comments: data });
}.bind(this)
});
},
the object gets populated and the parameter hash becomes like this
Parameters: {"product"=>{"0"=>{"name"=>"", "price"=>"", "quantity"=>""}}, "shop_id"=>"gulshop"}
So i'm getting
ActiveRecord::UnknownAttributeError (unknown attribute '0' for Product.):
How can i get the parameter hash like this:
Parameters: {"product"=>[{"name"=>"", "price"=>"", "quantity"=>""}], "shop_id"=>"gulshop"}
What can be done for it ?
Your original error 'unknown attribute '0' for Product.' is because the Product class does not have an attribute '0'. I'm not sure where the '0' is coming from as you haven't posted your react code that makes the request.
You can easily make a request from your component using jQuery's .ajax method. e.g
$.ajax({
type: 'POST',
url: '/your_url',
data: {
course: {
name: 'Hello World',
price: 120
}
}
});
You would then have something like the following in your controller..
class ProductController < ApplicationController
def create
#product = Product.create(product_params)
end
private
def product_params
params.require(:product).permit(:name, :price)
end
end

Resources