React Axios to Rails Knock - ruby-on-rails

I am trying to send a POST request from axios to a Rails API using the following function in the React frontend:
export function registerUser({ name, email, password }) {
var postdata = JSON.stringify({
auth: {
name, email, password
}
});
return function(dispatch) {
axios.post(`${API_URL}/user_token`, postdata )
.then(response => {
cookie.save('token', response.data.token, { path: '/' });
dispatch({ type: AUTH_USER });
window.location.href = CLIENT_ROOT_URL + '/dashboard';
})
.catch((error) => {
errorHandler(dispatch, error.response, AUTH_ERROR)
});
}
}
The Knock gem expects the request in the following format:
{"auth": {"email": "foo#bar.com", "password": "secret"}}
My current function seem to generate the correct format (inspecting the request in the browser devtools), but I'm getting the following error:
Uncaught (in promise) Error: Objects are not valid as a React child
(found: object with keys {data, status, statusText, headers, config,
request}). If you meant to render a collection of children, use an
array instead or wrap the object using createFragment(object) from the
React add-ons. Check the render method of Register.
class Register extends Component {
handleFormSubmit(formProps) {
this.props.registerUser(formProps);
}
renderAlert() {
if(this.props.errorMessage) {
return (
<div>
<span><strong>Error!</strong> {this.props.errorMessage}</span>
</div>
);
}
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
{this.renderAlert()}
<div className="row">
<div className="col-md-6">
<label>Name</label>
<Field name="name" className="form-control" component={renderField} type="text" />
</div>
</div>
<div className="row">
<div className="col-md-12">
<label>Email</label>
<Field name="email" className="form-control" component={renderField} type="text" />
</div>
</div>
<div className="row">
<div className="col-md-12">
<label>Password</label>
<Field name="password" className="form-control" component={renderField} type="password" />
</div>
</div>
<button type="submit" className="btn btn-primary">Register</button>
</form>
);
}
}

The error is caused by the following line in your code
errorHandler(dispatch, error.response, AUTH_ERROR)
The exception raised clearly explains that. Instead of setting error.response, try to use the actual data from error.response. E.g error.response.data. Also, you can try replacing the error.response with a string and see how that behaves, then reference the string you need from error.response.data.

Related

TypeError: Cannot read property 'message' of undefined ---using react-hook-form

I am trying to display an error message when nothing is typed inside the message input form, but when I load the page I get this error 'TypeError: Cannot read property 'message' of undefined'. I am using react-hook-forms. This is my code down below.
import { Button } from "#material-ui/core";
import { Close } from "#material-ui/icons";
import React from "react";
import { useForm } from "react-hook-form";
import "./SendMail.css";
const SendMail = () => {
const { register, handleSubmit, watch, errors } = useForm();
const onSubmit = (formData) =>{
console.log(formData)
}
return (
<div className="sendMail">
<div className="sendMail__header">
<h3>New Message</h3>
<Close className="sendMail__close" />
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<input name='to' placeholder="To" type="text" {...register('to',{required:true})}/>
<input name="subject" placeholder="Subject" type="text" {...register('subject',{required:true})} />
<input
name="message"
placeholder="Message..."
type="text"
className="sendMail__message"
{...register('message',{required:true})}
/>
{errors.message && <p>To is required!!</p>}
<div className="sendMail__send">
<Button
className="sendMail__send"
variant="contained"
color="primary"
type="submit"
>
Send
</Button>
</div>
</form>
</div>
);
};
export default SendMail;
Since v7 the errors object moved to the formState property, so you need to adjust your destructering:
const { register, handleSubmit, watch, formState: { errors } } = useForm();

How to check if a url belongs to a website that exists?

