Post not working React + Rails - ruby-on-rails

When I try to make a post I'm getting a 400 (Bad Request) Error.
I'm trying to post a new Player into a Team.
My controller
def create
#teams = Team.find(params[:team_id])
#players = #teams.players.new(player_params)
render json: #players
end
private
def player_params
params.require(:player).permit(:name, :photo, :nationality)
end
The function
_handleSubmit = async (e) => {
e.preventDefault();
const teamId = this.props.match.params.id;
const payload = this.state.players;
console.log(payload);
try {
const res = await axios.post(`/api/teams/${teamId}/players`, payload);
} catch (err) {
console.log(err);
}
};
_handleChange = (e) => {
const newState = { ...this.state.players };
newState[e.target.name] = e.target.value;
this.setState({ players: newState });
};

You need to strong compare what the body you send, and what the body you expect to receive on the server?
On backend you can send not only error code, and error message, or field identifier which error occurs.
And don't forget to set await statement if you will work with query result:
const res = await axios.post(`/api/teams/${teamId}/players`, payload);

Related

How to get link to composition by using status callbacks twilio

Here is what I tried but it's not working.
This guy is responsible for creating a composition after the meeting is ended.
app.post('/api/endMeeting', (req, res) => {
const roomSid = req.body.roomSid;
userEmail = req.body.userEmail;
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
client.video.rooms(roomSid).update({ status: 'completed' });
client.video.compositions.create({
roomSid: roomSid,
audioSources: '*',
videoLayout: {
grid : {
video_sources: ['*']
}
},
statusCallback: `${process.env.REACT_APP_BASE_URL}/api/getMeeting`,
statusCallbackMethod: 'POST',
format: 'mp4'
}).then(() => {
// sendRecordingEmail(composition.sid, userEmail);
res.status(200).send({
message: 'success'
});
}).catch(err => {
res.status(500).send({
message: err.message
});
});
});
And this guy will send the download link of the composition to the participant when it's available.
app.post('/api/getMeeting', (req, res) => {
if (req.query.StatusCallbackEvent === 'composition-available') {
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
const compositionSid = req.query.CompositionSid;
const uri = "https://video.twilio.com/v1/Compositions/" + compositionSid + "/Media?Ttl=3600";
client.request({
method: "GET",
uri: uri,
}).then((response) => {
const requestUrl = request(response.data.redirect_to);
sendRecordingEmail(requestUrl, userEmail);
res.status(200).send("success");
}).catch((error) => {
res.status(500).send("Error fetching /Media resource " + error);
});
}
});
I can confirm that the composition is created exactly in the Twilio console.
But it seems the status callback guy is not working and I can see the below issue.
It seems I made mistakes in using the status callback.
Please let me know what is the problem and how I can solve this.
Thank you.
Thank you very much for #philnash's help in solving this problem.👍
I solved the above issue and I can get the download link of the composition for now.
The problem was in the status callback function and I should use req.body instead of req.query because of the status callback method. (It's POST on my code.)
Here is the code that is fixed.
app.post('/api/getMeeting', (req, res) => {
if (req.body.StatusCallbackEvent === 'composition-available') {
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
const compositionSid = req.body.CompositionSid;
const uri = "https://video.twilio.com/v1/Compositions/" + compositionSid + "/Media?Ttl=3600";
client.request({
method: "GET",
uri: uri,
}).then((response) => {
const requestUrl = response.body.redirect_to; // Getting the redirect link that user can download composition
sendRecordingEmail(requestUrl, userEmail); // Send URL via email to the user
res.status(200).send("success");
}).catch((error) => {
res.status(500).send("Error fetching /Media resource " + error);
});
} else {
res.status(204).send('compositioin is not available');
}
});

I have a 404 error in an Ajax call on Ruby on rails

I'm pretty new to ajax (and web development in general) and I'm trying to implement this code directly on my view:
<% content_for :after_js do %>
<script type="text/javascript">
//1st dropdown selection
const dropdownOne = document.querySelector('#order_credits_package_id');
//Listening to dropdown change
dropdownOne.addEventListener('change', (event) => {
const selectedPackage = event.target.value
console.log(selectedPackage)
// document.getElementById("order_amount_centavos").value = event.target.value
// Params for AJAX call
const url = "/dynamic_dropdown_method";
const data = {'selection': selectedPackage }
// Storage of AJAX call answer (NB: can be refactored to avoid 2 calls)
// the ['id'] must match the one defined in your controller
const level_1_selected = ajaxCall(url, data)['dropdown_1_selected'];
const level_2_array = ajaxCall(url, data)['dropdown_2_array'];
// Identification of 2nd dropdown
const dropdownTwo = document.querySelector('#order_amount_centavos');
// Delete and replace options in 2nd dropdown
removeOptions(dropdownTwo);
addOptions(level_2_array, dropdownTwo)
});
// AJAX call
function ajaxCall(url,data) {
var result = "";
console.log("call Ajax")
console.log(url)
console.log(data)
$.ajax({
url: url,
async: false,
dataType: 'json',
type: 'POST',
data: data,
success: function (response) {
console.log("ajax Call")
console.log(response)
result = response;
}
});
return result;
}
// Delete existing select options
function removeOptions(selectElement) {
console.log("fonction remove")
var i, L = selectElement.options.length - 1;
for(i = L; i >= 0; i--) {
selectElement.remove(i);
}
}
// Add select option
function addOptions(optionsArray, dropdown) {
optionsArray.forEach(function (item) {
const new_option = document.createElement('option');
new_option.value = item;
new_option.innerHTML = item;
dropdown.appendChild(new_option);
});
}
</script>
<% end %>
I then added this method to the controller related to this view:
def dynamic_dropdown_method
#selection = params[:credits_package_id]
#array_dropdown_2 = CreditsPackage.find(#selection).price_centavos
return render json: {level_1_selected: #selection, level_2_array: #array_dropdown_2}.to_json
end
And the following route:
post "/dynamic_dropdown_method", to: "orders#dynamic_dropdown_method", as: :dynamic_dropdown_method
But when I try to run my code, I get the following error message in the console:
POST http://localhost:3000/dynamic_dropdown_method 404 (Not Found)
Does anyone have any idea how to fix it?
Thank you very much!

Websocket Connection Fail - Uncertain Which part of Code is Wrong

Several problems. To begin with I get the following error in my devtools
WebSocket connection to 'ws://localhost:3000/cable?token=ZmllcnlAc3dhZ2dlci5jb20=' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
On my rails server, I have the following output in a doc file on the project's repo: DOWNLOAD
It was rather too large for a blockquote.
To make a long story short, the connection is timing out half the time (resetting the server fixes this). However, most of the time it seems like the subscription silently fails to fire, as even making a new article from a different browser won't update the index page. I am completely lost as to what could be causing this to fail.
Relevant code:
Rails Side ApplicationCable
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = current_user
end
private
def current_user
token = request.params[:token].to_s
email = Base64.decode64(token)
User.find_by(email: email)
end
end
end
GraphQL Channel
class GraphqlChannel < ApplicationCable::Channel
def subscribed
#subscription_ids = []
end
def execute(data)
result = execute_query(data)
payload = {
result: result.subscription? ? { data: nil } : result.to_h,
more: result.subscription?
}
#subscription_ids << context[:subscription_id] if result.context[:subscription_id]
transmit(payload)
end
def unsubscribed
#subscription_ids.each do |sid|
SwyleSchema.subscriptions.delete_subscription(sid)
end
end
private
def execute_query(data)
SwyleSchema.execute(
query: data["query"],
context: context,
variables: data["variables"],
operation_name: data["operationName"]
)
end
def context
{
current_user_id: current_user.id,
current_user: current_user,
channel: self
}
end
end
Connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = current_user
end
private
def current_user
token = request.params[:token].to_s
email = Base64.decode64(token)
User.find_by(email: email)
end
end
end
Subscription Type
module Types
class SubscriptionType < GraphQL::Schema::Object
field :article_added, Types::ArticleType, null: false, description: "An article was posted"
def article_added
end
end
end
Create Article Mutation
module Mutations
class CreateArticle < BaseMutation
argument :title, String, required: true
argument :body, String, required: true
type Types::ArticleType
def resolve(title: nil, body: nil)
snippet = body[0, 300]
article = Article.new
article.title = title
article.body = body
article.snippet = snippet
article.user = context[:current_user]
if article.save
SwyleSchema.subscriptions.trigger("articleAdded", {}, article)
# { article: article}
article
else
{ errors: article.errors.full_messages }
end
end
end
end
Apollo.js
import { HttpLink } from 'apollo-link-http';
import { ApolloLink, Observable } from 'apollo-link';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { onError } from 'apollo-link-error';
import { ApolloClient } from 'apollo-client';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import introspectionQueryResultData from './fragmentTypes.json';
import ActionCable from 'actioncable';
import ActionCableLink from 'graphql-ruby-client/subscriptions/ActionCableLink';
const getCableUrl = () => {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const host = window.location.hostname;
const port = process.env.CABLE_PORT || '3000';
const authToken = localStorage.getItem('mlToken');
debugger;
return `${protocol}//${host}:${port}/cable?token=${authToken}`;
};
const createActionCableLink = () => {
const cable = ActionCable.createConsumer(getCableUrl());
return new ActionCableLink({ cable });
};
const hasSubscriptionOperation = ({ query: { definitions } }) =>
definitions.some(
({ kind, operation }) =>
kind === 'OperationDefinition' && operation === 'subscription'
);
const getTokens = async () => {
const tokens = {
"X-CSRF-Token": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content")
};
const authToken = await localStorage.getItem("mlToken");
return authToken ? { ...tokens, Authorization: authToken } : tokens;
};
const setTokenForOperation = async operation => {
return operation.setContext({
headers: {
// eslint-disable-next-line
... await getTokens(),
}
});
};
const createLinkWithToken = () =>
new ApolloLink(
(operation, forward) =>
new Observable(observer => {
let handle;
Promise.resolve(operation)
.then(setTokenForOperation)
.then(() => {
handle = forward(operation).subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer),
});
})
.catch(observer.error.bind(observer));
return () => {
if (handle) handle.unsubscribe();
};
})
);
const createHttpLink = () => new HttpLink({
uri: 'http://localhost:3000/graphql',
credentials: 'include',
})
const logError = (error) => console.error(error);
const createErrorLink = () => onError(({ graphQLErrors, networkError, operation }) => {
if (graphQLErrors) {
logError('GraphQL - Error', {
errors: graphQLErrors,
operationName: operation.operationName,
variables: operation.variables,
});
}
if (networkError) {
logError('GraphQL - NetworkError', networkError);
}
})
export const createClient = (cache, requestLink) => {
const client = new ApolloClient({
link: ApolloLink.from([
createErrorLink(),
createLinkWithToken(),
ApolloLink.split(
hasSubscriptionOperation,
createActionCableLink(),
createHttpLink(),
)
// createHttpLink(),
]),
cache,
});
return client;
};
export const createCache = () => {
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData
});
const cache = new InMemoryCache({fragmentMatcher});
if (process.env.NODE_ENV === 'development') {
window.secretVariableToStoreCache = cache;
}
return cache;
};
ARticles Index Component
import React, {Component} from 'react';
import articles from './queries/articles';
import { Query } from "react-apollo";
import {Link} from 'react-router-dom';
import ArticleTags from './article_tags';
import Subscription from './subscription';
class ArticlesIndex extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
const date = Date.now();
return (
<Query query={articles}>
{({ loading, error, data, subscribeToMore }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
const articles = data.articles;
return (
<div className="article-index-page">
<h1>Newest Articles</h1>
{ articles.map((article) => (
<div className="article-index-card" key={`${article.id}${article.title}${date}`}>
<h2 className="article-index-title">{article.title}</h2>
<h3 className="article-index-subtitle">by {article.author.username}</h3>
<p className="article-index-snippet">{article.snippet}<Link className="article-index-show-link" to={`/articles/${article.id}`}>{"...more"}</Link></p>
<ArticleTags tags={["lookAtThisTag", "othertag"] } />
<h4>{article.count} Comments {article.likeCount} Likes</h4>
</div>
))}
<Subscription subscribeToMore={subscribeToMore} />
</div>
)
}}
</Query>
);
}
}
export default ArticlesIndex;
Subscription Component (as per evilmartians)
import React, { useEffect } from 'react';
import ArticleSubscription from './subscriptions/article_added';
import { graphql } from 'react-apollo';
const Subscription = ({ subscribeToMore }) => {
useEffect(() => {
return subscribeToMore({
document: ArticleSubscription,
updateQuery: (prev, { subscriptionData }) => {
console.log("subdata: ", subscriptionData.data)
if (!subscriptionData.data) return prev;
const { articleAdded } = subscriptionData.data;
if (articleAdded) {
const alreadyInList = prev.articles.find(e => e.id === articleAdded.id);
if (alreadyInList) {
return prev;
}
return { ...prev, articles: prev.articles.concat([articleAdded]) };
}
return prev;
},
});
}, []);
return null;
};
export default Subscription;
And the subscriptions themselves
import gql from 'graphql-tag';
const ArticleSubscription = gql`
subscription ArticleSubscription {
articleAdded {
id
title
body
likers
likeCount
author {
id
username
},
currentUser {
id
username
email
}
}
}`
export default ArticleSubscription;

