Ruby - Append data to existing JSON - ruby-on-rails

According to this answer, its possible to append data to JSON.
But when I try test.push I get the error NoMethodError: undefined method push' `.
NETWORK_SG = Azure::Armrest::Network::NetworkSecurityGroupService.new(conf)
network_sg = NETWORK_SG.get('testing_123', rg)
test = network_sg.properties
puts test
{
"provisioningState": "Succeeded",
"resourceGuid": "test",
"securityRules": [
{
"name": "SSH",
"id": "SSH",
"etag": "18",
"type": "Microsoft/securityRules",
"properties": {}
}
]
}
options = {"key": "value"}
test.push(options)
How can I append the following JSON data to securityRules[]? Sometimes securityRules[] can be a empty array but I still want to append.
{
:name => 'rule_2',
:properties => {
:protocol => 'TCP',
:sourceAddressPrefix => '*',
:destinationAddressPrefix => '*',
:access => 'Allow',
:destinationPortRange => '22',
:sourcePortRange => '*',
:priority => '301',
:direction => 'Inbound',
}
}

You can use Array#push like this:
test = {
:provisioningState=>"Succeeded",
:resourceGuid=>"test",
:securityRules=>[
{:name=>"SSH", :id=>"SSH", :etag=>"18",:type=>"Microsoft/securityRules", :properties=>{}}
]
}
new_rule = {
:name => 'rule_2',
:properties => {
:protocol => 'TCP',
:sourceAddressPrefix => '*',
:destinationAddressPrefix => '*',
:access => 'Allow',
:destinationPortRange => '22',
:sourcePortRange => '*',
:priority => '301',
:direction => 'Inbound',
}
}
test[:securityRules].push(new_rule)
test
# {
# :provisioningState=>"Succeeded",
# :resourceGuid=>"test",
# :securityRules=> [
# {:name=>"SSH", :id=>"SSH", :etag=>"18", :type=>"Microsoft/securityRules", :properties=>{}},
# {:name=>"rule_2",:properties=>{:protocol=>"TCP",:sourceAddressPrefix=>"*",:destinationAddressPrefix=>"*",:access=>"Allow",:destinationPortRange=>"22",:sourcePortRange=>"*",:priori# ty=>"301",:direction=>"Inbound"}}
# ]
# }

Related

how to stub a post request with the required response in rails minitest

I am trying to stub a post request with the below response
{ 'data' => {
'detections' =>
[
[{
'language' => 'en',
'isReliable' => false,
'confidence' => 0.134
}],
[{
'language' => 'ar',
'isReliable' => false,
'confidence' => 0.9882
}]
]
} }
Can anyone help
You can use webmock https://github.com/bblimke/webmock#stubbing-requests-based-on-method-uri-body-and-headers
response = { 'data' => {'detections' =>[[{'language' => 'en','isReliable'=>false,'confidence' => 0.134}],[{'language' => 'ar','isReliable' => false,'confidence' => 0.9882 }]]}}
stub_request(:post, "url").with(<if needed>).to_return(status: 201, body: response.to_json, headers: { 'Content-Type' => 'application/json'})

Yii2: GridView: add button or link to controller action

