remove id from select().distinct - ruby-on-rails

I have this is AR on my controller
areas = WaterQuality.select(:area_id, :area).distinct
The problem is, the result always has id together with area_id and area. I have to do this bit to remove id from the result.
areas = WaterQuality.select(:area_id, :area).distinct
new_areas = []
areas.each do |area|
new_area = {
:area_id => area.area_id,
:area => area.area
}
new_areas << new_area
end
respond_with(new_areas)
I set the respond as respond_to :xml, :json
How can I have the result with only 2 attributes that I have defined without any other attributes?

You can try this-
results = WaterQuality.select(:area_id, :area).distinct.as_json
results_without_id = results.each {|h| h.delete("id")}
This would return you an array of hashes with key/value pair.
Hope it helps!

Maybe a bit over the top for your but I've started using ActiveModel::Serializer a while ago and I'm very happy with it.
class WaterQualityDistinctSerializer < ActiveModel::Serializer
attributes :area_id, :area
end

You could try:
WaterQuality.all.map { |record| record.slice(*%w(area_id area)).symbolize_keys }
Or even:
WaterQuality.all.map { |record| record.slice(*%w(area_id area)) }
This will return a slightly different hash in console, but the same json or xml.

Related

How can I iterate through a model then iterate again in my view?

I want to pull data for each of my users. I grab their person_id from my user table, then use each person's ID to figure out how many days each person has available, and show that in my view.
I'm not sure if I am doing this correctly because I am iterating in my controller then again in my view.
def how_many_days_users_have
#my_group = User.all.pluck(:person_id)
#my_group.each do |v|
#indirect_id_v = Empaccrl.where("person_id = ? and is_active = ?", '#{v]', 'Y').pluck(:a_code).first
#v_range = Empaccrl.where("person_id = ? and is_active = ?", '#{v]', 'Y').pluck(:ac).first
#v_range_taken = Empaccrl.where("person_id = ? and is_active = ?", '#{v]', 'Y').pluck(:taken).first
#total_v_hours = #v_range.to_d - #v_range_taken.to_d
#total_v_days = #total_v_hours / 8
end
Then in my view I use this to show me this data:
%tr.trace-table
-#indirect_id_v.each do |idd|
%tr.trace-table
%td.trace-table{:style => 'border: solid black;'}= idd
-#total_v_days.each do |days|
%tr.trace-table
%td.trace-table{:style => 'border: solid black;'}= days
Okay, first things first, move some of that junk to your model, like so:
class Empaccrl < ActiveRecord::Base
def self.all_people
where(person_id: User.all.pluck(:person_id))
end
def self.active_people
all_people.where(is_active: 'Y')
end
def self.active_vacation_data
active_people.select(:person_id, :ac, :taken)
end
def total_v_hours
ac.to_d - taken.to_d
end
def total_v_days
total_v_hours / 8
end
end
Then you can use:
peoples_vacation_information = Empaccrl.active_vacation_data.all
peoples_vacation_information.map do |person|
p "person #{person.person_id} has #{person.total_v_days} vacation days"
end
Honestly, you don't even need all that, but I'm not sure why you are doing what you are doing, so I figured better be safe and add stuff. Whatever you don't need, just ignore.

Create Hash iterating an array of objects

I have an object that has attributes name and data, among others. I want to create a hash that uses the name as the key and the data (which is an array) as the value. I can't figure out how to reduce the code below using map. Is it possible?
def fc_hash
fcs = Hash.new
self.forecasts.each do |fc|
fcs[fc.name] = fc.data
end
fcs
end
Use Hash[]:
Forecast = Struct.new(:name, :data)
forecasts = [Forecast.new('bob', 1), Forecast.new('mary', 2)]
Hash[forecasts.map{|forecast| [forecast.name, forecast.data]}]
# => {"mary"=>2, "bob"=>1}
def fc_hash
forecasts.each_with_object({}) do |forecast, hash|
hash[forecast.name] = forecast.data
end
end
I always use inject or reduce for this:
self.forecasts.reduce({}) do |h,e|
h.merge(e.name => e.data)
end
Hash[*self.forecases.map{ [fc.name, fc.data]}.flatten]
With Ruby 2.1 and onward, you could also use Array#to_h
self.forecasts.to_h { |forecast| [forecast.name, forecast.data] }

Parsing an array of objects by attributes in rails 3.2

Is it possible to parse an array of objects to select them by attribute? I have a situation where I need to display all objects of a model grouped by an attribute on the index page. What I had been doing in my controller is this...
#xx_controller.rb
#group1 = City.where(:population => 'big')
#group2 = City.where(:population => 'medium')
#group3 = City.where(:population => 'small')
But I'd prefer to do something like this in the controller...
#cities = City.all
And in my view something along the lines of a query, rather than prepackaged instance variables -
#cities.where....
Any thoughts?
If you don't mind loading everything at once from the database, you can do:
#cities = City.all.group_by(&:population)
Which returns a hash whose keys are the possible values for the population attribute.
Then, on your view, you can access the cities on each 'group' by doing #cities['small'], #cities['medium'] and so on.
Do you mean something like this?
#cities = City.all
small_cities = #cities.select { |city| city.population == 'small' }
medium_cities = #cities.select { |city| city.population == 'medium' }
big_cities = #cities.select { | city| city.population == 'big' }

