{"id":28285623,"url":"https://github.com/neighborland/sluggi","last_synced_at":"2025-06-16T11:31:24.797Z","repository":{"id":13065857,"uuid":"15746414","full_name":"neighborland/sluggi","owner":"neighborland","description":"Rails Slug Generator","archived":false,"fork":false,"pushed_at":"2025-02-14T21:32:00.000Z","size":106,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-21T19:20:03.610Z","etag":null,"topics":["activerecord","friendly-id","rails","ruby","slugs"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neighborland.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-01-08T19:58:05.000Z","updated_at":"2025-02-14T21:31:29.000Z","dependencies_parsed_at":"2022-09-13T17:51:03.936Z","dependency_job_id":null,"html_url":"https://github.com/neighborland/sluggi","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/neighborland/sluggi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neighborland%2Fsluggi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neighborland%2Fsluggi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neighborland%2Fsluggi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neighborland%2Fsluggi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neighborland","download_url":"https://codeload.github.com/neighborland/sluggi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neighborland%2Fsluggi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260150507,"owners_count":22966322,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","friendly-id","rails","ruby","slugs"],"created_at":"2025-05-21T19:17:29.208Z","updated_at":"2025-06-16T11:31:24.765Z","avatar_url":"https://github.com/neighborland.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sluggi\n\n[![Gem Version](https://img.shields.io/gem/v/sluggi.svg)](https://rubygems.org/gems/sluggi)\n[![Build Status](https://github.com/neighborland/sluggi/actions/workflows/ruby.yml/badge.svg)](https://github.com/neighborland/sluggi/actions/workflows/ruby.yml)\n\nSluggi is a simple [friendly_id](https://github.com/norman/friendly_id)-inspired slugging library for ActiveRecord models. It is faster than `friendly_id` (see below for benchmarks).\n\nIt provides basic slugs, slug history, and the ability to define multiple slug candidates.\n\n## Versions\n\nThe gemspec includes the `activerecord` version dependency, so the correct version of `sluggi` will be installed to match your `activerecord` version.\n\n| sluggi | activerecord |\n| --: | --: |\n| 0.5 | 4.0-5.0 |\n| 1.0 | 5.1-5.2 |\n| 2.0 | 6.x |\n| 3.0 | 7.x |\n| 4.0 | 8.x |\n\n## Install\n\nAdd this line to your Gemfile:\n\n```ruby\ngem 'sluggi'\n```\n\nAdd a string column named `slug` to any models you want to slug. You can generate a migration like so:\n\n```sh\nrails generate migration AddSlugToCats slug:string:uniq:index\nrake db:migrate\n```\n\nTo track slug history for any model, you must generate a migration to add the `slugs` table:\n\n```sh\nrails generate sluggi\nrake db:migrate\n```\n\n## Usage\n\nSluggi is Magic Free(tm). Each slugged model must:\n\n* Have a column named `slug` (see above).\n* Include the `Sluggi::Slugged` module\n* Override the `slug_value` method or the `slug_candidates` method.\n\n### Simple Slugged Model\n\nSpecify the slug value by defining `#slug_value` and `#slug_value_changed?`.\n\n```ruby\nclass Cat \u003c ActiveRecord::Base\n  include Sluggi::Slugged\n\n  def slug_value\n    name\n  end\n\n  def slug_value_changed?\n    name_changed?\n  end\nend\n```\n\n```ruby\ncat = Cat.create(name: 'Tuxedo Stan')\ncat.slug\n=\u003e 'tuxedo-stan'\n\ncat.to_param\n=\u003e 'tuxedo-stan'\n\ncat_path\n=\u003e 'cats/tuxedo-stan'\n\nCat.find_by_slug('tuxedo-stan')\n=\u003e cat\n```\n\n### Model with Slugged History\n\nTo save slug history, include `Sluggi::History`. You get a `slugs` association. You can search for any\nslug in the history using `.find_slug!`.\n\nYou must also implement `#saved_change_to_slug_value?`.\n\n```ruby\nclass Cat \u003c ActiveRecord::Base\n  include Sluggi::Slugged\n  include Sluggi::History\n\n  def slug_value\n    name\n  end\n\n  def slug_value_changed?\n    name_changed?\n  end\n\n  def saved_change_to_slug_value?\n    saved_change_to_name?\n  end\nend\n```\n\n```ruby\ncat = Cat.create(name: 'Tuxedo Stan')\ncat.slug\n=\u003e 'tuxedo-stan'\n\ncat.name = 'Tuxedo Bob'\ncat.save\ncat.slug\n=\u003e 'tuxedo-bob'\n\n# use .find_slug! to search slug history:\n\nCat.find_slug!('tuxedo-bob')\n=\u003e cat\nCat.find_slug!('tuxedo-stan')\n=\u003e cat\n\n# plain finders will not search history:\n\nCat.find_by_slug('tuxedo-bob')\n=\u003e cat\n\nCat.find_by_slug('tuxedo-stan')\n=\u003e RecordNotFound\n\n```\n\n### Model with Slug Candidates\n\nOverride `#slug_candidates` to define cascading candidate values for slugs.\nThis is useful to avoid uniqueness conflicts. Do not override `#slug_value` -\nthe default implementation in `Model` will call `#slug_candidates` and\nworks with or without `History`.\n\n```ruby\nclass Cat \u003c ActiveRecord::Base\n  include Sluggi::Slugged\n\n  # The first unused value in the list is used.\n  # Each item may be a value or a lambda.\n  # Use a lambda to defer expensive unique value calculations.\n  def slug_candidates\n    [\n      name,\n      -\u003e { \"#{name}-#{Cat.count}\" }\n    ]\n  end\n\n  def slug_value_changed?\n    name_changed?\n  end\nend\n```\n\n```ruby\ncat = Cat.create(name: 'Tuxedo Stan')\ncat.slug\n=\u003e 'tuxedo-stan'\n\ncat_2 = Cat.create(name: 'Tuxedo Stan')\ncat_2.slug\n=\u003e 'tuxedo-stan-456'\n```\n\n## Performance\n\nRun the benchmark script: `ruby bench.rb`. This script is based on the\nbenchmark script from `friendly_id`.\n\nHere are some anecdotal results using ruby 2.5.3:\n\n```\n                                                  SLUGGI      FRIENDLY_ID\n1) find (id) - direct ActiveRecord                0.092318    0.093049\n2) find (in-table slug)                           0.102773    0.259542\n3) find (in-table slug; using finders module)     0.098183    0.108248\n4) find (external slug)                           0.670229    0.832791\n5) insert (plain AR / no slug)                    0.345077    0.345105\n6) insert (in-table-slug)                         0.666451    0.815505\n7) insert (in-table-slug; using finders module)   0.668737    0.744433\n8) insert (external slug)                         2.480790    2.849761\n```\n\nNotes:\n\nSluggi is at least 10% faster in every benchmark.\n\n1) Baseline (does not use either gem)\n2) 0.44x\n3) 0.90x\n4) 0.80x\n5) Baseline (does not use either gem)\n6) 0.82x\n7) 0.90x\n8) 0.87x\n\n\n## Alternatives\n\n* [override ActiveRecord#to_param](http://guides.rubyonrails.org/active_support_core_extensions.html#to-param)\n* [use ActiveRecord.to_param](https://github.com/rails/rails/pull/12891)\n* [friendly_id](https://github.com/norman/friendly_id)\n* [slug](https://github.com/bkoski/slug)\n* [slugged](https://github.com/Sutto/slugged)\n* [others](https://rubygems.org/search?utf8=%E2%9C%93\u0026query=slug)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneighborland%2Fsluggi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneighborland%2Fsluggi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneighborland%2Fsluggi/lists"}