I have a controller with an action method:
namespace frontend\controllers;
class EmployeeController extends FrontController
{
/**
* Deletes an existing Employee status.
* #param integer $id
* #return mixed
*/
public function actionDeleteStatus($status_id)
{
error_log("actionDeleteStatus " . $status_id);
return $this->redirect(['update']);
}
}
In update form, I have a detail GridView, in which I want to add a "delete" link with an URL for this method as a GET request.
I try to get the URL with this: Url::toRoute(['employee/deleteStatus','status_id' => $model->status_id]) which gives me an url like /employee/deleteStatus?status_id=4 and throws a 404, here is the detailed code:
<div class="col-xs-12">
<?php
echo Html::label(Yii::t('app', 'Employee status history'));
echo GridView::widget([
'summary' => '',
'options' => [
'id' => 'status-history',
],
'emptyText' => '',
'export' => false,
'dataProvider' => $statusHistory,
'columns' => [
[...],
[
'class' => 'kartik\grid\DataColumn',
'attribute' => 'status_id',
'headerOptions' => [ 'class' => 'kv-grid-hide' ],
'contentOptions' => [ 'class' => 'kv-grid-hide' ]
],
[
'class' => 'yii\grid\ActionColumn',
'urlCreator' => function($action, $model, $key, $index) {
return Url::toRoute(['employee/deleteStatus','status_id' => $model->status_id]);
},
'template' => '{delete}',
'contentOptions' => ['class' => 'column-action'],
'buttons' => [
'delete' => function ($url, $model, $key) {
if (Yii::$app->user->can('globalDAF')) {
$options = [
'title' => Yii::t('app', 'Delete'),
'aria-label' => Yii::t('app', 'Delete'),
'data-confirm' => Yii::t('app', 'Sure to delete status?'),
'data-method' => 'post',
'data-pjax' => '0',
'class' => 'btn-llyc'
];
return Html::a('<span class="glyphicon glyphicon-remove"></span>', $url, $options);
} else {
return;
}
}
]
]
],
'hover' => true,
'responsiveWrap' => false
]);
?>
</div>
Is the url generation wrong? Why am I getting a 404?
Thanks.
For example, index becomes actionIndex, and hello-world becomes
actionHelloWorld.
Note: The names of the action methods are case-sensitive. If you have
a method named ActionIndex, it will not be considered as an action
method, and as a result, the request for the index action will result
in an exception. Also note that action methods must be public. A
private or protected method does NOT define an inline action.
Link
Url::toRoute(['employee/delete-status','status_id' => $model->status_id])
Or in config file:
'urlManager' => [
'class' => 'yii\web\UrlManager',
#code ..
'rules' => [
'employee/deleteStatus' => 'employee/delete-status',
],
],

How to deserialize parameters with relationships using ActiveModelSerializers?

I used to code below to deserialize the JSON API data send from client,
def action_record_params
ActiveModelSerializers::Deserialization.jsonapi_parse!(params)
end
When I pass the following data from the client, the deserializer cannot see relationships attributes.
Client send parameter
params = {"data": {"type": "action_record", "attributes": {"value": ""}}, "relationships": {"card": {"data": {"type": "card", "id": "#{card.id}"}}}}
Server deserialized data
{:value=>""}
How to deserialize parameters with relationships using ActiveModelSerializers?
Base on AMS documentation Deserialization section, which can be found below
https://github.com/rails-api/active_model_serializers/blob/master/docs/general/deserialization.md
The relationships can be extracted by via the option only: [:relatedModelName]. only is act as a whitelist in this case.
Sample Data
document = {
'data' => {
'id' => 1,
'type' => 'post',
'attributes' => {
'title' => 'Title 1',
'date' => '2015-12-20'
},
'relationships' => {
'author' => {
'data' => {
'type' => 'user',
'id' => '2'
}
},
'second_author' => {
'data' => nil
},
'comments' => {
'data' => [{
'type' => 'comment',
'id' => '3'
},{
'type' => 'comment',
'id' => '4'
}]
}
}
}
}
AMS deserialization with options
ActiveModelSerializers::Deserialization
.jsonapi_parse(document, only: [:title, :date, :author],
keys: { date: :published_at },
polymorphic: [:author])
Output hash
# {
# title: 'Title 1',
# published_at: '2015-12-20',
# author_id: '2',
# author_type: 'user'
# }

Ruby on rails array formatting - removing//selecting values from inner array inside a hash array

