• Stars
    star
    473
  • Rank 92,832 (Top 2 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 11 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A good, simple, solid tagging extension for ActiveRecord.

Gutentag

Gem Version Build Status Code Climate

A good, simple, solid tagging extension for ActiveRecord.

This was initially built partly as a proof-of-concept, partly to see how a tagging gem could work when it's not all stuffed within models, and partly just because I wanted a simpler tagging library. It's now a solid little tagging Rails engine.

If you want to know more, read this blog post, or have a look at the Examples page in the wiki (which includes a starting point for accepting tag values in a form).

Contents

Usage

The first step is easy: add the tag associations to whichever models should have tags (in these examples, the Article model):

class Article < ActiveRecord::Base
  # ...
  Gutentag::ActiveRecord.call self
  # ...
end

That's all it takes to get a tags association on each article. Of course, populating tags can be a little frustrating, unless you want to manage Gutentag::Tag instances yourself? As an alternative, just use the tag_names accessor to get/set tags via string representations.

article.tag_names #=> ['pancakes', 'melbourne', 'ruby']
article.tag_names << 'portland'
article.tag_names #=> ['pancakes', 'melbourne', 'ruby', 'portland']
article.tag_names -= ['ruby']
article.tag_names #=> ['pancakes', 'melbourne', 'portland']

Changes to tag_names are not persisted immediately - you must save your taggable object to have the tag changes reflected in your database:

article.tag_names << 'ruby'
article.save

You can also query for instances with specified tags. The default :match mode is :any, and so provides OR logic, not AND - it'll match any instances that have any of the tags or tag names:

Article.tagged_with(:names => ['tag1', 'tag2'], :match => :any)
Article.tagged_with(
  :tags  => Gutentag::Tag.where(name: ['tag1', 'tag2']),
  :match => :any
)
Article.tagged_with(:ids => [tag_id], :match => :any)

To return records that have all specified tags, use :match => :all:

# Returns all articles that have *both* tag_a and tag_b.
Article.tagged_with(:ids => [tag_a.id, tag_b.id], :match => :all)

To return records that have none of the specified tags, use :match => :none:

# Returns all articles that have *neither* tag_a nor tag_b.
Article.tagged_with(:ids => [tag_a.id, tag_b.id], :match => :none)

To return all tag names used by an instance of a model or relation

# Returns array of tag names
Gutentag::Tag.names_for_scope(Article)
# => ['tag1', 'tag2', 'tag3']

Gutentag::Tag.names_for_scope(Article.where(:created_at => 1.week.ago..1.second.ago))
# => ['tag3']

# Return array of the tag names used from the two most recent articles
Gutentag::Tag.names_for_scope(Article.order(created_at: :desc).limit(2))
# => []

Installation

Dependencies

These are the versions the test suite runs against. It's possible it may work on older versions of Ruby, but it definitely won't work on older versions of Rails.

  • Ruby: MRI v2.3-v3.1, JRuby v9.2.5
  • Rails/ActiveRecord: v4.0-v7.0

If you're using MRI v2.2 and/or ActiveRecord v3.2, the last version of Gutentag that fully supported those versions is v2.4.1.

Installing

Get it into your Gemfile - and don't forget the version constraint!

gem 'gutentag', '~> 2.6'

Next: your tags get persisted to your database, so let's import the migrations, update them to your current version of Rails, and then migrate:

bundle exec rake gutentag:install:migrations
bundle exec rails generate gutentag:migration_versions
bundle exec rake db:migrate

If you're using UUID primary keys, make sure you alter the migration files before running db:migrate to use UUIDs for the taggable_id foreign key column (as noted in issue 57.)

Without Rails

If you want to use Gutentag outside of Rails, you can. However, there is one caveat: You'll want to set up your database with the same schema (as importing in the migrations isn't possible without Rails). The schema from 0.7.0 onwards is below:

create_table :gutentag_tags do |t|
  t.string :name,           null: false, index: {unique: true}
  t.bigint :taggings_count, null: false, index: true, default: 0
  t.timestamps              null: false
end

create_table :gutentag_taggings do |t|
  t.references :tag,      null: false, index: true, foreign_key: {to_table: :gutentag_tags}
  t.references :taggable, null: false, index: true, polymorphic: true
  t.timestamps            null: false
end
add_index :gutentag_taggings, [:taggable_type, :taggable_id, :tag_id], unique: true, name: "gutentag_taggings_uniqueness"

Upgrading

Please refer to the CHANGELOG, which covers significant and breaking changes between versions.

Configuration

Gutentag tries to take a convention-over-configuration approach, while also striving to be modular enough to allow changes to behaviour in certain cases.

Tag validations

The default validations on Gutentag::Tag are:

  • presence of the tag name.
  • case-insensitive uniqueness of the tag name.
  • maximum length of the tag name (if the column has a limit).

You can view the logic for this in Gutentag::TagValidations, and you can set an alternative if you wish:

Gutentag.tag_validations = CustomTagValidations

The supplied value must respond to call, and the argument supplied is the model.

Tag normalisation

Tag normalisation is used to convert supplied tag values consistently into string tag names. The default is to convert the value into a string, and then to lower-case.

If you want to do something different, provide an object that responds to call and accepts a single value to Gutentag.normaliser:

Gutentag.normaliser = lambda { |value| value.to_s.upcase }

Case-sensitive tags

Gutentag ignores case by default, but can be customised to be case-sensitive by supplying your own validations and normaliser, as outlined by Robin Mehner in issue 42. Further changes may be required for your schema though, depending on your database.

Extending