I am making a website where in a form, users can input a web page address. I was going to go with checking if the url is formatted correctly like an actual url which I think is the sloppy way and instead I want to check if url belongs to an actual website. Like, let's say user inputs www.pyrtyrmyrsyr.org, that is a valid address, but it doesn't lead to a website. Let's say user inputs www.python.org, that is both a valid address and leads to a website that exists.
And how can I check this validity before the form is sent and after input is given? Make the form's "send" button not clickable if url is not valid?
EDIT : Realized I didn't add any code of my view, apologize for that, also forgot to mention I use Bootstrap for View.
This is the form I use, what I am trying to do is use "Check" button, to check validity, by taking URL inside form-control with "id=url"
<div>
<div class="row">
<div class="col-md-12">
<h2 style="margin-left:20px; margin-top:10px">Add a Link</h2>
<form action="~/Link/Create" method="post">
<div class="form-group well clearfix" style="margin-left:20px; margin-right:20px; margin-top:20px">
<br />
<div class="row">
<label for="name" class="col-lg-2">URL:</label>
<div class="col-lg-9">
<input class="form-control" id="url" placeholder="URL" name="Address" /><br />
</div>
<div class="col-lg-1">
<button type="button" class="btn btn-primary" id="checkurl">Check</button>
</div>
</div>
<div class="row">
<div class="col-lg-2">
<label for="name">Interval:</label>
</div>
<!--<div class="col-lg-10">
<input class="form-control" placeholder="Interval to check (minutes)" name="Interval" /><br />
</div>-->
<div class="col-lg-5">
<select class="form-control" id="sel1">
<option>Minutes</option>
<option>Hours</option>
<option>Days</option>
<option>Weeks</option>
<option>Months</option>
</select>
</div>
<div class="col-lg-5">
<select class="form-control" id="sel2">
<option>Minutes</option>
<option>Hours</option>
<option>Days</option>
<option>Weeks</option>
<option>Months</option>
</select>
</div>
</div>
<div class="row">
<button class="btn btn-success pull-right" type="submit" style="width:200px; margin-right:15px">Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
As far as I searched so far, connection to another domain/website is not possible using Javascript or anything similar so I need a server-side language, so I need to take this url, send it to control and return a true/false value after checking connection.
You can use Remote Validation in Asp.NET MVC. Let you have following property in your model.
public string URL {get; set;}
Add Remote attribute to your property like
[Remote("YourAction", "YourController", HttpMethod = "GET", ErrorMessage = "URL is not valid.")]
public string URL {get; set;}
Now write the following code in your specified action of the controller.
public class YourController : Controller
{
[AllowAnonymous]
public ActionResult YourAction(string URL)
{
try
{
//Check here by hitting your URL using HTTPClient or WebClient that it is returning something or not.
WebClient wc = new WebClient();
string HTMLSource = wc.DownloadString(URL);
return Json(true, JsonRequestBehavior.AllowGet); //Return true if it is valid.
}
catch (Exception)
{
return Json(false, JsonRequestBehavior.AllowGet); //Return false if it is not vald.
}
}
}
You must have to add following configurations in your web.config
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
Your code on view will be like
#Html.EditorFor(model => model.URL, new { type = "url", #class = "form-control", placeholder = "URL" } })
#Html.ValidationMessageFor(model => model.URL, "", new { #class = "text-danger" })
Solved it:
Added a bool to my model:
public bool Valid { get; set; }
Changed my view a little:
<div class="row">
<label for="name" class="col-lg-2">URL:</label>
<div class="col-lg-9">
<input class="form-control" id="url" placeholder="URL" name="Address" /><br />
</div>
<div class="col-lg-1">
<button type="button" class="btn btn-primary pull-right" id="checkurl">Check</button>
</div>
<input type="hidden" name="Valid" id="Validity"/>
</div>
Used the following codes, one for checking validity, other to reset form being usable if input is changed
$('#checkurl').click(function () {
var address = $('#url').val();
$.ajax({
url: "/Control/CheckUrl",
type: "POST",
data: JSON.stringify({ url: address }),
cache: false,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
error: function (xhr) {
alert('Error: ' + xhr.statusText);
},
success: function (result) {
if (result) {
document.getElementById("Validity").value = true;
document.getElementById("saveBut").disabled = false;
}
else {
document.getElementById("Validity").value = false;
document.getElementById("saveBut").disabled = true;
}
},
async: true,
processData: false
});
});
$('#url').change(function ()
{
if (document.getElementById("saveBut").disabled == false)
{
document.getElementById("Validity").value = false;
document.getElementById("saveBut").disabled = true;
}
});
Ajax code there leads to a controller function that reformats URL a bit and checks validity:
public ActionResult CheckUrl(string url)
{
try
{
if (String.IsNullOrEmpty(url)) return Json(false, JsonRequestBehavior.AllowGet); ;
if (url.Equals("about:blank")) return Json(false, JsonRequestBehavior.AllowGet); ;
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
{
url = "http://" + url;
}
WebClient wc = new WebClient();
string HTMLSource = wc.DownloadString(url);
return Json(true, JsonRequestBehavior.AllowGet);
}
catch (Exception)
{
return Json(false, JsonRequestBehavior.AllowGet);
}
}
It works flawlessly and as desired.

Dynamically add multiple fields to be validated using bootstrap validator

