Dry validation i18n message for array validation - ruby

Let say I have define a dry-validation like this:
class ApplicationContract < Dry::Validation::Contract
config.messages.backend = :i18n
config.messages.load_paths << 'config/errors.yml'
params do
required(:todo).schema do
required(:title).filled(:string)
required(:items).array(:hash) do
required(:name).filled(:string)
end
end
end
end
Here is my config/errors.yml:
vi:
dry_validation:
errors:
rules:
title:
filled?: 'phai duoc dien'
key?: 'ko dc trong'
items:
name:
key?: 'thieu name'
filled?: 'name rong'
In my code, I use it to validate my data:
my_json = create_my_json
v = ApplicationContract.new
result = v.call(my_json)
render json: result.errors(locale: :vi).to_h
If my_json like:
{
"title": "",
"items": [
{
"name": "bbb"
}
]
}
then I got response:
{
"todo": {
"title": [
"phai duoc dien"
]
}
}
You guys can see my validation for field title works fine with locale vi
Now if my json like:
{
"title": "aa",
"items": [
{
"name": ""
}
]
}
then the response is:
{
"todo": {
"items": {
"0": {
"name": [
"translation missing: vi.dry_validation.errors.filled?"
]
}
}
}
}
The validation still works but it can not get my locale message. It show the warning "translation missing: vi.dry_validation.errors.filled?" instead. How can I fix this problem?

Finally I got it. Just remove the node items from config/errors.yml:
vi:
dry_validation:
errors:
rules:
title:
filled?: 'phai duoc dien'
key?: 'ko dc trong'
name:
key?: 'thieu name'
filled?: 'name rong'

Related

How to mutate a list of objects in an array as an argument in GraphQL completely

I cannot mutate a list of objects completely, because only the last element of the array will be mutated.
What already works perfectly is, if I put each element ({play_positions_id: ...}) in the array manually like here:
mutation CreateProfile {
__typename
create_profiles_item(data: {status: "draft", play_positions: [{play_positions_id: {id: "1"}}, {play_positions_id: {id: "2"}}]}) {
id
status
play_positions {
play_positions_id {
abbreviation
name
}
}
}
}
Output:
{
"data": {
"__typename": "Mutation",
"create_profiles_item": {
"id": "1337",
"status": "draft",
"play_positions": [
{
"play_positions_id": {
"id": "1",
"abbreviation": "RWB",
"name": "Right Wingback"
}
},
{
"play_positions_id": {
"id": "2",
"abbreviation": "CAM",
"name": "Central Attacking Midfielder"
}
}
],
}
}
}
Since you can add many of those elements, I defined a variable/argument like here
mutation CreateProfile2($cpppi: [create_profiles_play_positions_input]) {
__typename
create_profiles_item(data: {status: "draft", play_positions: $cpppi}) {
id
status
play_positions {
play_positions_id {
id
abbreviation
name
}
}
}
}
Variable object for above:
"cpppi": {
"play_positions_id": {
"id": "1"
},
"play_positions_id": {
"id": "2
}
}
Output:
{
"data": {
"__typename": "Mutation",
"create_profiles_item": {
"id": "1338",
"play_positions": [
{
"play_positions_id": {
"id": "2",
"abbreviation": "CAM",
"name": "Central Attacking Midfielder"
}
}
],
}
}
}
Schema:
input create_profiles_input {
id: ID
status: String!
play_positions: [create_profiles_play_positions_input]
}
input create_profiles_play_positions_input {
id: ID
play_positions_id: create_play_positions_input
}
input create_play_positions_input {
id: ID
abbreviation: String
name: String
}
At the last both snippets, only the last object with the id "2" will be mutated. I need these to use the defined input type from my backend.
I figured it out. I got it wrong with the brackets in the variable. Here the solution:
"cpppi": [
{
"play_positions_id": {
"id": "1"
}
},
{
"play_positions_id": {
"id": "2"
}
}
]