I have long list of values in the inner_value field from which I want only some values
I have array in this format:
hash_array = [
{
"array_value" => 1,
"inner_value" => [
{"iwantthis" => "forFirst"},
{"iwantthis2" => "forFirst2"},
{"Idontwantthis" => "some value"},
{"iwantthis3" => "forFirst3"},
{"Idontwantthis2" => "some value"},
{"Idontwantthis3" => "some value"},
{"Idontwantthis4" => "some value"},
{"Idontwantthis5" => "some value"},
{"Idontwantthis6" => "some value"},
]
},
{
"array_value" => 2,
"inner_value" => [
{"iwantthis" => "forSecond"},
{"Idontwantthis" => "some value"},
{"iwantthis3" => "forSecond3"},
{"iwantthis2" => "forSecond2"},
{"Idontwantthis2" => "some value"},
{"Idontwantthis3" => "some value"},
{"Idontwantthis4" => "some value"},
{"Idontwantthis5" => "some value"},
{"Idontwantthis6" => "some value"},
]
},
]
Desired Output:
[
{
"array_value" => 1,
"inner_value" => [
{"iwantthis" => "forFirst"},
{"iwantthis2" => "forFirst2"},
{"iwantthis3" => "forFirst3"}
]
},
{
"array_value" => 2,
"inner_value" => [
{"iwantthis" => "forSecond"},
{"iwantthis2" => "forSecond2"},
{"iwantthis3" => "forSecond3"}
]
},
]
I have tried using running loop in this but its too much costly.
So I tried something like this:
hash_array.select { |x| x["inner_value"].select {|y| !y["iwantthis"].nil? } }
but this ain't working either..
Note:Order/Sort does not matter
Your aim is not to select, you have to modify the input:
hash_array.map { |hash| hash['inner_value'] = hash['inner_value'].first }
#=> [
# {
# "array_value"=>1,
# "inner_value"=> {
# "iwantthis"=>"forFirst"
# }
# },
# {
# "array_value"=>2,
# "inner_value"=> {
# "iwantthis"=>"forSecond"
# }
# }
# ]
Here you'd basically change the value of whole hash['inner_value'] to what you want.
To do this with known key:
hash_array.map do |hash|
hash['inner_value'] = hash['inner_value'].find { |hash| hash['iwantthis'] }
end # `iwantthis` is the key, that can change
For multiple keys:
keys = %w(iwantthis Idontwantthis)
hash_array.map do |hash|
hash['inner_value'] = keys.flat_map do |key|
hash['inner_value'].select {|hash| hash if hash[key] }
end
end
#=> [{"array_value"=>1, "inner_value"=>[{"iwantthis"=>"forFirst"}, {"Idontwantthis"=>"some value"}]}, {"array_value"=>2, "inner_value"=>[{"iwantthis"=>"forSecond"}, {"Idontwantthis"=>"some value"}]}]
you can use map
hash_array.map{|k| {"array_value" => k['array_value'], 'inner_value' => k['inner_value'][0]} }
#=> [{"array_value"=>1, "inner_value"=>{"iwantthis"=>"forFirst"}}, {"array_value"=>2, "inner_value"=>{"iwantthis"=>"forSecond"}}]

What is an elegant way of modifying hashes inside an array within a nested hash in Ruby

I would like to transform this
def some_process(k,v)
return "#{v}_#{k}"
end
a_hash = {
"i_love_hashes" => {
"thing" => 20,
"other_thing" => "0",
"yet_another_thing" => "i disagree",
"_peculiar_thing" => [
{"count" => 30,
"name" => "freddie"},
{"count" => 15,
"name" => "johhno"},
{"count" => 12,
"name" => "mohammed"},
]
},
"as_do_i" => {
"thing" => 10,
"other_thing" => "2",
"yet_another_thing" => "i strongly agree",
"_peculiar_thing" => [
{"count" => 10,
"name" => "frodo"},
{"count" => 4,
"name" => "bilbo"},
{"count" => 2,
"name" => "elizabeth"},
]
}
}
into this
{
"i_love_hashes"=>{
"thing"=>20,
"other_thing"=>"0",
"yet_another_thing"=>"i disagree",
"_peculiar_thing"=> [
{"count"=>30, "name"=>"freddie", :sinister_name=>"freddie_i_love_hashes"},
{"count"=>15, "name"=>"johhno", :sinister_name=>"johhno_i_love_hashes"},
{"count"=>12, "name"=>"mohammed", :sinister_name=>"mohammed_i_love_hashes"}
]},
"as_do_i"=>{
"thing"=>10,
"other_thing"=>"2",
"yet_another_thing"=>"i strongly agree",
"_peculiar_thing"=>[
{"count"=>10, "name"=>"frodo", :sinister_name=>"frodo_as_do_i"},
{"count"=>4, "name"=>"bilbo", :sinister_name=>"bilbo_as_do_i"},
{"count"=>2, "name"=>"elizabeth", :sinister_name=>"elizabeth_as_do_i"}
]
}
}
this is the code I am currently using to achieve this
a_hash.each_with_object({}) do |(k,v),o|
o.merge!({k =>
v.each_with_object({}) do |(a,b),g|
g.merge!({ a =>
(b.is_a?(Array) ? b.collect {|x| x.merge({sinister_name: (some_process k, x["name"])})} : b)
})
end
})
end
Ignoring the specific details of what is being returned by "some_process" (what is important is that it depends on the outer most key and the inner name values, in this example), are there any alternatives that would be considered more elegant?
Why not do a recursive function?
def add_siniter(hash)
hash[:siniter_name] = "#{hash['name']}_i_love_hashes"
hash
end
def format_hash(item)
case item
when Hash then item.keys.each{|key| format_hash(item[key])}
when Array then item.map!{|h| add_siniter(h)}
end
end
format_hash(a_hash)

Resources