I have gone through the example here. But it illustrates dynamic addition of a single input field. I have to add multiple dynamic input fields. How can I achieve it? Refer this example jsfiddle
I need to dynamically add all the three fields in the table row on clicking button through.
You can try somethings like this:
<form id="myForm" action="myAction">
<div class="row" id="line_1">
<div class="col-md-2 form-group">
<input type="text" class="form-control input-sm" id="idFirstField_1" name="firstField[]">
</div>
<div class="col-md-2 form-group">
<input type="text" class="form-control input-sm" id="idSecondField_1" name="secondField[]">
</div>
<div class="col-md-2 form-group">
<input type="text" class="form-control input-sm" id="idThirdField_1" name="thirdField[]">
</div>
</div>
<a id="cloneButton">add line</a>
</form>
In the JavaScript file you must to use the function clone() and to change the id of each input if you want:
$(document).ready(function () {
var count = 2;
$('#cloneButton').click(function () {
var klon = $('#line_1');
klon.clone().attr('id', 'line_' + (++count)).insertAfter($('#line_1'));
$('#line_' + count).children('div').children('input').each(function () {
$(this).val('');
var oldId = $(this).attr('id').split('_');
$(this).attr('id', oldId[0] + '_' + count);
});
});
//if you want to validate the fields, then you can use this code:
$('#myForm').bootstrapValidator({
fields: {
'firstField[]': {
validators: {
notEmpty: {
message: 'Enter a value'
}
}
},
'secondField[]': {
validators: {
notEmpty: {
message: 'Enter a value'
}
}
},
'thirdField[]': {
validators: {
notEmpty: {
message: 'Enter a value'
}
}
}
}
});
});
Now the bootstrap validation does not will work for cloned fields because you must to use in the JavaScript file somethings like this
$('#myForm').bootstrapValidator('addField', $option); //(from your link http://bootstrapvalidator.com/examples/adding-dynamic-field/ )
but who will contains all fields. I don't now how to do it.

Saving data through AngularJS

