# Habtm on an array

**URL:** <https://www.ruby-forum.com/t/habtm-on-an-array/62091>\
**Category:** Ruby\
**Created:** [May 31, 2006, 1:28pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091 "2006-05-31T13:28:35Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [May 31, 2006, 1:28pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091/1 "2006-05-31T13:28:35Z")

</div>

Hi,

I have three Models

User, Group and File.

User habtm group  
Group habtm File

How can I find all that files that a particular user has access to?  
eg user.groups.files ?

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [May 31, 2006, 1:40pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091/2 "2006-05-31T13:40:37Z")

</div>

On May 31, 2006, at 12:28, Daniel wrote:

> eg user.groups.files ?  
> The Rails-specific list ([http://lists.rubyonrails.org/mailman/](http://lists.rubyonrails.org/mailman/)  
> listinfo/rails) and wiki and things may give you a better answer  
> (particularly in terms of things like query optimisation) than you’ll  
> get here, but…

user.groups is an array, it’s not the array which has a file  
attribute, but each individual group in it, so maybe something like  
this:

class User  
def files  
self.groups.inject([]) { |arr, group| arr + group.files }  
end  
end

matt smillie.

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [May 31, 2006, 2:21pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091/3 "2006-05-31T14:21:34Z")

</div>

On Wednesday 31 May 2006 5:28 am, Daniel wrote:

> I have three Models
> 
> User, Group and File.
> 
> User habtm group  
> Group habtm File
> 
> How can I find all that files that a particular user has access to?  
> eg user.groups.files ?

Step back from the problem a step. Forget that you are working with  
models or  
that you are dealing with habtm relationships in Rails.

user.groups returns an array. And each of the elements in that array,  
if you  
call files() on it, returns another array.

So all you are really looking at here is a requirement to iterate over  
an  
array of arrays, creating a set consisting of each of the unique values  
from  
those arrays. Strip all the Rails stuff away, and it’s just a simple  
data  
problem.

So, create a simple surrogate to think about:

a = [[1,2,3],  
[2,3,4],  
[3,4,5],  
[4,5,6],  
[5,6,7],  
[6,7,8]]

That’s just an array of arrays. Arrays in Ruby provide some handy  
methods for  
treating them like sets. And what you want is the union of all of your  
sets.  
With an array, | performs a union operation. So:

[1.,2,3] | [2,3,4]

returns

[1,2,3,4]

So all that you need to do now is iterate through your array applying  
each sub  
array to a common array with the union operator.

arr = []  
a.each {|elem| arr = arr | elem}

That works. You get:

[1,2,3,4,5,6,7,8]

FYI, Ruby also provides a method, inject(), that is perfect for this  
kind of  
operation. So, the above code can be rewritten like so:

a.inject([]) {|arr,elem| arr | elem}

inject() just takes a starting value and a block. The arguments to the  
block  
are an accumulator variable, which is initialized to the starting value  
passed to inject, and each successive element of the array inject it  
iterating over. The code in the block is evaluated and the result of  
the  
code is inserted into the accumulator variable. When all values of the  
array  
have been iterated over, inject() returns the final value of the  
accumulator.  
It’s the loop for code that needs to accumulate values.

Anyway, that’s the way to solve the problem with an arbitrary set of  
arrays.  
So, now just apply it to your model.

Something like this, probably:

class User  
def files  
groups.inject([]) {|all\_files, some\_files| all\_files | some\_files}  
end  
end

Hope this helps,

Kirk H.

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [May 31, 2006, 3:26pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091/4 "2006-05-31T15:26:02Z")

</div>

> -----Original Message-----  
> From: Kirk H. [[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]

> […nice breakdown…]

> a.inject([]) {|arr,elem| arr | elem}

a.flatten.uniq ?

> […]  
> Something like this, probably:
> 
> class User  
> def files  
> groups.inject([]) {|all\_files, some\_files| all\_files |  
> some\_files}  
> end  
> end

Should be equivalent to:

groups.flatten.uniq

But does probably not work because (as you explained)

“…And each of the elements in that array, if you  
call files() on it, returns another array”

class User  
def files  
groups.inject([]) {|all\_files, group| all\_files | group.files}  
end  
end

> Hope this helps,
> 
> Kirk H.

cheers

Simon

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [May 31, 2006, 3:50pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091/5 "2006-05-31T15:50:45Z")

</div>

> > class User  
> > def files  
> > groups.inject([]) {|all\_files, group| all\_files | group.files}  
> > end  
> > end
> 
> Doh! Yeah. I goofed. Thanks.
> 
> Kirk H.

We all do that - from time to time 🙂

As Rails implements Symbol#to\_proc one should be able to do

myuser.groups.map(&:files).flatten.uniq

but that is getting esotheric.

cheers

Simon

---

<div class="post-metadata">

**Author:** ![daniel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3ec8ea/32.png) [@daniel](https://www.ruby-forum.com/u/daniel)\
**Post date:** [May 31, 2006, 3:35pm UTC](https://www.ruby-forum.com/t/habtm-on-an-array/62091/6 "2006-05-31T15:35:12Z")

</div>

On Wednesday 31 May 2006 7:23 am, Kroeger, Simon (ext) wrote:

> Should be equivalent to:  
> groups.inject([]) {|all\_files, group| all\_files | group.files}  
> end  
> end

Doh! Yeah. I goofed. Thanks.

Kirk H.
