Rails - exchange attributes values - ruby-on-rails

I have a table called decoders_contracts with this attributes:
id | decoder_id | contract_id
1 3 31
2 3 31
3 1 31
4 1 31
...
I need to exchange the decoder_id this way:
id | decoder_id | contract_id
1 1 31
2 1 31
3 3 31
4 3 31
...
I tried something like this, but it doesn't works:
contract_id = params[:contract_id] # 31
dc1 = params[:dc1] # 1
dc2 = params[:dc2] # 3
DecodersContract.where(contract_id: contract_id, decoder_id: dc1).update_all(decoder_id: dc2)
DecodersContract.where(contract_id: contract_id, decoder_id: dc2).update_all(decoder_id: dc1)
All decoders_id became 1

Yes, you can't do it that way. After the first where all the DecodersContract have the same value.
Better would be to have an intermediate value, preferably one that can't occur naturally.
DecodersContract.where(contract_id: contract_id, decoder_id: dc1).update_all(decoder_id: 999)
DecodersContract.where(contract_id: contract_id, decoder_id: dc2).update_all(decoder_id: dc1)
DecodersContract.where(contract_id: contract_id, decoder_id: 999).update_all(decoder_id: dc2)

Related

ActiveRecord::Fixture::FixtureError: table has no columns named "false"

I am getting the error: ActiveRecord::Fixture::FixtureError: table "creatures" has no columns named "false". I have no column named false in this model.
What is going on?
Here is my fixture:
3 one:
4 name: MyString
5 no: 1
6 type1: 1
7 type2: 1
8 total: 1
9 hp: 1
10 attack: 1
11 defense: 1
12 special_attack: 1
13 special_defense: 1
14 speed: 1
15 generation: 1
16 legendary: false
17
Putting the no in single quotes solved the problem.
If I put a debugger call just before the error is raised:
[475, 484] in /usr/local/bundle/gems/activerecord-7.0.4.2/lib/active_record/connection_adapters/abstract/database_statements.rb
475: fixture = fixture.stringify_keys
476:
477: unknown_columns = fixture.keys - columns.keys
478: if unknown_columns.any?
479: debugger
=> 480: raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
481: end
482:
483: columns.map do |name, column|
484: if fixture.key?(name)
(byebug) fixtures
It looks like the no got interpreted as a false:
[{"name"=>"MyString", false=>1, "type1"=>1, "type2"=>1, "total"=>1, "hp"=>1, "attack"=>1, "defense"=>1, "special_attack"=>1, "special_defense"=>1, "speed"=>1, "genneration"=>1, "legendary"=>false, "created_at"=>2023-02-05 18:53:31.63881045 UTC, "updated_at"=>2023-02-05 18:53:31.63881045 UTC, "id"=>980190962}, {"name"=>"MyString", false=>2, "type1"=>1, "type2"=>1, "total"=>1, "hp"=>1, "attack"=>1, "defense"=>1, "special_attack"=>1, "special_defense"=>1, "speed"=>1, "genneration"=>1, "legendary"=>false, "created_at"=>2023-02-05 18:53:31.63881045 UTC, "updated_at"=>2023-02-05 18:53:31.63881045 UTC, "id"=>298486374}]
Putting the no in single quotes solved the problem:
3 one:
4 name: MyString
5 'no': 1
6 type1: 1
7 type2: 1
8 total: 1
9 hp: 1
10 attack: 1
11 defense: 1
12 special_attack: 1
13 special_defense: 1
14 speed: 1
15 generation: 1
16 legendary: false
17
18 two:
19 name: MyString
20 'no': 2
21 type1: 1
22 type2: 1
23 total: 1
24 hp: 1
25 attack: 1
26 defense: 1
27 special_attack: 1
28 special_defense: 1
29 speed: 1
30 generation: 1
31 legendary: false

Inner join return duplicated record

