how to group objects in an array Ruby - ruby

I have an array of users who are managers.
However there are repeated Users.
I would like to group them so that there is only one instance of each User in the array.
What would be the best way to go about this?
#managers.sort_by{|obj| obj.id} # Just sorted the data but did not eliminate duplicats
#managers.group_by{|u|u.name} # just created a bunch of arrays for each name

Use the uniq method, which returns a new array with duplicates removed.
#managers.uniq

If by duplicate you mean the same object ID, then you can do the following:
#managers.uniq.group_by(&:name)

Filtering the array feels like fixing symptoms. Why does the array contain rubbish in the first place?
I would suggest adding a manager? method to your User model that returns true if the user is a manager. Then you could to something like
#managers = User.select &:manager?
and get an array that only contains managers.

you can also do
Manager.select('DISTINCT user_id')
to get a clean array in the first place, whith better performance.

Related

how to check for an attribute in an array in ruby-on-rails

I need to find whether a specific attribute is present or not with where statement that takes an array in ruby.
I tried like the below.
User.where(id: [1,2,3]).include?('address')
User.where(id: [1,2,3]) would return a relation (which behaves pretty much as an array, but that's another story). It means, that is consists of objects - instances of User class.
You check if this collection includes string ('address'). It is not, as you may guess by now.
If you need to map all users by address, you can use pluck:
User.where(id: [1,2,3]).pluck(:address)
You could use: User.where(id: [1,2,3]).map(&:address) which will return an array containing the addresses.
And you can use User.where(id: [1,2,3]).map(&:address).map(&:present?) if you want an array with true or false value

How to push to an array without explicit declaration?

I have an array of Rails app User objects (users) and I am gathering email entries from these objects in a new array. I am tired of doing:
emails = []
users.each {|user| emails << user.email}
Is there a way to declare and use an array in a single go in an enumerator block like that?
Use #collect method
users.collect {|user| user.email }
# in short
users.collect(&:email)
collect emails will be nice to read rather than map emails, so I will use #collect. But both the methods are synonym of each other.
There is #each_with_object method.
users.each_with_object( [] ) {|user, emails| emails << user.email}
Not really a good example, collect works much better here, since you need an array. However, if you ever happen to use a different container, not an array (maybe some custom class), this might be handy.
And I also have to note that it looks much like ActiveRecord usage, since it's about Rails. So you might find #pluck useful:
I can't provide an equal piece of code here, because I have no idea what do you have in users. But here's a similar snippet:
User.all.pluck(:email)

Add new attribute to existing hash

I am retrieving results using Mongoid, but I want to add a new attribute to each of the records returned in an instance variable using the key. How would I go about doing this?
In PHP I would do this by looping through the array and inserting it based on the key of the object. I am unable to figure out how this can be done in Ruby when I receive the message: Model ABC can't be converted into an Integer.
Update: I ended up adding a method in the model to achieve what I was trying to do.
I'll try to point you in the right direction.
If you have an array of records and what to loop through it, use Array#each: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-each
You can write attributes easily: http://rdoc.info/github/mongoid/mongoid/Mongoid/Attributes#write_attribute-instance_method
Hope that helps

How to get the collection based upon the wildchar redis key using redis-rb gem?

The redis objects created using the redis-rb gem.
$redis = Redis.new
$redis.sadd("work:the-first-task", 1)
$redis.sadd("work:another-task", 2)
$redis.sadd("work:yet-another-task", 3)
Is there any method to get the collection that has "work:*" keys?
Actually, if you just want to build a collection on Redis, you only need one key.
The example you provided builds 3 distinct collections, each of them with a single item. This is probably not that you wanted to do. The example could be rewritten as:
$redis = Redis.new
$redis.sadd("work","the-first-task|1")
$redis.sadd("work", "another-task|2")
$redis.sadd("work", "yet-another-task|3")
To retrieve all the items of this collection, use the following code:
x = $redis.smembers("work")
If you need to keep track of the order of the items in your collection, it would be better to use a list instead of a set.
In any case, usage of the KEYS command should be restricted to tooling/debug code only. It is not meant to be used in a real application because of its linear complexity.
If you really need to build several collections, and retrieve items from all these collections, the best way is probably to introduce a new "catalog" collection to keep track of the keys corresponding to these collections.
For instance:
$redis = Redis.new
$redis.sadd("catalog:work", "work:the-first-task" )
$redis.sadd("catalog:work", "work:another-task" )
$redis.sadd("work:the-first-task", 1)
$redis.sadd("work:the-first-task", 2)
$redis.sadd("work:another-task", 3)
$redis.sadd("work:another-task", 4)
To efficiently retrieve all the items:
keys = $redis.smembers("catalog:work")
res = $redis.pipelined do
keys.each do |x|
$redis.smembers(x)
end
end
res.flatten!(1)
The idea is to perform a first query to get the content of catalog:work, and then iterate on the result using pipelining to fetch all the data. I'm not a Ruby user, so there is probably a more idiomatic way to implement it.
Another simpler option can be used if the number of collections you want to retrieve is limited, and if you do not care about the ownership of the items (in which set is stored each item)
keys = $redis.smembers("catalog:work")
res = $redis.sunion(*keys)
Here the SUNION command is used to build a set resulting of the union of all the sets you are interested in. It also filters out the duplicates in the result (this was not done in the previous example).
Well, I could get it by $redis.keys("work:*").

Duplicated Zend_Form Element ID in a page with various forms

How do I tell the Zend_Form that I want an element (and it's ID-label, etc) to use another ID value instead of the element's name?
I have several forms in a page. Some of them have repeated names. So as Zend_Form creates elements' IDs using names I end up with multiple elements with the same ID, which makes my (X)HTML document invalid.
What is the best solution to fix this, given that I really have to stick with using the same element names (they are a hash common to all forms and using the Zend_Form Hash Element is really out of question)?
Zend_Form_Element has a method called setAttribs that takes an array. You may be able to do something like $element->setAttribs(array('id' => "some_id"));
or you can do $element->setAttrib('id', 'some_id');
Thanks, Chris Gutierrez.
However, as I said, I needed to get ride of the default decorator generated IDs like -label. Wiht the $element->setAttribs() it is not possible, however.
So based on http://framework.zend.com/issues/browse/ZF-7125 I just did the following:
$element->clearDecorators();
$element->setAttrib('id', 'some_id');
$element->addDecorator("ViewHelper");
Whoever sees this: please note this was enough for what I needed. But may not be for you (the default settings has more than the viewHelper decorator).

Resources