Positing JSON to Rails API from Ember JS - ruby-on-rails

I'm trying to post data from my Ember app to my Rails API for a blog application I'm playing with.
I'm having a few issues, which I think each stem from my initial problem.
First of all, when I try to store the data from my inputs in Ember, I can't seem to store them in any variables. I've tried checking to see if I'm trying to access the values the wrong way but the documents I've been reading (Ember docs, and other stack overflow questions) lead me to believe I'm doing this correctly.
//new.js
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Route.extend({
actions:{
createPost(){
var created_at = new Date();
var user = this.store.findRecord('user', 1);
var title = this.get('title');
var body = this.get('body');
console.log(title, body);
// console.log(user);
var post = this.store.createRecord('post', {
title: title,
body: body,
created_at: created_at,
user: user
})
post.save();
}
}
});
and
//new.hbs
{{outlet}}
<form>
<strong>Title</strong><br/>
{{input name="title" value=title}}<br/>
<strong>Body</strong><br/>
{{input name="body" value=body}}<br/>
<button type="submit" {{action 'createPost'}}>Submit</button>
</form>
My output of title and body returns undefined.
Another issue I'm having is when I try post this data to my Rails API, I get a 422 error. It says that there is an unpermitted parameter (created_at) included, so I was wondering if there was a way to exclude parameters from my post request?
Thanks in advance.

I would move this action in controller, than define title and body as property.
import Ember from 'ember';
export default Ember.Controller.extend({
title: null,
body: null,
actions: {
createPost(){
var created_at = new Date();
var user = this.store.findRecord('user', 1);
var title = this.get('title');
var body = this.get('body');
console.log(title, body);
// console.log(user);
var post = this.store.createRecord('post', {
title: title,
body: body,
created_at: created_at,
user: user
})
post.save();
}
}
})
Error is showing because you didn't define title and body.
As for other part of problem with param created_at just remove it from model or from this.store.createRecord() block

The following snippet instantiates a new post record in the model hook which is available to the template.
//new.js
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Route.extend({
model() {
return this.store.createRecord('post');
},
actions:{
createPost(){
var user = this.store.findRecord('user', 1);
var created_at = new Date();
var post = this.currentModel;
post.setProperties({created_at: created_at, user: user});
post.save();
}
}
});
and your template becomes
//new.hbs
{{outlet}}
<form>
<strong>Title</strong><br/>
{{input name="title" value=model.title}}<br/>
<strong>Body</strong><br/>
{{input name="body" value=model.body}}<br/>
<button type="submit" {{action 'createPost'}}>Submit</button>
</form>
The var user = this.store.findRecord('user', 1); line in it's current form will cause issues since findRecord returns a promise.
To exclude the created_atfrom being sent to the API endpoint, create a post serializer
//serializers/post.js
import DS from 'ember-data';
// NOTE: Update the serializer to reflect your project's serializer choice
export default DS.JSONAPISerializer.extend({
attrs: {
created_at: { serialize: false }
}
});

Related

how to retrieve form values and labels from react hook form and antd Select

I am using antd Select and react hook form via 'Controller'. I am populating the Select options from a fetched data with structure;
{
{
"id": "232342",
"term": "hello"
}
{
"id": "232342",
"term": "hello"
}
}
the Select component properly displays the term for selection. However, i want to retrieve both the 'id'and 'term' of the selected and use it to populate another json object.
getValues(" ") retrieves the 'id' only. How do i retrieve and access both the 'id' and 'term'.
Here is a portion of code:
import React from 'react'
import { useForm, Controller } from 'react-hook-form'
import { Select } from 'antd'
const { Option } = Select
export default function PatientRegistrationForm({ options }) {
const { register, handleSubmit, getValues, control, formState: { errors } } = useForm({
defaultValues: {
customer: "",
}
})
const children = []
for (const {id, pt: {term}} of options){
children.push(<Option key={id}>{term}</Option>)
}
// Define the retrieved values from the form
const retrievedID = getValues("customer")
// Use the retreived values to populate this object
const customer = {
customerId = retrievedID
customerName = "nothing happens here"
},
return (
<div className="">
<form onSubmit={handleSubmit(onSubmit)} className="">
<section>
<Controller
control={control}
name="customer"
render={({ field }) => (
<Select {...field} defaultValue=""
bordered={true}
filterOption={true}
className="form-control"
>
{ children }
</Select>
)}
/>
</section>
</form>
</div>
);
}
Thanks in advance for your help.
You have to retrieve the option manually using something like:
const retrievedID = getValues("customer")
const retrievedOption = options.find(option => option.id === retrievedID)
const customer = {
customerId: retrievedID,
customerName: retrievedOption.term
}
thank you #sgarcia.dev for your answer. I know its been a while but i want to put it out here incase it helps someone else. It turns out it had little to do with react hook form. Ant design select component has a prop 'labelInValue' which returns an object containing both the label and value.