My table:
Report_Period
Entity
Tag
Users Count
Report_Period_M-1
Report_Period_Q-1
...
2017-06-30
entity 1
X
471
2017-05-31
2017-03-31
...
2020-12-31
entity 2
A
135
2020-11-30
2020-09-30
...
2020-11-30
entity 3
X
402
2020-10-31
2020-08-31
...
What I want:
Report_Period
Entity
Tag
Users Count
Users_Count_M-1
Users_Count_Q-1
...
2017-06-30
entity 1
X
471
450
438
...
2020-12-31
entity 2
A
135
122
118
...
2020-11-30
entity 3
X
402
380
380
...
I have have tried this code but it duplicate records! How can I avoid it?
SELECT M."Entity",M."Tag",M."Report_Period",M."Users Count",
M."Report_Period_M-1",M1."Users Count" AS "Users Count M1",
FROM "DB"."SCHEMA"."PERIOD" M, "DB"."SCHEMA"."PERIOD" M1
WHERE M."Report_Period_M-1"= M1."Report_Period"
Your join clause should include the entity column and tag (I suspect)
SELECT M."Entity",
M."Tag",
M."Report_Period",
M."Users Count",
M."Report_Period_M-1",
M1."Users Count" AS "Users Count M1",
FROM "DB"."SCHEMA"."PERIOD" M,
"DB"."SCHEMA"."PERIOD" M1
WHERE M."Report_Period_M-1"= M1."Report_Period"
AND M."Entity" = M1."Entity"
AND M."Tag" = M1."Tag"

Fixing joining two datasets with same variables

I want to join two datasets.
Datasets had same columns/ variables.
Dataset 1 (n11)
caseid v000 v005 age v021 v022 v023 v024 resi region v102 education pregnant v445 v501 v717 wealth stra occupation
1 101 15 2 NP6 342191 5 101 10 1 1 2 1 2 1 0 2190 1 4 4 NPIR61FL$ssubreg=1, NPIR61FL$v025=2 2
2 101 19 2 NP6 342191 7 101 10 1 1 2 1 2 0 0 2300 1 4 3 NPIR61FL$ssubreg=1, NPIR61FL$v025=2 2
3 101 19 4 NP6 342191 2 101 10 1 1 2 1 2 1 0 2139 1 4 3 NPIR61FL$ssubreg=1, NPIR61FL$v025=2 2
4 101 21 4 NP6 342191 5 101 10 1 1 2 1 2 0 0 1855 1 4 2 NPIR61FL$ssubreg=1, NPIR61FL$v025=2 2
5 101 45 3 NP6 342191 5 101 10 1 1 2 1 2 0 0 2133 3 4 3 NPIR61FL$ssubreg=1, NPIR61FL$v025=2 2
6 101 47 2 NP6 342191 1 101 10 1 1 2 1 2 2 0 2022 1 4 4 NPIR61FL$ssubreg=1, NPIR61FL$v025=2 2
Dataset 2 (n16)
caseid v000 v005 age v021 v022 v023 v024 resi region v102 education pregnant v445 v501 v717 wealth stra occupation
1 101 2 2 NP5 295061 6 101 1 1 1 2 1 2 0 0 2534 1 4 2 NPIR51FL$v024=1, NPIR51FL$v025=2 2
2 101 2 3 NP5 295061 1 101 1 1 1 2 1 2 2 0 2061 0 4 2 NPIR51FL$v024=1, NPIR51FL$v025=2 2
3 101 3 3 NP5 295061 1 101 1 1 1 2 1 2 2 0 2157 1 4 1 NPIR51FL$v024=1, NPIR51FL$v025=2 2
4 101 4 1 NP5 295061 4 101 1 1 1 2 1 2 0 0 2370 1 4 1 NPIR51FL$v024=1, NPIR51FL$v025=2 2
5 101 6 6 NP5 295061 2 101 1 1 1 2 1 2 3 0 2254 0 4 2 NPIR51FL$v024=1, NPIR51FL$v025=2 2
6 101 7 2 NP5 295061 2 101 1 1 1 2 1 2 2 0 2364 0 4 1 NPIR51FL$v024=1, NPIR51FL$v025=2 2
I used rbind function.
code was d2 <-rbind(n11, n16)
I found the following error. How can I fix this?
Error: Can't convert from <labelled<double>> to <labelled<double>> due to loss of precision.
* Locations: 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5...
Values are labelled in `` but not in ``.
Run `rlang::last_error()` to see where the error occurred.
I have found the solution now.
We can use full_join function of dplyr package to solve this.
d2<- full_join(n11, n16)