AWS Lambda HTTPS post to Paypal IPN error

I have been trying to implement Paypal's IPN using AWS Api Gateway to get an IPN handler url. the api is integrated with a Lambda function as the "receiver".
I have tested the api gateway url using Paypal's IPN simulator.It works for the first step and I get this message "IPN was sent and the handshake was verified".
My problem is now with the next step,where I have to send the recived message back to Paypal using HTTPS post. I have tried a number of times and keep getting this error:
{
"code": "ECONNREFUSED",
"errno": "ECONNREFUSED",
"syscall": "connect",
"address": "127.0.0.1",
"port": 443
}
I really would appreciate some help in getting this to work.
I'm using node.js 8.10.Here's my Lambda function:
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
// Return 200 to caller
console.log('sending 200 back to paypal');
callback(null, {
statusCode: '200'
});
// Read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
console.log('modifying return body...');
var body = 'cmd=_notify-validate&' + event.body;
callHttps(body, context);};
function callHttps(body, context) {
console.log('in callHttp()....');
var https = require('https');
var options = {
url: 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr',
method: 'POST',
headers: {
"user-agent": "Nodejs-IPN-VerificationScript"
},
body: body
};
const req = https.request(options, (res) => {
res.on('data', (chunk) => {
// code to execute
console.log("on data - can execute code here....");
});
res.on('end', () => {
// code to execute
console.log("on end - can execute code here....");
});
});
req.on('error', (e) => {
console.log("Error has occured: ", JSON.stringify(e, null, 2));
});
req.end();}
managed to sort it out.i was using url instead of breaking it down to host and path.here's the full code that worked for me:
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
// Return 200 to caller
console.log('sending 200 back to paypal');
callback(null, {
statusCode: '200'
});
callHttps(event.body, context);};
function callHttps(body, context) {
console.log('in callHttp()....');
// Read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
console.log('modifying return body...');
var bodyModified = 'cmd=_notify-validate&' + body;
var https = require('https');
var options = {
host: "ipnpb.sandbox.paypal.com",
path: "/cgi-bin/webscr",
method: 'POST',
headers: {
'user-agent': 'Nodejs-IPN-VerificationScript',
'Content-Length': bodyModified.length,
}
};
const req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
var result = '';
res.on('data', (d) => {
// get the result here
result += d;
});
res.on('end', (end) => {
// check the result
if (result === 'VERIFIED') {
// process the message
// split the message
var res = body.split("&");
// create an object
var paypalMessageObject = new Object();
// loop through split array
res.forEach(element => {
// split element
var temp = (element.toString()).split("=");
// add to the object
paypalMessageObject[temp[0]] = temp[1];
});
console.log('paypalMessageObject: ' + JSON.stringify(paypalMessageObject, null, 2));
var checkItems = {
payment_status: paypalMessageObject.payment_status,
mc_gross: paypalMessageObject.mc_gross,
mc_currency: paypalMessageObject.mc_currency,
txn_id: paypalMessageObject.txn_id,
receiver_email: paypalMessageObject.receiver_email,
item_number: paypalMessageObject.item_number,
item_name: paypalMessageObject.item_name
};
console.log('checkItems: ', JSON.stringify(checkItems, null, 2));
}
else { console.log('not verified, now what?'); }
});
});
req.on('error', (e) => {
console.log("Error has occured: ", JSON.stringify(e, null, 2));
});
req.write(bodyModified);
req.end();}

