Rails 4 - Select tag from collection using Acts as Taggable gem with select_tag

In my rails app I have two models: Team and Post, each Post can have multiple tags, and each Team can have many Posts. In my team's show action I want to present a select_tag with which the user can select one tag of all the created tags for it's posts. When the user selects a tag using the select_tag I only want to show the posts that also have that tag. I use the Acts as Taggable On gem.

What I currently have is this (I'm using HAML):

= select_tag "tags", options_from_collection_for_select(@posts, "tags", :tag_list)

This give me a select that looks something like this:

[row 1] Tag 1
[row 2] Tag 1, Tag 2
[...]

What I want is a select list that looks like this:

[row 1] Tag 1
[row 2] Tag 2
[row 3] Tag 3
[...]

I haven't used select_tag much. Would it be possible to do what I want somehow? And how would that look?

Answers


There's two aspects to this: showing the correct tag list, and filtering the posts by the selected tag.

Showing the correct tag list

You want to create a <select> element that only contains tags for that team's posts. options_from_collection_for_select takes 3 parameters: a collection, a method to get the value for each option, and a method to get the name of each option. So you should be passing a set of tags to options_from_collection_for_select, not a set of posts. And that set of tags shouldn't be all tags - just the ones for your team's posts. Fortunately, acts_as_taggable_on provides a method to do that so you can build tag clouds.

So you're going to update your controller to look something like this:

class TeamController < ApplicationController
    def show
        @team = Team.find params[:id]
        @posts = team.posts
        @team_tags = team.posts.tag_counts_on(:tags)
    end
end

And update your view to use @team_tags instead:

= select_tag "tag", options_from_collection_for_select(@team_tags, 'id', 'name') 

This should give you a select box populated with the tags specific to that team.

Filtering posts by tag

Now we've got the correct tag list, we want to be able to filter posts by tag. That <select> tag should be within a form; you can either create a new controller action that handles that form, or adapt your show method accordingly. The latter's a bit trickier, so I've taken that approach here. Let's update your view to make the assumptions clearer:

= form_tag team_path(@team), method: 'get', class: 'tag_form' do
  = select_tag "tag", options_from_collection_for_select(@team_tags, 'id', 'name', @tag)
  = submit_tag "Filter posts"

And update the controller action to filter the posts, if we've got a 'tags' parameter:

class TeamController < ApplicationController
    def show
        @team = Team.find params[:id]
        @team_tags = team.posts.tag_counts_on(:tags)
        if params[:tag]
            @tag = Tag.find params[:tag]
            @posts = team.posts.tagged_with @tag.name
        else
            @tag = nil
            @posts = team.posts
        end
    end
end

Notice that we're passing in the selected tag as the instance variable @tag, and using that in our options_from_collection_for_select to select the right tag if we chose a filter.

The icing on the cake

You can use a little jQuery and CoffeeScript to hide your submit button and make the filtering happen automatically when the user chooses a new tag, which will improve your user experience a bit. Add this to app/assets/javascripts/teams.js.coffee:

$ ->
    $forms = $('.tag_form')
    $forms.each (i, el) -> 
        $('input[type=submit]', el).hide()
        $('select', el).on 'change', (ev) -> 
            $(el).submit() 

This works by finding all elements with a class of tag_form, removes all <input type="submit"> elements within each one, and then listens for change events on the select elements within those forms.


Need Your Help

What's the simplest way to import a System.Data.DataSet into Excel?

.net excel serialization dataset

In .NET 2.0 (in this case VB), is there a standard API that'll serialize a DataSet object into a stream that can be saved as a tab-delimited file and opened directly in Excel? Or does one have to ...

Unit testing in ASP.NET/C# using monodevelop and NUnit

asp.net-mvc nunit monodevelop

I'm developing a webapp using ASP.NET MVC and C# using Monodevelop IDE and unit testing using NUnit plugin for monodevelop in ubuntu OS. How do I implement the unit testing for my setup?

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.