How do I tell Alexa to prompt user for input

I need to tell alexa to prompt user for input then store that input in a variable to be used in my code.
InvocationName: send mail
Alexa: Tell me mail subject
User: Test email
Alexa: Okay, tell me message body.
User: This is just a sample test
Alexa, okay, tell me receiver email
User: test#gmail.com
Below is my intent schema:
{
"interactionModel": {
"languageModel": {
"invocationName": "send mail",
"intents": [
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
},
{
"name": "SendMailIntent",
"slots": [
{
"name": "ReceiverEmail",
"type": "AMAZON.SearchQuery"
}
],
"samples": [
"mail",
"send mail"
]
}
],
"types": []
},
"dialog": {
"intents": [
{
"name": "SendMailIntent",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "ReceiverEmail",
"type": "AMAZON.SearchQuery",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.838288524310.965699312002"
}
}
]
}
],
"delegationStrategy": "ALWAYS"
},
"prompts": [
{
"id": "Elicit.Slot.838288524310.965699312002",
"variations": [
{
"type": "PlainText",
"value": "Enter subject"
}
]
}
]
}
}
and below is the code I have been able to come up with:
// sets up dependencies
const Alexa = require('ask-sdk-core');
const i18n = require('i18next');
const languageStrings = require('./languageStrings');
const SendMailHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
// var code = this.event.request.intent.slots.code.value;
//console.log(code)
// checks request type
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'SendMailIntent');
},
handle(handlerInput) {
const speechText = 'Ok. Tell me the mail subject'
const response = handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText) // <--- Here is our reprompt
.getResponse();
console.log(response)
return response;
},
};
// Omitted default Alexa handlers
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(
SendMailHandler,
)
.lambda();
You should use dialog management with 2 slots.
As I can see currently you only collect one slot (ReceiverEmail) with dialoge management.
But you need also to create a slot for the text you want to send.
Later in your code you need to check if the dialogue is in status COMPLETED.
See the example https://github.com/alexa/skill-sample-nodejs-petmatch/ or this video: https://www.youtube.com/watch?v=u99WMljnQXI

sailsjs: model email validation seems not to work

On a fresh sailsjs installation, I've got a test model defined like this:
module.exports = {
attributes: {
username:{
type:'string'
}
,email:{
type:'string'
,email:true
}
}
};
And if I navigate to this:
http://localhost:1337/user/create?username=stratboy1&email=test#wow.com
I get this error:
{
"error": "E_VALIDATION",
"status": 400,
"summary": "1 attribute is invalid",
"model": "User",
"invalidAttributes": {
"email": [
{
"rule": "email",
"message": "\"email\" validation rule failed for input: 'test#wow.com'"
}
]
}
}
Any of you knows why?
I've come across this earlier but don't quite remember the cause.
As a quick fix, you can substitute
email: { type: 'string', email: true }
with
email: { type: 'email' }

Iterate through JSON respone Facebook Graph

