# Has many\_through, how to show only unassociated fields for a category?

**URL:** <https://www.ruby-forum.com/t/has-many-through-how-to-show-only-unassociated-fields-for-a-category/189537>\
**Category:** Rails\
**Created:** [June 2, 2010, 5:51pm UTC](https://www.ruby-forum.com/t/has-many-through-how-to-show-only-unassociated-fields-for-a-category/189537 "2010-06-02T17:51:25Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![samuel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@samuel](https://www.ruby-forum.com/u/samuel)\
**Post date:** [June 2, 2010, 5:51pm UTC](https://www.ruby-forum.com/t/has-many-through-how-to-show-only-unassociated-fields-for-a-category/189537/1 "2010-06-02T17:51:25Z")

</div>

Hi everybody,

I’m using ruby 1.9.1, with rails 2.3.\*. I have an application of  
products and categories, but I want each type of product to have  
specific attributes. So, basically, according to the chosen category,  
I want different fields to be shown for the user.

So, before actually making the association of the product with the  
attribute, I want to create an administration system where the  
administrators could actually select wich fields they want for each  
category, in an N:N association, usign has many through  
(categoryFields is the middle table). So, up to now, the structure is:

class Field \< ActiveRecord::Base  
has\_many :categoryFields, :dependent =\> :destroy  
has\_many :categories, :through =\> :categoryFields  
end

class CategoryField \< ActiveRecord::Base  
belongs\_to :field  
belongs\_to :category  
end

class Category \< ActiveRecord::Base  
has\_many :categoryFields, :dependent =\> :destroy  
has\_many :fields, :through =\> :categoryFields  
end

And this works perfectly.  
so, now, in my Category Edit view, I want to show a list of ALL  
AVAILABLE FIELDS (i.e. only those not already associated to that  
specific category) at the right, and in the left, all the ASSOCIATED  
FIELDS for that category. Using a simple drag-and-drop, the user can  
drag fields from the right to insert them in category, or move them to  
the right to remove them from that specific category.

The problem is that I don’t want that any field in the left column  
also appear in the right column (each field can only be used once in  
that specific category, since those attributes are unique). So, once  
you have associated a field to a category, it will not appear in the  
list of available fields (right list). I’m coming from PHP and this is  
my first rails application (I know, it’s kinda complicated for a  
noob).

So, what should I do, to exclude those values?

The edit method in the category controller:  
@category = Category.find(params[:id])  
@categories = Category.roots #the categories acts as nested set, so  
we have to fetch all available parent categories  
@fields = Field.all

Now, the view do the following:

 \<% if !@category.fields.empty? # this loops through all teh ASSOCIATED fields and display their names%\> \<% @category.fields.each do |field| %\> \<%=field.name%\> \<% end %\> \<% end %\> 

 \<% if !@fields.empty? # this loops through ALL THE fields and display their names %\> \<% @fields.each do |field| %\> \<%=field.name%\> \<% end %\> \<% end %\> 

So, where should I place the “filter” so that only available fields  
will appear in the second div? Shoud I place it in the controller, as  
a condition somehow, and how? Or should I use some array-function to  
“pop out” the already associated fields from the @fields array? Wich  
is better from the point of view of performance, and how do I do each  
of them?

Thanks a lot in advice, for any help  
Samuel  
Brandãremoved\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![samuel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@samuel](https://www.ruby-forum.com/u/samuel)\
**Post date:** [June 3, 2010, 2:36pm UTC](https://www.ruby-forum.com/t/has-many-through-how-to-show-only-unassociated-fields-for-a-category/189537/2 "2010-06-03T14:36:30Z")

</div>

Fields.all gives you an array of all the fields in the database  
@category.fields gives you an array of all the fields for the given  
category (since you have the has\_many :fields, :through  
=\> :categoryFields association)

How do you get the fields that are present in the first array but not  
in the second? Subtraction.

@fields\_not\_chosen\_yet = Fields.all - @category.fields

Btw, you may want to exchange :categoryFields for :category\_fields.

---

<div class="post-metadata">

**Author:** ![samuel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@samuel](https://www.ruby-forum.com/u/samuel)\
**Post date:** [June 3, 2010, 4:55pm UTC](https://www.ruby-forum.com/t/has-many-through-how-to-show-only-unassociated-fields-for-a-category/189537/3 "2010-06-03T16:55:53Z")

</div>

Hi Sharagoz, thank you for your reply. However, I had already tried  
array subtraction once, but with no success.

I tried for example:

associatedFields = @category.fields  
allFields = Field.all

available = allFields - associatedFields

however it did not work.  
When I try:

associatedFields.inspect

> > [#, #, #, #]

allFields.inspect

> > [#, #, #, #, #, #, #, #]

It seems to me that those resulting variables (allFields and  
associatedFields) are not of the specific class Array, or if they are,  
the subtraction is not working properly. I’m gonna do some more tests,  
to make sure i’m not screwing somewhere else.

thanks in advice for any help (at least I know i’m in the right  
direction :D)

Is there ANY way to make this subtraction/selection through SQL  
queries?

---

<div class="post-metadata">

**Author:** ![samuel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@samuel](https://www.ruby-forum.com/u/samuel)\
**Post date:** [June 3, 2010, 4:58pm UTC](https://www.ruby-forum.com/t/has-many-through-how-to-show-only-unassociated-fields-for-a-category/189537/4 "2010-06-03T16:58:14Z")

</div>

> associatedFields = @category.fields  
> allFields = Field.all
> 
> available = allFields - associatedFields

Field.all :conditions =\> [“id not in (?)”,  
@category.fields.all.map(&:id)]

Field.where([“id not in (?)”, @category.fields.all.map(&:id)]) if rails  
3

Ivan N.  
removed\_email\_address@domain.invalid