Extract text from wrk output

I'm running a load test with wrk2 as a job on Jenkins. I'd like to send the results of the load test to Graylog but I only want to store the Requests/Sec and average latency.
Here's what the output looks like:
Running 30s test # https://example.com
1 threads and 100 connections
Thread calibration: mean lat.: 8338.285ms, rate sampling interval: 19202ms
Thread Stats Avg Stdev Max +/- Stdev
Latency 16.20s 6.17s 29.64s 65.74%
Req/Sec 5.00 0.00 5.00 100.00%
Latency Distribution (HdrHistogram - Recorded Latency)
50.000% 15.72s
75.000% 20.81s
90.000% 24.58s
99.000% 29.13s
99.900% 29.66s
99.990% 29.66s
99.999% 29.66s
100.000% 29.66s
Detailed Percentile spectrum:
Value Percentile TotalCount 1/(1-Percentile)
4497.407 0.000000 1 1.00
7561.215 0.100000 11 1.11
11100.159 0.200000 22 1.25
12582.911 0.300000 33 1.43
14565.375 0.400000 44 1.67
15720.447 0.500000 54 2.00
16416.767 0.550000 60 2.22
17301.503 0.600000 65 2.50
18464.767 0.650000 71 2.86
19185.663 0.700000 76 3.33
20807.679 0.750000 81 4.00
21479.423 0.775000 84 4.44
22347.775 0.800000 87 5.00
22527.999 0.825000 90 5.71
23216.127 0.850000 93 6.67
23478.271 0.875000 95 8.00
23805.951 0.887500 96 8.89
24723.455 0.900000 98 10.00
25067.519 0.912500 99 11.43
25395.199 0.925000 101 13.33
26525.695 0.937500 102 16.00
26525.695 0.943750 102 17.78
26705.919 0.950000 103 20.00
28065.791 0.956250 104 22.86
28065.791 0.962500 104 26.67
28377.087 0.968750 105 32.00
28377.087 0.971875 105 35.56
28475.391 0.975000 106 40.00
28475.391 0.978125 106 45.71
28475.391 0.981250 106 53.33
29130.751 0.984375 107 64.00
29130.751 0.985938 107 71.11
29130.751 0.987500 107 80.00
29130.751 0.989062 107 91.43
29130.751 0.990625 107 106.67
29655.039 0.992188 108 128.00
29655.039 1.000000 108 inf
#[Mean = 16199.756, StdDeviation = 6170.105]
#[Max = 29638.656, Total count = 108]
#[Buckets = 27, SubBuckets = 2048]
----------------------------------------------------------
130 requests in 30.02s, 13.44MB read
Socket errors: connect 0, read 0, write 0, timeout 1192
Requests/sec: 4.33
Transfer/sec: 458.47KB
Does anyone know how I could go about extracting Requests/sec (at the bottom) and the latency average to send as JSON parameters?
The expected output would be: "latency": 16.2, "requests_per_second": 4.33
You didn't provide the expected output so your question isn't clear but is this what you want?
$ awk 'BEGIN{a["Latency"]; a["Requests/sec:"]} ($1 in a) && ($2 ~ /[0-9]/){print $1, $2}' file
Latency 16.20s
Requests/sec: 4.33
Updated based on you adding expected output to your question:
$ awk '
BEGIN { map["Latency"]="latency"; map["Requests/sec:"]="requests_per_second" }
($1 in map) && ($2 ~ /[0-9]/) { printf "%s\"%s\": %s", ofs, map[$1], $2+0; ofs=", " }
END { print "" }
' file
"latency": 16.2, "requests_per_second": 4.33

interrogate a Ruby array of hashes

