Rails 4 -使用Acts作为Taggable gem使用select_tag从集合中选择标签



在我的rails应用程序中,我有两个模型:TeamPost,每个Post可以有多个标签,每个Team可以有许多Posts。在我的团队的show动作中,我想展示一个select_tag,用户可以用它从所有创建的标签中选择一个标签。当用户使用select_tag选择一个标签时,我只想显示同样具有该标签的帖子。我使用Acts as Taggable On gem.

我现在有这个(我使用HAML):

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

给我一个选择,看起来像这样:

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

我想要的是一个像这样的选择列表:

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

我不怎么用select_tag。有可能做我想做的事吗?那会是什么样子?

这有两个方面:显示正确的标记列表,并根据所选标记过滤帖子。

显示正确的标签列表

您想要创建一个<select>元素,它只包含该团队帖子的标签。options_from_collection_for_select接受3个参数:一个集合,一个获取每个选项值的方法,以及一个获取每个选项名称的方法。所以您应该将一组标签传递给options_from_collection_for_select,而不是一组帖子。这组标签不应该是所有的标签-只有那些你的团队的帖子。幸运的是,acts_as_taggable_on提供了这样做的方法,因此您可以构建标记云。

所以你要更新你的控制器,让它看起来像这样:

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

和更新你的视图使用@team_tags代替:

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

这将给您一个选择框,其中填充了特定于该团队的标签。

通过标签筛选文章

现在我们有了正确的标签列表,我们希望能够按标签过滤帖子。<select>标签应该在一个表单中;您可以创建一个新的控制器动作来处理该表单,或者相应地调整您的show方法。后者有点棘手,所以我在这里采用了这种方法。让我们更新您的视图,使假设更清晰:

= 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"

并更新控制器动作来过滤帖子,如果我们有一个'tags'参数:

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

请注意,我们将选择的标签作为实例变量@tag传入,并在options_from_collection_for_select中使用它来选择正确的标签,如果我们选择了一个过滤器。

锦上添花

您可以使用一点jQuery和CoffeeScript来隐藏提交按钮,并使过滤在用户选择新标签时自动发生,这将稍微改善您的用户体验。添加到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() 

通过查找所有具有tag_form类的元素,删除每个元素中的所有<input type="submit">元素,然后监听这些表单中选择元素的更改事件。

最新更新