How to store chat messages in database?

I'm using Node.js with Rails for a basic chat app. Now when i refreshed the page all messages get deleted. So i want to store messages in rails database using AJAX.
How can i do this?
nodejs/index.js
console.log("Server is starting...");
const http = require('http');
const hostname = '0.0.0.0';
const port = '8000';
console.log("Creating server...");
const server = http.createServer().listen(port, hostname);
console.log('chat server running on '+ hostname + ':' + port);
let socketList = require('socket.io').listen(server);
socketList.sockets.on('connection', function (socket) {
console.log('connection received');
console.log('socket in node = ', socket);
socket.on('disconnect', function () {
console.log('socket disconnected');
});
socket.on('join_room', function (data) {
socket.join(data.chatroom);
socketList.in(data.chatroom).emit('user_joined', {
user_email: data.user_email,
chatroom: data.chatroom
});
});
socket.on('send_message', function (data) {
console.log(data.message, data.user_email);
socketList.in(data.chatroom).emit('receive_message', {
message: data.message,
user_email: data.user_email
});
});
});
rails/application.js
window.addEventListener('load', function (ev) {
var user_email = $('#current_user_email').html(); // checking if user login
if(user_email){
var socket = io.connect('http://0.0.0.0:8000');
console.log('socket in rails = ' , socket);
socket.on('connect', function () {
console.log('connection established to node server');
});
socket.emit('join_room',
{
user_email: user_email,
chatroom: 'home'
});
socket.on('user_joined', function (data) {
console.log(data.user_email + ' joined ' + data.chatroom);
});
$('#send-message').click(function () {
let msg = $('#chat-message-input').val();
if(msg !==''){
socket.emit('send_message', {
message: msg,
user_email: user_email,
chatroom: 'home'
});
}
$('#chat-message-input').val('');
});
socket.on('receive_message', function (data) {
console.log(data.user_email, data.message);
let newMessage = $('<li>');
let messageType = 'other-message';
if (data.user_email === user_email){
messageType = 'self-message';
}
newMessage.addClass(messageType);
newMessage.append($('<span>', {
'html': data.message
}));
newMessage.append($('<sub>', {
'html': data.user_email
}));
$('#chat-messages-list').append(newMessage);
});
Also what are the different methods can be used to store messages in database?
Can we also store directly in the Rails database just using Node.js?
Not gonna write code but basically u can start:
rails g scaffold Chat name:text chat:text
then post with ajax to /chat.json set data like {name:user_name, chat:texxt}
Then also u need to ask all user chats from /chat.json
Also u need to write in rails in index function
if params[:id]) do
#chat = Chat.find(name:username)
else
#chat = Chat.all
end
Then show those messages to user
but this is basic concept to get u going

Resources