I need to group people by age in Ruby. I have their date of birth, and a method which returns their age in years. So a solution like this works.
case
when (0..15).cover?(age_years)
'child'
when (16..24).cover?(age_years)
'16 to 24'
when (25..34).cover?(age_years)
'25 to 34'
when (35..44).cover?(age_years)
'35 to 44'
when (45..54).cover?(age_years)
'45 to 54'
when (55..64).cover?(age_years)
'55 to 64'
when age_years > 64
'really old'
else
'unknown'
end
However, I am trying to learn Ruby and am looking for a more elegant solution. I thought about putting the age_ranges into an array of hashes like this...
age_ranges = [{ name: 'child', min_age: 0, max_age: 15 },
{ name: '16 to 24', min_age: 16, max_age: 24 }]
but am at a loss as to how to interrogate this data to return the correct name where the age_years is within the appropriate ranges, or even a range like this
age_ranges = [{ name: 'child', age_range: '0..15' },
{ name: '16 to 24', age_range: '16..24' }]
which looks neater but I have no idea if I have written gibberish as I don't know how to extract the name when the age years matches.
Can someone point me in the right direction?
Now that you have an map of age names and ranges (note I used range, not string as a value of age_range), you want to search the age_ranges array of hashes for such, which value of age_range includes the age:
def age_ranges
[
{ name: 'child', age_range: 0..15 },
{ name: '16 to 24', age_range: 16..24 }
]
end
def find_age(age)
age_ranges.find { |hash| hash[:age_range].include?(age) }[:name]
end
find_age(12)
#=> "child"
find_age(17)
#=> "16 to 24"
Note, that [:name] will fail if find returns nil (meaning, no matches found).
To overcome it either add an infinite range as a last one in the array (I'd prefer this one, because it is simpler):
def age_ranges
[
{ name: 'child', age_range: 0..15 },
{ name: '16 to 24', age_range: 16..24 },
{ name: 'unknown', age_range: 25..Float::INFINITY }
]
end
Or handle it while fetching the age in the find_age method:
def find_age(age)
age_ranges.each_with_object('unknown') { |hash, _| break hash[:name] if hash[:age_range].include?(age) }
end
Also, make sure to handle the negative numbers passed to the method (since age_ranges do not cover negatives):
def find_age(age)
return 'Age can not be less than 0' if age.negative?
age_ranges.find { |hash| hash[:age_range].include?(age) }[:name]
end
P.S. After all these "note/make sure" I want to say that #mudasobwa's answer is the simplest way to go about it :)
Use Range#=== triple equal directly, as it is supposed to be used:
case age_years
when 0..15 then 'child'
when 16..24 then '16 to 24'
when 25..34 then '25 to 34'
when 35..44 then '35 to 44'
when 45..54 then '45 to 54'
when 55..64 then '55 to 64'
when 64..Float::INFINITY then 'really old' # or when 64.method(:<).to_proc
else 'unknown'
end
To make case to accept floats, one should use triple-dot ranges:
case age_years
when 0...16 then 'child'
when 16...25 then '16 to 24'
when 25...35 then '25 to 34'
when 35...45 then '35 to 44'
when 45...55 then '45 to 54'
when 55...64 then '55 to 64'
when 64..Float::INFINITY then 'really old' # or when 64.method(:<).to_proc
else 'unknown'
end
Here's how I'd do it, to avoid code repetition between 16 and 64 :
def age_range(age, offset=4, span=10, lowest_age=16)
i = ((age-offset-1)/span).to_i
min = [i*span+offset+1, lowest_age].max
max = (i+1)*span + offset
"#{min} to #{max}"
end
def age_description(age)
case age
when 0...16 then 'child'
when 16..64 then age_range(age)
when 64..999 then 'really old'
else 'unknown'
end
end
(0..99).each do |age|
puts "%s (%s)" % [age_description(age), age]
end
It outputs :
child (0)
child (1)
child (2)
child (3)
child (4)
child (5)
child (6)
child (7)
child (8)
child (9)
child (10)
child (11)
child (12)
child (13)
child (14)
child (15)
16 to 24 (16)
16 to 24 (17)
16 to 24 (18)
16 to 24 (19)
16 to 24 (20)
16 to 24 (21)
16 to 24 (22)
16 to 24 (23)
16 to 24 (24)
25 to 34 (25)
25 to 34 (26)
25 to 34 (27)
25 to 34 (28)
25 to 34 (29)
25 to 34 (30)
25 to 34 (31)
25 to 34 (32)
25 to 34 (33)
25 to 34 (34)
35 to 44 (35)
...
As a bonus, it also works with Floats (e.g. 15.9 and 16.0).

Resources