Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dcalixto/friendly_id
FriendlyId for Crystal - Create human-readable URLs and slugs
https://github.com/dcalixto/friendly_id
crystal crystal-lang seo seo-optimization slug slug-generator slugify
Last synced: 5 days ago
JSON representation
FriendlyId for Crystal - Create human-readable URLs and slugs
- Host: GitHub
- URL: https://github.com/dcalixto/friendly_id
- Owner: dcalixto
- Created: 2024-12-02T04:59:11.000Z (2 months ago)
- Default Branch: master
- Last Pushed: 2024-12-22T01:25:14.000Z (about 2 months ago)
- Last Synced: 2024-12-22T02:21:42.171Z (about 2 months ago)
- Topics: crystal, crystal-lang, seo, seo-optimization, slug, slug-generator, slugify
- Language: Crystal
- Homepage: https://github.com/dcalixto/friendly_id
- Size: 4.17 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# FriendlyId
A Crystal shard for creating human-readable URLs and slugs. FriendlyId lets you create pretty URLs and slugs for your resources, with support for history tracking and customization.
[![Crystal Test](https://github.com/dcalixto/friendly_id/actions/workflows/crystal-test.yml/badge.svg?branch=master)](https://github.com/dcalixto/friendly_id/actions/workflows/crystal-test.yml)
## Installation
1. Add the dependency to your `shard.yml`:
```yaml
dependencies:
friendly_id:
github: dcalixto/friendly_id
```> [!NOTE]
> Make sure your database table has a slug column:```yaml
ALTER TABLE posts ADD COLUMN slug VARCHAR;
```2. Run
```yaml
shards install
```Generate and run the required migrations:
```crystal
crystal ../friendly_id/src/friendly_id/install.cr
```This will create the necessary database tables and indexes for FriendlyId to work:
```crystal
CREATE TABLE friendly_id_slugs (
id BIGSERIAL PRIMARY KEY,
slug VARCHAR NOT NULL,
sluggable_id BIGINT NOT NULL,
sluggable_type VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```## Setup
Configure FriendlyId in your application:
> [!NOTE]
> set a initializer # friendly_id.cr```crystal
require "friendly_id"
FriendlyId.configure do |config|
config.migration_dir = "db/migrations"
end
```Update your model's save method to include the `generate_slug` method:
```crystal
class Post
include FriendlyId::Slugged
friendly_id :title
# Model-level slug generation
def save
generate_slug # Generate the slug before saving
@updated_at = Time.utcif id
@@db.exec <<-SQL, title, slug, body, user_id, created_at, updated_at, id
UPDATE posts
SET title = ?, slug = ?, body = ?, user_id = ?, created_at = ?, updated_at = ?
WHERE id = ?
SQL
else
@@db.exec <<-SQL, title, slug, body, user_id, created_at, updated_at
INSERT INTO posts (title, slug, body, user_id, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?)
SQL
end
self
end
end```
Or Update your controller save method to include the `generate_slug` method:
```crystal
class PostsController
def create(env)
title = env.params.body["title"]
body = env.params.body["body"]
user_id = current_user(env).idpost = Post.new(
title: title,
body: body,
user_id: user_id
)# Controller-level slug generation
post.generate_slug # Generate the slug before savingif post.save
env.redirect "/posts/#{post.slug}"
else
env.redirect "/posts/new"
end
end
end
```## Usage
Basic Slugging
```crystal
class Post
include FriendlyId::Slugged
include FriendlyId::Findersproperty id : Int64?
property title : String
property slug : String?
endpost = Post.new("Hello World!")
post.slug # => "hello-world"
```The Slug is Update Automatically
```crystal
post = Post.new("Hello World!")
post.save
puts post.slug # => "hello-world"post.title = "Updated Title"
post.save
puts post.slug # => "updated-title"```
With History Tracking
```crystal
class Post
include FriendlyId::Slugged
include FriendlyId::Historyproperty id : Int64?
property title : String
property slug : String?def initialize(@title)
end
endpost = Post.new("Hello World!")
post.save
post.slug # => "hello-world"post.title = "Updated Title"
post.save
post.slug_history # => ["hello-world"]
```Using a Custom Attribute
```crystal
class User
include FriendlyId::Sluggedproperty id : Int64?
property name : String
property slug : String?
friendly_id :name # Use name instead of title for slugsdef initialize(@name); end
enduser = User.new("John Doe")
user.save
puts user.slug # => "john-doe"
```## Friendly ID Support
The `FriendlyId::Finders` module provides smart URL slug handling with ID and Historical Slug fallback:
### lookup records by:
- Current slug
- Numeric ID
- Historical slugs```crystal
class Post
include FriendlyId::Finders
end```
Finding Records
```crystal
# All these will work:
Post.find_by_friendly_id("my-awesome-post") # Current slug
Post.find_by_friendly_id("123") # ID
Post.find_by_friendly_id("old-post-slug") # Historical slug
# Regular find still works
post = Post.find(1)
```## Configuration
```crystal
def should_generate_new_friendly_id?
title_changed? || slug.nil?
end
``````crystal
class Post
include DB::Serializable
include FriendlyId::Slugged
include FriendlyId::Finders
include FriendlyId::History# ... your existing code ...
def should_generate_new_friendly_id?
title_changed? || slug.nil?
end
end
```### Custom Slug Generation
```crystal
class Post
include FriendlyId::Slugged
def normalize_friendly_id(value)
value.downcase.gsub(/\s+/, "-")
end
end
```## URL Helpers
To use friendly URLs in your controller, include the `FriendlyId::UrlHelper` module:
```crystal
# In your Controller
include FriendlyId::UrlHelper
``````crystal
<%= post.title %>
```## Features
- Slug generation from specified fields
- SEO-friendly URL formatting
- History tracking of slug changes
- Custom slug normalization
- Special character handling
- Database-backed slug storageRun tests
```crystal
crystal spec```
## Contributing
1. Fork it
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create a new Pull RequestContributors
Daniel Calixto - creator and maintainer
## License
MIT License. See LICENSE for details.
```
```