Im trying to iterate through a returned response from the Facebook Graph api
def get_feed
uri = URI(FACEBOOK_URL)
response = HTTParty.get(uri)
results = JSON.parse(response.body)['data']
puts formatted_data(results)
end
def formatted_data(results)
return unless results
formatted = results['data'].each do |d|
unless d.nil?
{
message: d['message'],
}
end
formatted.delete_if {|x| x.nil?}
end
end
The response is very large so here is a snippet if it helps
{
"data": [
{
"id": "197958940234297_827831980580320",
"from": {
"category": "Amateur sports team",
"category_list": [
{
"id": "189018581118681",
"name": "Sports Club"
},
{
"id": "139721016091877",
"name": "Outdoor Recreation"
},
{
"id": "109615542448700",
"name": "Physical Fitness"
}
],
"name": "Varsity Vandals",
"id": "197958940234297"
},
"to": {
"data": [
{
"id": "668983363",
"name": "Heather Walker"
},
{
"id": "638195502",
"name": "Emma Williams"
},
{
"id": "1286337937",
"name": "Becky Williams"
}
]
},
"with_tags": {
"data": [
{
"id": "668983363",
"name": "Heather Walker"
},
{
"id": "638195502",
"name": "Emma Williams"
},
{
"id": "1286337937",
"name": "Becky Williams"
}
]
},
"message": "Great turnout for the women's intro session today. Cool to have a women's game and a men's game running side by side. Touch is for all.",
"picture": "https://fbcdn-photos-f-a.akamaihd.net/hphotos-ak-prn2/t1.0-0/1507550_827829843913867_410211203232735862_s.jpg",
"link": "https://www.facebook.com/photo.php?fbid=827829843913867&set=pcb.827831980580320&type=1&relevant_count=2",
"icon": "https://fbstatic-a.akamaihd.net/rsrc.php/v2/yz/r/StEh3RhPvjk.gif",
"actions": [
{
"name": "Comment",
"link": "https://www.facebook.com/197958940234297/posts/827831980580320"
},
{
"name": "Like",
"link": "https://www.facebook.com/197958940234297/posts/827831980580320"
}
],
"privacy": {
"value": ""
},
I am getting an error
TypeError: no implicit conversion of String into Integer
At the moment i would just like to pull out all the Messages from the JSON object...Am i handling the extraction correctly
Any help appreciated
Thanks
I tried you code, I change you require is move formatted.delete_if {|x| x.nil?} out of loop, like following, as formatted will be nil inside the loop.
def formatted_data(results)
return unless results
formatted = results['data'].each do |d|
unless d.nil?
{
message: d['message'],
}
end
end
formatted.delete_if {|x| x.nil?}
end
are you sure your not using the data key twice?
results = JSON.parse(response.body)['data'] in main method and formatted = results['data'].each in your formatted_data method?
Thinking maybe?
def def formatted_data(results)
return unless results
results['data'].map {|m| {message: m['message']} }.compact
end
I'd do this:
def get_feed
uri = URI(FACEBOOK_URL)
response = HTTParty.get(uri)
messages = format_data(response)
for message in messages do
puts message
end
end
def format_data(response, new_data = [])
if response.present?
results = JSON.parse(response)
for result in results do
new_data << result[:data][:message] if result[:data][:message].present?
end
return new_data #-> array of messages
end
end

ActiveRecord relation with nested objects to JSON

I'm using ActiveRecord with Sinatra. I have AR relation Post has_many Comments.
I need to create response in JSON that returns all posts and their comments. It should look like this:
[
{
"id":1,
"title:"Title_1",
"comments":[
{ "content":"lorem ipsum", "post_id":1 },
{ "content":"foo bar", "post_id":1 },
]
},
{
"id":2,
"title:"Title_2",
"comments":[
{ "content":"lorem ipsum", "post_id":2 },
{ "content":"foo bar", "post_id":2 },
]
}
]
I think it common task to create response like that, so I hope there should be some nice way to do it.
My temporary solution (the code below) works correctly but it too long and unreadable:
Post.all.map{|x| x.as_json(include: [:comments]).values[0] }.to_json
This is another solution that I found:
Post.all.as_json(include: [:comments]).to_json
Sadly, the returned structure looks different, it wraps every post into additional node "post: {}". I'd like to avoid it.
[
{
"post":{
"id":1,
"title:"Title_1",
"comments":[
{ "content":"lorem ipsum", "post_id":1 },
{ "content":"foo bar", "post_id":1 },
]
}
},
{
"post":{
"id":1,
"title:"Title_2",
"comments":[
{ "content":"lorem ipsum", "post_id":2 },
{ "content":"foo bar", "post_id":2 },
]
}
}
]
try:
ActiveRecord::Base.include_root_in_json = false
http://apidock.com/rails/ActiveRecord/Serialization/to_json

Resources