Search code examples
ruby-on-railsrubyruby-on-rails-4acts-as-taggable-on

Search form with acts_as_taggable_on in Rails 4


I am creating a rails app that allows a user to create a post and add tags to it. I am trying to implement a search bar that can search for tags and filter the results by displaying all the posts that contain the tag that a user has searched for. I have installed the acts_as_taggable_on gem.

Here is my Post model where I am trying to implement the search method that is not working at the moment:

class Post < ActiveRecord::Base
belongs_to :user
acts_as_taggable

def self.search(search)
    where("tag_list LIKE", "%#{search}")
end
end

Here is my Post controller with index method and private methods:

class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy, :upvote]
before_filter :authenticate_user!, except: [:index, :show]

def index
if params[:search]
    @posts = Post.search(params[:search]).order("created_at DESC")
else
    @posts = Post.all
end
end

private

def set_post
    @post = Post.find(params[:id])
end
def post_params
    params.require(:post).permit(:title, :content, :tag_list, :user_id)
end
end

This is how I am implementing the search form in my views:

<%= form_tag(posts_path, :method => 'get', id: "search-form") do %>
<%= text_field_tag :search,params[:search], placeholder: "Search Tags" %>
<%= submit_tag "Search" %>
<% end %>

Migrations (All created by the acts_as_taggable_on gem):

class CreatePosts < ActiveRecord::Migration
def change
    create_table :posts do |t|
        t.string :title
        t.text :content

        t.timestamps null: false
    end
end
end

class ActsAsTaggableOnMigration < ActiveRecord::Migration
def self.up
    create_table :tags do |t|
        t.string :name
    end

create_table :taggings do |t|
    t.references :tag

    t.references :taggable, polymorphic: true
    t.references :tagger, polymorphic: true

    t.string :context, limit: 128

    t.datetime :created_at
end

add_index :taggings, :tag_id
add_index :taggings, [:taggable_id, :taggable_type, :context]
end

def self.down
    drop_table :taggings
    drop_table :tags
end
end

class AddMissingUniqueIndices < ActiveRecord::Migration
def self.up
    add_index :tags, :name, unique: true

    remove_index :taggings, :tag_id
    remove_index :taggings, [:taggable_id, :taggable_type, :context]
    add_index :taggings, [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type], unique: true, name: 'taggings_idx'
    end

def self.down
    remove_index :tags, :name

    remove_index :taggings, name: 'taggings_idx'
    add_index :taggings, :tag_id
    add_index :taggings, [:taggable_id, :taggable_type, :context]
end
end

class AddTaggingsCounterCacheToTags < ActiveRecord::Migration
def self.up
    add_column :tags, :taggings_count, :integer, default: 0

ActsAsTaggableOn::Tag.reset_column_information
ActsAsTaggableOn::Tag.find_each do |tag|
  ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings)
end
end

def self.down
    remove_column :tags, :taggings_count
end
end

class AddMissingTaggableIndex < ActiveRecord::Migration
def self.up
    add_index :taggings, [:taggable_id, :taggable_type, :context]
end

def self.down
    remove_index :taggings, [:taggable_id, :taggable_type, :context]
end
end

class ChangeCollationForTagNames < ActiveRecord::Migration
def up
    if ActsAsTaggableOn::Utils.using_mysql?
      execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;")
    end
    end
end

Solution

  • You don't need to write your own scope - Acts as Taggable comes with one for just your situation: tagged_with

    Here's an example: https://github.com/mbleigh/acts-as-taggable-on#finding-tagged-objects

    Remove your search scope and change your controller#index method to do this instead:

    @posts = Post.tagged_with(params[:search]).order("created_at DESC")