Form Data not submitting complete string

Could someone tell me what my form data's string ends at the comma? I'm sending a form with react with a string with foo, bar but only foo is sent in the form data. This has nothing to do with the database as in the chrome dev tools, under network, I see only one value of the string. Here's a image of my actual views:
Only Wordpress, gets submitted. Noticed the ,?
Some code, in React (I'm using react-select):
<form action="/" method="post">
<Select ref="stateSelect" options={skillsOptions} simpleValue multi={this.state.multi} value={this.state.skillsSelectValue} name="skills" onChange={this.skillsUpdateValue} valueKey="value" labelKey="name" loadOptions={this.getContributors} />
</form>
skillsUpdateValue: function(newValueCnd) {
// var str = newValueCnd.split(',');
this.setState({
skillsSelectValue: newValueCnd
});
this.setState({
skills: newValueCnd
});
},
Am I missing something from the form? Using just Rails, all words great.
Edit:
Input options:
var skillsOptions = [
{ value: 'one', name: 'One' },
{ value: 'two', name: 'Two' }
];

Setting error message in html with knockout validation

I would like to use knockout-validation by only adding validation rules in HTML5, which works great:
http://jsfiddle.net/gt228dgm/1/
I would then like to change the default error messages generated by the browser (like "This field is required." or "Invalid"). This is pretty easily done in javascript code, But I believe this kind of texts should go into the HTML. Is that possible and how? I guess I'm looking for something like:
<input data-bind='value: firstName, validate: { message: "Please enter first name" }' required pattern="^[A-Za-z]{1,255}$"/></label>
I have implemented a custom knockout binding that solves my issue:
ko.bindingHandlers.validate = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var valueBinding = allBindings().value;
var value = valueAccessor();
if (value) {
valueBinding.extend(value);
}
}
};
The binding then looks like this
<input data-bind='value: firstName, validate: { required: { message: 'Full name is missing' }, pattern: { message: 'Full name should be max. 255 alphanumeric characters' } }' required pattern="^[A-Za-z]{1,255}$"/>
Any other suggestions?
I've been playing these days with knockout validation. For your need, you could use validationMessage binding. Here is an example of your code modified, to use this binding: http://jsfiddle.net/elbecita/gt228dgm/4/
Basically, you'd end up having something like:
<span data-bind="validationMessage: firstName, text: 'Your error.'"></span>
<input data-bind='value: firstName, valueUpdate: "input"' required pattern="^[A-Za-z]{1,255}$" />
I've added the valueUpdate binding just to have the validation message shown immediately. And then, in your javascript code, when you define the validation configuration, be sure to turn to false the insertMessages option. If not, you'll see the default message too.
But... I think is easier and cleaner to do this with the knockout extenders in javascript code, having all custom messages centralized in some sort of constants file, instead of having them scattered through the html.
Anyway, dig into the knockout validation bindings, they may help you with your needs. :)
Proper way to handle custom validation message in KO is to create a custom validation not binding.
Here is an example of simple number validation
ko.validation.rules['integerFormat'] = {
validator: function (value, options) {
if (!value) return true;
var regex = /^\d+$/;
var matches = regex.test(value);
if(matches){
value = parseInt(value,10);
return typeof value== "number" && isFinite(value) && value%1===0;
}else{
return false
}
},
message: app.MyCustomIntegerNotValidMSG
}
app.MyCustomIntegerNotValidMSG is just a variable holding your MSG
You would use this in your ViewModel like this
self.myIntegerToValidate = ko.observable().extend({
integerFormat:{}
});;

Ember.js route is not performing a new request when params change

