# Gutentag [![Gem Version](https://badge.fury.io/rb/gutentag.png)](http://badge.fury.io/rb/gutentag) [![Build Status](https://travis-ci.org/pat/gutentag.png?branch=master)](https://travis-ci.org/pat/gutentag) [![Code Climate](https://codeclimate.com/github/pat/gutentag.png)](https://codeclimate.com/github/pat/gutentag) 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](http://freelancing-gods.com/posts/gutentag_simple_rails_tagging). ## Contents * [Usage](#usage) * [Installation](#installation) * [Upgrading](#upgrading) * [Configuration](#configuration) * [Contribution](#contribution) * [Licence](#licence)

Usage

The first step is easy: add the tag associations to whichever models should have tags (in these examples, the Article model): ```Ruby 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. ```Ruby 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: ```Ruby 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: ```Ruby 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`: ```ruby # Returns all articles that have *both* tag_a and tag_b. Article.tagged_with(:ids => [tag_a.id, tag_b.id], :match => :all) ```

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.2-v2.5, JRuby v9.1 * Rails/ActiveRecord: v3.2-v5.2 ### Installing Get it into your Gemfile - and don't forget the version constraint! ```Ruby gem 'gutentag', '~> 2.2.1' ``` Next: your tags get persisted to your database, so let's import and run the migrations to get the tables set up: ```Bash rake gutentag:install:migrations rake db:migrate ``` ### Without Rails If you want to use Gutentag outside of Rails, you can. However, there are two caveats: * You'll want to invoke this code once ActiveRecord's connected to the database: ```ruby ActiveSupport.run_load_hooks :gutentag ``` * And 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: ```Ruby create_table :gutentag_taggings do |t| t.integer :tag_id, null: false t.integer :taggable_id, null: false t.string :taggable_type, null: false t.timestamps null: false end add_index :gutentag_taggings, :tag_id add_index :gutentag_taggings, [:taggable_type, :taggable_id] add_index :gutentag_taggings, [:taggable_type, :taggable_id, :tag_id], unique: true, name: 'unique_taggings' create_table :gutentag_tags do |t| t.string :name, null: false t.integer :taggings_count, null: false, default: 0 t.timestamps null: false end add_index :gutentag_tags, :name, unique: true add_index :gutentag_tags, :taggings_count ```

Upgrading

Please refer to the [CHANGELOG](CHANGELOG.md), 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`](lib/gutentag/tag_validations.rb), and you can set an alternative if you wish: ```ruby 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](lib/gutentag.rb#L15) 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`: ```ruby 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](https://github.com/rmehner) in [issue 42](https://github.com/pat/gutentag/issues/42). Further changes may be required for your schema though, depending on your database.

Contribution

Please note that this project now has a [Contributor Code of Conduct](http://contributor-covenant.org/version/1/0/0/). By participating in this project you agree to abide by its terms.

Licence

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