When I run a simple query of Item.where(:id => id) in my ItemHelper class and it returns
[
{
JDPA: null,
_id: "530e45f43f72fb3dee000001",
category: null,
created_at: "2014-02-26T19:52:20Z",
creator: "5170547c791e4b1a16000001",
detail: "Detail",
event_id: "52d958e73f72fb1e1f000001",
image_content_type: null,
image_file_name: null,
image_file_size: null,
image_updated_at: null,
question: null,
section: null,
title: "Title",
updated_at: "2014-02-26T19:52:21Z",
veh1: 5,
veh10: null,
veh2: 5,
veh3: 6,
veh4: null,
veh5: null,
veh6: null,
veh7: null,
veh8: null,
veh9: null,
version: null
}
]
I want to get an array of :veh1..:veh10 as [5, 5, 6, null, ...]. Having a lot of trouble doing this...
I thought of using JBuilder in my helper, but now I've blown things up...
How can I do something as simple as using .only(:veh1..:veh10 and remove the nulls...then I could probably make an array.
Thoughts, comments, am I being dumb?? Should this be easy? I'm a beginner here. :)
My Answer
This feels really sloppy. Is there a better way to do this?? More elegant??
def item_ppu(id)
item = Item.where(:_id => id)
newitem = item.map{|i| [i.veh1, i.veh2, i.veh3, i.veh4, i.veh5, i.veh6, i.veh7, i.veh8, i.veh9, i.veh10]}
h = Hash.new(0)
newitem[0].each { | v | h.store(v, h[v]+1) }
f = 2*h[2]#lots more math
return f
end
If this is a Mongoid model, and you're only looking for a single object, you can just use find and then map to the attributes you need:
object = Item.find(id)
You can use values_at to retrieve specific values from the object's attributes hash (in Mongoid, the hash's keys are strings):
keys = (1..10).map {|n| "veh#{n}" } #=> ["veh1", "veh2" ...
values = object.attributes.values_at(*keys)
values.compact # removes the nil values from the array
Taken all together:
object.attributes.values_at(*(1..10).map {|n| "veh#{n}" }).compact
EDIT
In the interest of writing clean, understandable code, here's how I would actually write this in a production app:
class Item
# whatever goes here
def ppu
veh_values.inject {|result, value| # ... some calculation }
end
private
def veh_values
attributes.values_at(*veh_keys).compact
end
def veh_keys
(1..10).map {|n| "veh#{n}" }
end
end
This is now an instance method on the Item class, so to call it, your syntax would be:
item.ppu
Related
I spend a time to find a solution how to convert an array came from the HTTP request to something can rails read.
Example of the request:
"line_item":[{
"item_id": 1,
"item_name": "Burger",
"item_price": 15.00,
"item_quantity": 2
},
{
"item_id": 2,
"item_name": "Soda",
"item_price": 3.00,
"item_quantity": 1
}]
and then I loop the array like so:
#not_available_items = []
#line_item = #order.line_item
#line_item.each do |i|
#item = Item.find(i.item_id)
if #item.is_active == false
#not_available_items.push(
{
item_id: i.item_id,
item_name: i.item_name
}
)
end
end
The error message:
"exception": "#<NoMethodError: undefined method `item_id' for {\"item_id\"=> 1, \"item_name\"=>\"Burger\", \"item_price\"=> 15.0, \"item_quantity\"=> 2}:Hash>"
Hope I explained the issue clear.
Thanks
The variable i is an object of type Hash (and not of type Item). In Ruby, unlike Javascript, you cannot access the key of a Hash object using the . operator.
You can use the [] operator to fetch the value for a key in a Hash.
In your code, you are using i.item_id, but i does not have an attribute or method called item_id; it has a key item_id. Since, i is a Hash, you can access the fields by calling and i["item_id"]
#not_available_items = []
#line_item = #order.line_item
#line_item.each do |i|
#item = Item.find(i["item_id"])
if #item.is_active == false
#not_available_items.push(
{
item_id: i.item_id,
item_name: i.item_name
}
)
end
end
I am currently working on statistics, so I get an array containing all my data. The problem is that this data contains enums and that I would like to translate them without overwriting the rest.
Here is a given example that contains my array (it contains several hundred) :
#<Infosheet id: 90, date: "2018-04-22 00:00:00", number: 7, way: "home", gender: "man", age: "age1", district: "", intercommunal: "", appointment: true, othertype: "", otherorientation: "", user_id: 3, created_at: "2018-04-22 17:51:16", updated_at: "2018-04-22 17:51:16", typerequest_id: 168, orientation_id: 188, info_number: nil, city_id: 105>
I would like to translate the enums of "way" or "gender" or "age", while retaining the rest of the data, because currently, if I make a translation in the console, it crushes everything else.
Do you know how to make that ?
Thanks !
You can just loop over all the enum attributes and get their values. Later you can merge and pass a new hash containing converted values
ENUM_COLUMNS = %i[way gender age] # Equivalent to [:way, :gender, :age]
def convert_enums
overrided_attributes = {}
ENUM_COLUMNS.each { |column| overrided_attributes[column.to_s] = self[column] }
attributes.merge(overrided_attributes)
end
NOTE:
While infosheet.gender returns you male or female
infosheet[:gender] will return you the respective integer value 0 or 1
You can test this if you use translate enum gem :
a = Infosheet.group(:gender).count
{“male”=>30, “female”=>6532}
Create a hash
r = Hash.new
And populate this with :
a.each {|s| puts r[Infosheet.translated_gender(s[0])]=s[1] }
r
result :
{“homme”=>30, “femme”=>6532}
I have 2 apples:
{
id: 1,
rotten: true,
branch_on_tree: nil,
type: "red delicious"
},
{
id: 2,
rotten: nil,
branch_on_tree: 5,
type: "red delicious"
}
They are duplicate apples for red delicious. How do I merge the records together and then delete the one with missing data? Is there a convenient way to do this?
Note: There might be like 10 duplicates. I don't want any null values in my final record. Non-null values take precedence.
Not very convinient way but it will work
assuming apples is an array:
[
{
id: 1,
rotten: true,
branch_on_tree: nil,
type: "red delicious"
},
# ...
]
that can come from:
apples = Apple.where(type: "red delicious")
apples_attrs = apples.map(&:attributes)
Then,
apple_attrs = apples_attrs.reduce do |apple, next_apple|
apple.merge(next_apple) do |_, old_value, new_value|
old_value || new_value
end
end
apples.destroy_all
Apple.create(apple_attrs)
You might want to check this guide https://apidock.com/ruby/Hash/merge
Assuming type always has some value, you can use DISTINCT with where clause. The below should work
Apple.where('rotten IS NOT NULL AND branch_on_tree IS NOT NULL').select('DISTINCT ON (type) rotten,branch_on_tree,type').take
I am returning a response of user fields in JSON. I am creating JSON as below.
def user_response(users)
users_array = []
users.each do |user|
uhash = {}
uhash[:id] = user.id,
uhash[:nickname] = user.nickname,
uhash[:online_sharing] = user.online_sharing,
uhash[:offline_export] = user.offline_export,
uhash[:created_at] = user.created_at,
uhash[:app_opens_count] = user.app_opens_count,
uhash[:last_activity] = user.last_activity,
uhash[:activity_goal] = user.activity_goal,
uhash[:last_activity] = user.last_activity,
uhash[:region] = user.region
users_array << uhash
end
users_array
end
But the response is pretty weird. The :id key in hash has an array of all the fields don't know why.
{
"nickname": "adidas",
"online_sharing": null,
"offline_export": null,
"created_at": "2016-08-26T09:03:54.000Z",
"app_opens_count": 29,
"last_activity": "2016-08-26T09:13:01.000Z",
"activity_goal": 3,
"region": "US",
"id": [
9635,
"adidas",
null,
null,
"2016-08-26T09:03:54.000Z",
29,
"2016-08-26T09:13:01.000Z",
3,
"2016-08-26T09:13:01.000Z",
"US"
]
}
That's due to your , at the end of each line
The problem consists of two things:
An assignment evaluates as the value being assigned:
puts (foo = 42) # => prints 42
Multiple values, separated with comma on the right hand side of an assignment form an array:
bar = 1, 2, 3
bar # => [1, 2, 3]
The new lines don't change that, so you basically do something like this:
sonne = (foo = :eins), (bar = :zwei), (baz = :drei), (qux = :vier)
sonne # => [:eins, :zwei, :drei, :vier]
The fix is indeed to remove the commas.
You have comma , at the end of each line
uhash[:id] = user.id,
Also, You may change the above code to:
def user_response(users)
users.map do |user|
user.attributes.slice(:id, :nickname, :online_sharing, :offline_export, :created_at, :app_opens_count, :last_activity, :activity_goal, :last_activity, :region)
end
end
I am doing my Ruby on Rails project now. PostgreSQL is used as database.I have a table called pets, where stores all pets information(name, gender, age, etc.), which are shown as follows.
{Pet id: 1, name: "Jean", gender: "Female", pet_type: "Cat", age: "0", body_weight: 1, breed: "Abyssinian", created_at: "2015-04-26 23:50:01", updated_at: "2015-04-26 23:50:01"}
{Pet id: 2, ...}
...
{Pet id: 10, ...}
Now I am going to check whether there is a Abyssinian breed cat in table pets. If there is, return the Pet id, otherwise return "no such cat found".
Is there anyone know how to do this? Thanks in advance.
To find the first pet where breed == "Abyssinian":
pet = Pet.find_by(breed: "Abyssinian", pet_type: "Cat")
So, to combine that with your required logic:
pet = Pet.find_by(breed: "Abyssinian", pet_type: "Cat")
output = pet ? pet : "no such cat found"
You could simply this even further to:
output = Pet.find_by(breed: "Abyssinian", pet_type: "Cat") || "no such cat found"
Is "breed" a field in the pets table? If so, you could do something like:
if Pet.exists?( breed: "Abyssinian" )
x = Pet.where( breed: "Abyssinian" )
else
x = "No such cat found"
end
The danger in this is that there could be multiple Pets returned. If you want to find one and only one, you could do
if Pet.where( breed: "Abyssinian" ).count == 1
instead.
REVISION
#infused's answer is more succinct, I would encourage an implementation similar to his, assuming a breed column exists.