Using a method while looping through an array in ruby

I am using ruby-aaws to return Amazon Products and I want to enter them into my DB. I have created a model Amazonproduct and I have created a method get_amazon_data to return an array with all the product information. When i define the specific element in the array ( e.g. to_a[0] ) and then use ruby-aaws item_attributes method, it returns the name I am searching for and saves it to my DB. I am trying to iterate through the array and still have the item_attributes method work. When i don't define the element, i get this error: undefined method `item_attributes' for #Array:0x7f012cae2d68
Here is the code in my controller.
def create
#arr = Amazonproduct.get_amazon_data( :r ).to_a
#arr.each { |name|
#amazonproduct = Amazonproduct.new(params[:amazonproducts])
#amazonproduct.name = #arr.item_attributes.title.to_s
}
EDIT: Code in my model to see if that helps:
class Amazonproduct < ActiveRecord::Base
def self.get_amazon_data(r)
resp = Amazon::AWS.item_search('GourmetFood', { 'Keywords' => 'Coffee Maker' })
items = resp.item_search_response.items.item
end
end
Thanks for any help/advice.
I'm not familiar with the Amazon API, but I do observe that #arr is an array. Arrays do not usually have methods like item_attributes, so you probably lost track of which object was which somewhere in the coding process. It happens ;)
Try moving that .item_attributes call onto the object that supports that method. Maybe amazonproduct.get_amazon_data(:r), before its being turned into an array with to_a, has that method?
It's not quite clear to me what your classes are doing but to use #each, you can do something like
hash = {}
[['name', 'Macbook'], ['price', 1000]].each do |sub_array|
hash[sub_array[0]] = sub_array[1]
end
which gives you a hash like
{ 'name' => 'Macbook', 'price' => 1000 }
This hash may be easier to work with
#product = Product.new
#product.name = hash[:name]
....
EDIT
Try
def create
#arr = Amazonproduct.get_amazon_data( :r ).to_a
#arr.each do |aws_object|
#amazonproduct = Amazonproduct.new(params[:amazonproducts])
#amazonproduct.name = aws_object.item_attributes.title.to_s
end
end

Ruby on Rails: Array to Hash with (key, array of values)

Lets say I have an Array of content_categories (content_categories = user.content_categories)
I now want to add every element belonging to a certain categorie to content_categories with the category as a key and the the content-item IDs as elements of a set
In PHP something like this is possible:
foreach ($content_categories as $key => $category) {
$contentsByCategoryIDArray = Category.getContents($category[id])
$content_categories[$key][$contentsByCategoryIDArray]
}
Is there an easy way in rails to do this?
Greets,
Nico
Your question isn't really a Rails question, it's a general Ruby programming question.
Your description isn't very clear, but from what I understand, you want to group IDs for common categories using a Hash. There are various other ways of doing this, but this is easy to understand::
ary = [
'cat1', {:id => 1},
'cat2', {:id => 2},
'cat1', {:id => 3}
]
hsh = {}
ary.each_slice(2) { |a|
key,category = a
hsh[key] ? hsh[key] << category[:id] : hsh[key] = [category[:id]]
}
hsh # => {"cat1"=>[1, 3], "cat2"=>[2]}
I'm using a simple Array with a category, followed by a simple hash representing some object instance, because it makes it easy to visualize. If you have a more complex object, replace the hash entries with those objects, and tweak how you access the ID in the ternary (?:) line.
Using Enumerable.inject():
hsh = ary.each_slice(2).inject({}) { |h,a|
key,category = a
h[key] ? h[key] << category[:id] : h[key] = [category[:id]]
h
}
hsh # => {"cat1"=>[1, 3], "cat2"=>[2]}
Enumerable.group_by() could probably shrink it even more, but my brain is fading.
I'd use Enumerable#inject
content_categories = content_categories_array.inject({}){ |memo, category| memo[category] = Category.get_contents(category); memo }
Hash[content_categories.map{|cat|
[cat, Category.get_contents(cat)]
}]
Not really the right answer, because you want IDs in your array, but I post it anyway, because it's nice and short, and you might actually get away with it:
content_categories.group_by(&:category)
content_categories.each do |k,v|
content_categories[k] = Category.getContents(v)
end
I suppose it's works
If i understand correctly, content_categories is an array of categories, which needs to be turned into a hash of categories, and their elements.
content_categories_array = content_categories
content_categories_hash = {}
content_categories_array.each do |category|
content_categories_hash[category] = Category.get_contents(category)
end
content_categories = content_categories_hash
That is the long version, which you can also write like
content_categories = {}.tap do |hash|
content_categories.each { |category| hash[category] = Category.get_contents(category) }
end
For this solution, content_categories must be a hash, not an array as you describe. Otherwise not sure where you're getting the key.
contents_by_categories = Hash[*content_categories.map{|k, v| [k, Category.getContents(v.id)]}]

Resources