Update:
I have replaced <input type=submit to <button ... and also remove the form tag from my html, after modifying my code i do not see it executing my JS and I have a debugger line in the code and it does not break....
I'm trying to POST data and I have all the code in placed and wired-up correctly (I believe) but when I try to Submit my page # My page gets refreshed, I don't see any event is firing and I have set debugger in the JS, and I do not see any JS error in developer tool
What I'm missing here apart from my code?
here is my code:
//HML code
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My AngularJS App</title>
<script src="../AppScripts/RequesterAdd.js"></script>
</head>
<body>
<form>
<div ng-app="requesterAddModule" ng-controller="requesterAddController" class="container">
<h2> add requester</h2>
<div ng-show="ShowMessage">Record saved Successfully</div>
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>HostModel</h4>
<hr />
<div class="form-group">
<div>First Name:</div>
<div class="col-md-10">
<input type="text" ng-model="FirstName" required class="form-control input-lg" placeholder="First Name" />
</div>
</div>
<div class="form-group">
<div>Middle Name:</div>
<div class="col-md-10">
<input type="text" ng-model="MiddleName" required class="form-control input-lg" placeholder="Middle Name" />
</div>
</div>
<div class="form-group">
<div>Last Name:</div>
<div class="col-md-10">
<input type="text" ng-model="LastName" required class="form-control input-lg" placeholder="Last Name" />
</div>
</div>
<div class="form-group">
<div>eMail Address:</div>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span>
<input type="text" ng-model="Email" required class="form-control input-lg" placeholder="Email Address" />
</div>
</div>
<div class="form-group">
<div>Is Host Active:</div>
<div class="col-md-10">
<input type="checkbox" ng-model="Active" required class="control-label col-md-2" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" id="btnCreate" data-ng-click="addRequester_ClickEvent" value="Create" class="btn btn-primary" />
</div>
</div>
</div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</div>
</form>
</body>
</html>
//JS:
var requesterAddModule = angular.module("requesterAddModule", []);
requesterAddModule.factory('requesterAddService',
['$http', function ($http) {
return {
addRequester: function (reqesterData) {
console.log(reqesterData);
debugger;
$http({
url: 'PersistRequester',
method: 'POST',
data: reqesterData
}).then (function (response) {
if (response !== 'undefined' && typeof(response) == 'object') {
window.location.href = '/'
}
},
function(response) {
//failed
}
);
}
};
}]);
requesterAddModule.controller('requesterAddController', ['$scope', '$http', '$window', 'requesterAddService', function ($scope, $http, $window, requesterAddService) {
$scope.addRequester_ClickEvent = function () {
var req = {};
debugger;
req["FirstName"] = $scope.FirstName;
req["MiddleName"] = $scope.MiddleName;
req["LastName"] = $scope.LastName;
req["Email"] = $scope.Email;
req["Active"] = $scope.Active;
requesterAddService.addRequester(req);
}
}]);
//MVC Server side code:
[HttpPost]
public JsonResult PersistRequester(Requester requester)
{
var req = requester;
//if (ModelState.IsValid)
// {
req.CreatedDateTime = DateTime.Now;
db.Requesters.Add(requester);
db.SaveChanges();
return Json(new { Status = "Success" });
//}
}
You're using a form without a method and action which will by default post to the current url. I would highly recommend not to use a form or at least not using an <input type="submit" /> which will default in all the browsers to submit the form.
You're clearly using Bootstrap 3 here so why not just remove the form tag and the submit button and replace it with another element which will not trigger the form post and style it with class="btn btn-primary". Some could argue against this practise along the graceful degradation guidelines but since this particular form is not built from ground up to support the non-js scenario, it is best not to allow browser submit at all.
Also, in your service where you're doing the actual post, you specifically tell the page to reload.
if (response !== 'undefined' && typeof(response) == 'object') {
window.location.href = '/'
}
You should pass this data back to the viewmodel so that the view can re-render and display the response.
If you change the url, the view state is lost and the page will simply render again to the initial state.
instead line
<input type="submit" id="btnCreate" data-ng-click="addRequester_ClickEvent" value="Create" class="btn btn-primary" />
please do
<button id="btnCreate" data-ng-click="addRequester_ClickEvent()" class="btn btn-primary" >Create</button>
I've just tested and is working for me replace:
<input type="submit" id="btnCreate" data-ng-click="addRequester_ClickEvent" value="Create" class="btn btn-primary" />
with
<button id="btnCreate" data-ng-click="addRequester_ClickEvent()" value="Create" class="btn btn-primary" >submit</button>
and I've change a bit your service to :
requesterAddModule.factory('requesterAddService',
['$http', function ($http)
{
return {
addRequester: function (reqesterData)
{
console.log(reqesterData);
debugger;
$http.post('PersistRequester', reqesterData).then(function (response)
{
if (response !== 'undefined' && typeof (response) == 'object') {
window.location.href = '/'
}
},
function (response)
{
//failed
}
);
}
};
}]);
it's posting to /home/PersistRequester if method 'PersistRequester' exist in other controller ie : foo controller change
$http.post('PersistRequester', reqesterData).then(function (response)
to $http.post('foo/PersistRequester', reqesterData).then(function (response)

.Net MVC - Submitting the form with AngullarJS

I'm pretty new at AngularJS and i'm trying to use it in my new project. I have made an basic login form. When i submit the form, i'm unable to read the values that AngularJS in sending.
Here is my View
<html>
<head>
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<link href="~/Style/Style.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<title>Welcome to Elara!</title>
<script>
var formApp = angular.module('formApp', []);
function formController($scope, $http) {
$scope.formData = {};
$scope.processForm = function () {
$http({
method: 'POST',
url: 'Home/Login',
data: { UserName: $scope.formData.UserName, Password: $scope.formData.Password },
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.success(function (data) {
console.log(data);
if (!data.success) {
//do things here
} else {
//do things here
}
});
};
}
</script>
</head>
<body ng-app="formApp" ng-controller="formController">
<div id="FormArea">
<div id="Login" class="well well-sm">
<form role="form" ng-submit="processForm()">
<div class="form-group">
<label for="LoginUserName">User Name</label>
<input type="text" class="form-control" id="LoginUserName" placeholder="Username" ng-model="formData.UserName">
<br />
<label for="LoginPassword">Password</label>
<input form="LoginPassword" type="password" class="form-control" placeholder="Password" ng-model="formData.Password" />
<br />
<button type="submit" class="btn btn-default">Login</button>
</div>
</form>
</div>
<div id="Login">
</div>
</div>
</body>
</html>
And my controller
public bool Login(string UserName, string Password)
{
var userName = UserName;
var password = Password;
return Login(userName, password);
}
The problem is username and password is always null. I'm receiving a string like this from post event
Request.Form = {%7b%22UserName%22%3a%22h%22%2c%22Password%22%3a%22h%22%7d}
You're not really submitting a model, rather 2 arguments, so use params instead of data in your $http request:
$http({
method: 'POST',
url: 'Home/Login',
params: { UserName: $scope.formData.UserName, Password: $scope.formData.Password },
})
Secondly, I hope you're not trying to post this to an MVC controller, post it to a Web API controller instead.

Resources