If you need to extend Gutentag's models, you will need to wrap the include inside a to_prepare hook to ensure it's loaded consistently in all Rails environments:

# config/initializers/gutentag.rb or equivalent
Rails.application.config.to_prepare do
  Gutentag::Tag.include TagExtensions
end

Further discussion and examples of this can be found in issue 65.

Contribution

Please note that this project now has a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Licence

Copyright (c) 2013-2022, Gutentag is developed and maintained by Pat Allan, and is released under the open MIT Licence.

More Repositories

1

thinking-sphinx

Sphinx/Manticore plugin for ActiveRecord/Rails
Ruby
1,620
star
2

combustion

Simple, elegant testing for Rails Engines
Ruby
674
star
3

riddle

Ruby Client API for Sphinx
Ruby
136
star
4

ts-delayed-delta

Manage delta indexes via Delayed Job for Thinking Sphinx
Ruby
73
star
5

thinking-sphinx-raspell

An add-on gem for spelling suggestions in Thinking Sphinx
Ruby
58
star
6

ts-datetime-delta

Manage delta indexes via datetime columns for Thinking Sphinx
Ruby
45
star
7

fakeweb-matcher

An RSpec matcher for the Fakeweb HTTP stubbing library
Ruby
37
star
8

calendav

Interact with CalDAV via Ruby
Ruby
36
star
9

sliver

A super simple, extendable Rack API.
Ruby
30
star
10

sphinx

Free open-source SQL full-text search engine
C++
26
star
11

active-matchers

Helpful rspec matchers for testing validations and associations.
Ruby
23
star
12

ginger

Run specs/tests multiple times through different gem versions
Ruby
22
star
13

render_api

Ruby interface for the render.com API.
Ruby
19
star
14

pat.github.com

HTML
17
star
15

railscamps.com

Rails Camps Website
HTML
15
star
16

pedantic

Pares text down to the words that matter
Ruby
14
star
17

pippin

A PayPal Rails Engine that handles IPNs
Ruby
14
star
18

drumknott-server

Server for storing static site search data.
Ruby
11
star
19

gyoza

Streamlined Editing for GitHub Pages
JavaScript
11
star
20

support-act

Encouraging people to buy albums alongside their streaming, to better support artists.
Ruby
11
star
21

not-a-mock

A cleaner and DRYer alternative to mocking and stubbing with RSpec.
Ruby
10
star
22

laughtrack

A festival buzz tracker
Ruby
10
star
23

joiner

Builds ActiveRecord joins from association paths
Ruby
7
star
24

sslocal-rb

Make local environment SSL as streamlined as possible.
Ruby
7
star
25

numbr5

Thank-you bot for IRC (and maybe more)
Ruby
7
star
26

sphinx-tute

Project for the Sphinx Tutorial at RailsConf 2009
Ruby
6
star
27

ruby-netcdf

Copy of source for ruby-netcdf gem, with tweak for MRI 2.0.0
C
6
star
28

enkoder

An extension to the Rails TextHelper module that can be used to protect email addresses (or other information) by obfuscating them using JavaScript code. Written by Dan Benjamin.
Ruby
6
star
29

nudge

Simple Static Site Deployer via Git
Ruby
6
star
30

radiant-tiny-mce

Tiny MCE Filter and Asset Management (via Paperclipped)
5
star
31

tramampoline

Trampoline Website, now with registrations
HTML
5
star
32

thin-glazed

SSL Proxy for HTTP Thin servers
Ruby
5
star
33

ts-sidekiq-delta

Thinking Sphinx - Sidekiq Deltas
Ruby
5
star
34

gzipped_tar

In-memory reading/writing of .tar.gz files
Ruby
5
star
35

radiant-layout-layer

Automatically create Radiant layouts based on HTML files in other extensions
Ruby
5
star
36

inkan

Unique file markers for tracking whether files have been changed.
Ruby
4
star
37

vcr_assistant

Manages VCR cassettes and set-up logic for RSpec.
Ruby
4
star
38

beer-tracker

Website/API partner for Numbr5
3
star
39

sslocal-js

Make local environment SSL as streamlined as possible.
JavaScript
3
star
40

chargify-loops

A Rails Engine for Chargify Webhooks
Ruby
3
star
41

laughtrack-couch

Couch Logic and Views for LaughTrack
JavaScript
2
star
42

postie

Ruby
2
star
43

babushka-deps

Babushka Dependencies
Ruby
2
star
44

radiant-publican

Automatically copy Radiant extensions' public files on every load for the development environment
2
star
45

spreadsheet-excel

Resurrecting an old gem.
Ruby
2
star
46

.js

JavaScript
1
star
47

shithead

A card game
Ruby
1
star
48

bb8

Keeps Terraform state and variables secret per environment, with help from Voltos
Ruby
1
star
49

lipwig

Write group emails in Markdown, send via Postmark or SMTP.
Ruby
1
star
50

ruby-event-guides

Tips and thoughts about running Rails Camps and RubyConf AU.
1
star
51

thinking-sphinx-examples

Example of advanced search form.
Ruby
1
star
52

trampolinemelb.com

Website for Trampoline, a cross-discipline unconference.
1
star
53

livecal

Translate ical/ics files into actual calendars and events
Ruby
1
star
54

isnotagithubberyet

Because Jan said I should - and who needs a better reason than that?
Ruby
1
star
55

resque-crashlog

Resque failure handler for crashlog.io
Ruby
1
star
56

lu-tze

Automated Backup Helper for Heroku
Ruby
1
star
57

json_template_benchmarking

Ruby
1
star