# Dynamic tag cloud

**URL:** <https://www.ruby-forum.com/t/dynamic-tag-cloud/68236>\
**Category:** Rails\
**Created:** [September 11, 2006, 12:49am UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236 "2006-09-11T00:49:45Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 11, 2006, 12:49am UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/1 "2006-09-11T00:49:45Z")

</div>

Hello everyone 🙂

This is my first post to this list so let me briefly introduce myself.  
I am a student at Imperial College London and am currently learning to  
ride the rails. Together with two other students I am developing a  
revolutionary job platform for students.

At the moment I am implementing tagging into our application using  
DHH’s acts\_as\_taggable plugin. In my database I have a table with job  
listings. Every job listing has various tags. As intended by the  
acts\_as\_taggable plugin these tags are stored in a table called tags  
and linked to the job listings through a table called taggings. I also  
have a tag cloud showing the most popular tags. So far everything is  
working fine.

Now I would like to modify my tag cloud in the following way: I have a  
page where users can narrow the job listings down using tags. They can  
click on a tag and then a list of all jobs carrying that tag is  
displayed. Now I would like to adjust my tag cloud accordingly. The tag  
cloud should now only show tags associated to the remaining jobs. In  
other words: By showing only those listings with a particular tag I am  
defining a subset of my database. Now I would like to show only tags  
out of that subset in my tag cloud. An example can be seen on  
[http://www.extate.com/search.php?q=kensington](http://www.extate.com/search.php?q=kensington) . When you click on a tag  
the tags list gets updated and you can narrow your search down again  
using the new list of tags.

Any ideas about how I could accomplish such a dynamic tag cloud? Please  
be as specific as possible as I am relatively new to Ruby and Rails.

So far, my tag cloud is generated as described on

> **[Acts As Taggable Tag Cloud](http://juixe.com/techknow/index.php/2006/07/15/acts-as-taggable-tag-cloud/)**
>
> If you are using the Ruby on Rails acts\_as\_taggable plugin you may want to display the top tags in a tag cloud. To generate a tag cloud you will to write some code beyond just writing the controlle…

Many thanks for your help,  
Aeneas

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 12, 2006, 11:44am UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/2 "2006-09-12T11:44:30Z")

</div>

Anyone? Could you at least point me in the right direction?

Aeneas

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 12, 2006, 12:52pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/3 "2006-09-12T12:52:38Z")

</div>

Sure, that’s pretty easy. You’ll need to extend the acts\_as\_taggable  
plugin  
though.

Lets say we add something like this to tab.rb:

def self.get\_all\_tagged\_with\_for\_type(type, tags)

```
query = "SELECT taggable_id, name FROM"
query << " taggings, tags WHERE"
query << " tags.id = taggings.tag_id"
query << " AND name IN ('#{sanitize(tags.join('\',\''))}') AND

```

taggable\_type = ‘#{type.name}’;

end

That will return all object IDs of the given type for the given array of  
tags.

so you might call it like this:

Tag.get\_all\_tagged\_with\_for\_type(Job, Tag.parse(params[:tags].tr(‘,’, ’  
')))

This assumes your URL looks something like:

> **[Overview](https://www.salesforce.com/products/platform/overview/?d=70130000000liBh&internal=true&bc=HA)**
>
> Go digital fast and empower your teams to work from anywhere. Develop scalable, custom business apps with low-code development or give your teams the tools to build with services and APIs.

You need to perform some better parsing if you want tags with spaces in  
them. Tag.parse() will handle such tags if they’re quoted.

I’ve not tested any of this code, so no doubt it doesn’t work without a  
little work. But please note the use of sanitize() in the model method!  
We’re taking user input and using it a query so we need to protected  
against  
SQL injection attacks

The annoying part comes when extending the existing plugin tab.rb.  
Currently, Rails will reload the plugin in development for each request  
and  
you’ll loose any methods you dynamically extended it with during  
startup. So  
for now stick the method inside the plugin and keep and eye out for  
Rails  
1.2:  
[http://rails.techno-weenie.net/tip/2006/9/8/reloading-dynamically-extended-classes](http://rails.techno-weenie.net/tip/2006/9/8/reloading-dynamically-extended-classes)

Hope that helps  
Ian

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 12, 2006, 12:52pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/4 "2006-09-12T12:52:39Z")

</div>

Oops, and of course we need to Tag.find\_by\_sql(query) in that model  
method  
😉

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 12, 2006, 8:11pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/5 "2006-09-12T20:11:38Z")

</div>

You need to iterate over the results and load each job using the  
taggable\_id  
value:

tagged\_with = Tag.get\_all\_tagged\_with\_for\_type(Job, [‘hard’])

for tagged in tagged\_with

```
job = Job.find(tagged[:taggable_id])
job.tag_list

```

end

You could move the query into a method inside your Job model and join on  
the  
taggable\_id and job id to save you having to iterate the results in this  
way.

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 12, 2006, 7:35pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/6 "2006-09-12T19:35:34Z")

</div>

Ian, many thanks for your reply!  
It is still not doing what I want.  
I simplified (for testing) the relevant part of the SQL query slightly  
by adding the common tag manually:

query \<\< " AND name IN (‘hard’)"

Here is what I expected:

I wanted to see all tags assigned to those jobs which have also been  
tagged with “hard”.

However, that’s not what I am getting with this query. Instead I just  
get the tag hard itself and nothing else. I am pretty sure everything  
else is set up correctly. When I leave the line quoted above out then I  
get all tags in the tags table so this is working.

Any suggestions?

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 13, 2006, 10:44pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/7 "2006-09-13T22:44:28Z")

</div>

Many thanks for your help!

I have now managed to output the correct tags to the browser as a comma  
separated list.

Controller:  
@jobs\_tagged\_with = Tag.find\_by\_name(params[:common\_tag], :limit =\> 10  
).tagged

View:  
\<% for job in @jobs\_tagged\_with %\>  
\<%= job.tags.collect{|tag| tag.name}.join(", ") + “,” %\>  
\<% end %\>

However, that’s not quite what I want. How can I get the tags  
currently displayed on screen in an array? This array could then be  
used to feed my tag cloud.

I am sure this is nothing very difficult for someone a bit more  
experienced with Ruby than I am. I am still trying to get my head  
around all this…

Aeneas

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 21, 2006, 2:13pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/8 "2006-09-21T14:13:32Z")

</div>

Finally, I have been able to figure out an SQL query which does all the  
work for me. Here it is:

SELECT tags.name, count(\*) AS count FROM jobs  
JOIN taggings ON jobs.id = taggings.taggable\_id  
JOIN tags ON taggings.tag\_id = tags.id  
WHERE jobs.id IN ( SELECT jobs.id FROM jobs  
JOIN taggings ON jobs.id = taggings.taggable\_id  
JOIN tags ON taggings.tag\_id = tags.id  
WHERE tags.name IN (“tag2”, “tag3”)  
)  
AND tags.name NOT IN (“tag2”, “tag3”)  
GROUP BY tags.name  
ORDER BY count DESC , tags.name

Aeneas

---

<div class="post-metadata">

**Author:** ![Aeneas](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@Aeneas](https://www.ruby-forum.com/u/Aeneas)\
**Post date:** [September 13, 2006, 11:02pm UTC](https://www.ruby-forum.com/t/dynamic-tag-cloud/68236/9 "2006-09-13T23:02:30Z")

</div>

Displayed on the screen as an array object? or you want to convert a  
string  
list of tags into an array? Not quite sure what you want.

If you meaning parsing the tags:

Tag.parse(“tag1 tag2 “tag3 with spaces””) # Parse space seperate list  
of  
tags  
=\> [“tag3 with space”, “tag1”, “tag2”]

“tag1, tag2, tag3 with spaces”.split(’, ')  
=\> [“tag1”, “tag2”, “tag3 with spaces”]

If you mean an array as in something you can pass as a parameter in the  
URL,  
then just use a comma seperated list and parse it in the receiving  
controller.