I'm working in my first web app with Ember.js backed with a Rails for API.
I have the following nested resources:
this.resource('selection_processes', function() {
this.resource('selection_process', { path: '/:selection_process_id' }, function() {
this.resource('candidate', { path: '/candidates/:candidate_id' });
});
})
So, when I access selection_processes/1 it's getting all of its candidates. Thats ok, but the problem is when I click on another selection process link Ember does not perform a new request, rendering no data in my templates. Btw, the API is returning the correct objects.
The only way I got this working was including all objects in my serializers, making Ember getting all the data of the whole nested resources in a single request. But this seems to be a lazy practice and "heavy".
By the way, here are my routes:
Safira.SelectionProcessesRoute = Ember.Route.extend({
model: function () {
return this.store.find('selection_process');
}
});
Safira.SelectionProcessRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('selection_process', params.selection_process_id);
}
});
Safira.CandidateRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('candidate', params.candidate_id);
}
});
UPDATE
Here are my models
Safira.SelectionProcess = DS.Model.extend({
beginDate : DS.attr('date'),
endDate : DS.attr('date'),
title : DS.attr('string'),
description : DS.attr('string'),
steps : DS.hasMany('Safira.Step', {async: true})
});
Safira.Step = DS.Model.extend({
realization: DS.attr('date'),
title: DS.attr('string'),
candidates: DS.hasMany('Safira.Candidate', {async: true}),
selection_process : DS.belongsTo('Safira.SelectionProcess')
});
Safira.Candidate = DS.Model.extend({
name : DS.attr('string'),
email : DS.attr('string'),
confirmation_token : DS.attr('string'),
step : DS.belongsTo('Safira.Step')
});
you have to pass same data in both cases.(when you get a collection or individual items).
I think you are returning partial data in case of collection.
When you go through a link it assumes it already has data for that model so it won't send a new request. IMO you should be able to access partial data of that model received in collection.
if the model is big, split it into multiple models. it require server side change also.

Reading parameters enterd on the screen

I have a page that accepts parameters from the user. I read this parameter in my action using params.playerId. and then do the computations with it.
I have changed my UI now and am using extJS for display purposes.
Therefore I have an edit and an editData action.
editData action has the code to run the sql and execute the appropriate js file and displays edit.jsp. However, in the editData action, when I use params.playerId, I get a null value.
What can be a work round for this scenario?
My code before integrating with extJS: list action is called and list.gsp is displayed with data.
def list = {
def session = sessionFactory.getCurrentSession()
def result = session.createSQLQuery("select player_id from w.music where player_id=(params.playerId)").list();
def tuneInstanceList = new ArrayList()
def tune = new Tune()
result.each
{
tune.playerId = it
tune.playerPrice = "100" tuneInstanceList.add(tune)
}
[recoveryInstanceList: recoveryInstanceList]
}
Now, when I ntegrate with extJS, I get the value of params.playerId as null. Code is below.
list.gsp:
<%# page import="tune.Music"%>
<script type="text/javascript">
var ds = new Ext.data.Store({
autoLoad: true,
proxy: new Ext.data.HttpProxy({
url: 'http://localhost:8080/tune/music/listData'}),
reader: new Ext.data.JsonReader({
results: 'total',
root:'items',
id:'id'
},
[
{name: 'playerId'},
{name: 'playerPrice'}
]
)
});
var cm = new Ext.grid.ColumnModel([
{header: "Player Id", width: 70, sortable:true, dataIndex: 'playerId'},
{header: "Player Price", width: 90, dataIndex: 'playerPrice'}
]);
//cm.defaultSortable = true;
// create the grid
var grid = new Ext.grid.GridPanel({
ds: ds,
cm: cm,
renderTo:'grid-example',
width:1300,
height:300
});
</script>
<div class="body">
<!--<g:javascript library="examples"/>-->
<!-- EXAMPLES -->
<h1>Ext Grid</h1>
<div id="grid-example"></div>
</div>
My controller action:
def list={ }
def listData = {
def session = sessionFactory.getCurrentSession()
def result = session.createSQLQuery("select player_id from w.music where player_id= (params.playerId)").list();
def tuneInstanceList = new ArrayList()
result.each {
def tune = new Tune()
tune.playerId = it tune.playerPrice = "100"
tuneInstanceList.add(tune)
}
def listResult = [total: tunInstanceList.size(), items: tunInstanceList]
render listResult as JSON;
}
How can I retrieve the parameters that have been entered by the user??
Thanks!
Worked around this issue by reading the parameters in list() action and saving it in a session.
Then used this session data in the listData() action to do the computations.
Not sure if this is the best approach. This is just a workaround.

Resources