Convert Figma logo to code with AI

luckyframework logolucky

A full-featured Crystal web framework that catches bugs for you, runs incredibly fast, and helps you write code that lasts.

2,697
171
2,697
96

Top Related Projects

6,353

A flexible framework for maintainable Ruby apps

Use Turbo in your Ruby on Rails app

The advanced business logic framework for Ruby.

Padrino is a full-stack ruby framework built upon Sinatra.

Quick Overview

Lucky is a full-featured web application framework written in Crystal. It aims to be fast, secure, and maintainable, with a focus on developer productivity and happiness. Lucky leverages Crystal's type system to catch errors at compile-time and provides a set of tools for building robust web applications.

Pros

  • Strong type safety, catching many errors at compile-time
  • High performance due to Crystal's speed and Lucky's optimizations
  • Built-in security features like CSRF protection and secure defaults
  • Intuitive and expressive DSL for routing, database queries, and HTML generation

Cons

  • Smaller ecosystem compared to more established frameworks like Ruby on Rails
  • Limited hosting options due to Crystal's relative newness
  • Steeper learning curve for developers not familiar with Crystal
  • Less documentation and community resources compared to more popular frameworks

Code Examples

  1. Defining a route and action:
class Home::Index < BrowserAction
  get "/" do
    plain_text "Hello, World!"
  end
end
  1. Creating a database query:
class UserQuery < User::BaseQuery
  def recently_active
    created_at.gte(1.week.ago)
  end
end

recent_users = UserQuery.new.recently_active
  1. Generating HTML with Lucky's view syntax:
class Users::IndexPage < MainLayout
  needs users : UserQuery

  def content
    h1 "Users"
    ul do
      @users.each do |user|
        li user.name
      end
    end
  end
end

Getting Started

  1. Install Crystal and Lucky CLI:

    brew install crystal
    brew install lucky
    
  2. Create a new Lucky project:

    lucky init my_app
    cd my_app
    
  3. Set up the database:

    lucky db.create
    lucky db.migrate
    
  4. Start the server:

    lucky dev
    

Your Lucky application is now running at http://localhost:3000.

Competitor Comparisons

6,353

A flexible framework for maintainable Ruby apps

Pros of Hanami

  • More mature and established framework with a larger community
  • Modular architecture allowing for flexible application structure
  • Comprehensive documentation and guides for developers

Cons of Hanami

  • Steeper learning curve due to its modular nature
  • Slower development pace compared to Lucky
  • Less focus on type safety and compile-time checks

Code Comparison

Hanami route definition:

# config/routes.rb
root to: 'home#index'
resources :books, only: [:index, :show]

Lucky route definition:

# src/actions/home/index.cr
class Home::Index < BrowserAction
  get "/" do
    html IndexPage
  end
end

Hanami emphasizes convention over configuration, while Lucky leverages Crystal's type system for enhanced safety and performance. Hanami's modular approach allows for more flexibility in application structure, whereas Lucky focuses on a more opinionated, streamlined development experience.

Both frameworks aim to provide efficient web development tools, but they cater to different preferences and priorities. Hanami offers a mature ecosystem with extensive documentation, while Lucky emphasizes compile-time safety and rapid development through Crystal's features.

Use Turbo in your Ruby on Rails app

Pros of Turbo Rails

  • Seamless integration with Ruby on Rails, leveraging existing Rails knowledge
  • Extensive documentation and large community support
  • Easy to implement progressive enhancement for existing Rails applications

Cons of Turbo Rails

  • Limited to Ruby on Rails framework, less flexible for other backend technologies
  • May require more JavaScript knowledge for advanced features
  • Performance can be affected by the overhead of Rails

Code Comparison

Lucky (Crystal):

class Users::Index < BrowserAction
  get "/users" do
    users = UserQuery.new.recently_added
    html Users::IndexPage, users: users
  end
end

Turbo Rails (Ruby):

class UsersController < ApplicationController
  def index
    @users = User.recently_added
  end
end

Key Differences

  • Lucky is built with Crystal, offering type safety and high performance
  • Turbo Rails focuses on enhancing existing Rails applications with modern SPA-like features
  • Lucky provides a more opinionated, full-stack framework approach
  • Turbo Rails is part of the Hotwire ecosystem, integrating well with other Hotwire libraries

Use Cases

  • Choose Lucky for building high-performance, type-safe web applications from scratch
  • Opt for Turbo Rails when enhancing existing Rails applications or prioritizing Rails ecosystem compatibility

The advanced business logic framework for Ruby.

Pros of Trailblazer

  • Modular architecture allows for flexible implementation across different frameworks
  • Provides a comprehensive set of abstractions for business logic and domain modeling
  • Supports complex workflows and multi-step operations with built-in state management

Cons of Trailblazer

  • Steeper learning curve due to its extensive set of concepts and abstractions
  • Can introduce additional complexity for simpler applications
  • Less opinionated about database interactions and ORM usage

Code Comparison

Lucky (Crystal):

class Users::Index < BrowserAction
  get "/users" do
    users = UserQuery.new.recently_created
    html Users::IndexPage, users: users
  end
end

Trailblazer (Ruby):

class Users::Index < Trailblazer::Operation
  step :fetch_users
  step :render

  def fetch_users(ctx, **)
    ctx[:users] = User.recently_created
  end

  def render(ctx, users:, **)
    # Rendering logic here
  end
end

Lucky focuses on a more traditional MVC approach with built-in database querying and view rendering. Trailblazer, on the other hand, emphasizes separation of concerns and explicit step definitions for business logic. Lucky provides a more streamlined development experience for typical web applications, while Trailblazer offers greater flexibility and scalability for complex domain logic.

Padrino is a full-stack ruby framework built upon Sinatra.

Pros of Padrino

  • Mature and well-established framework with a larger community and ecosystem
  • Modular architecture allows for flexible and customizable application structure
  • Supports multiple ORMs, testing frameworks, and template engines

Cons of Padrino

  • Less active development compared to Lucky (last commit over a year ago)
  • Older technology stack, potentially lacking modern features and optimizations
  • Steeper learning curve due to its extensive feature set and flexibility

Code Comparison

Lucky (Crystal):

class Users::Index < BrowserAction
  get "/users" do
    users = UserQuery.new.recently_created
    html Users::IndexPage, users: users
  end
end

Padrino (Ruby):

MyApp.controllers :users do
  get :index do
    @users = User.recently_created
    render 'users/index'
  end
end

Summary

Lucky is a modern web framework written in Crystal, focusing on type safety and performance. It offers a more opinionated structure and leverages Crystal's compile-time checks for enhanced reliability.

Padrino is a Ruby web framework that extends Sinatra, providing a full-stack alternative to Ruby on Rails. It offers more flexibility and modularity but may require more configuration and decision-making from developers.

Both frameworks aim to simplify web development, but Lucky's type system and performance optimizations make it attractive for developers prioritizing speed and reliability. Padrino's maturity and extensive ecosystem make it suitable for developers who need more flexibility and are comfortable with Ruby.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

github banner-short

Version License

API Documentation Website Lucky Guides Website

Discord

The goal: prevent bugs, forget about most performance issues, and spend more time on code instead of debugging and fixing tests.

In summary, make writing stunning web applications fast, fun, and easy.

Coming from Rails?

Try Lucky

Lucky has a fresh new set of guides that make it easy to get started.

Feel free to say hi or ask questions on our chat room.

Or you can copy a real working app with Lucky JumpStart.

Installing Lucky

To install Lucky, read the Installing Lucky guides for your Operating System. The guide will walk you through installing a command-line utility used for generating new Lucky applications.

Keep up-to-date

Keep up to date by following @luckyframework on Twitter.

Documentation

API (main)

What's it look like?

JSON endpoint:

class Api::Users::Show < ApiAction
  get "/api/users/:user_id" do
    user = UserQuery.find(user_id)
    json UserSerializer.new(user)
  end
end
  • If you want you can set up custom routes like get "/sign_in" for non REST routes.
  • A user_id method is generated because there is a user_id route parameter.
  • Use json to render JSON. Extract serializers for reusable JSON responses.

Database models

# Set up the model
class User < BaseModel
  table do
    column last_active_at : Time
    column last_name : String
    column nickname : String?
  end
end
  • Sets up the columns that you’d like to use, along with their types
  • You can add ? to the type when the column can be nil . Crystal will then help you remember not to call methods on it that won't work.
  • Lucky will set up presence validations for required fields (last_active_at and last_name since they are not marked as nilable).

Querying the database

# Add some methods to help query the database
class UserQuery < User::BaseQuery
  def recently_active
    last_active_at.gt(1.week.ago)
  end

  def sorted_by_last_name
    last_name.lower.desc_order
  end
end

# Query the database
UserQuery.new.recently_active.sorted_by_last_name
  • User::BaseQuery is automatically generated when you define a model. Inherit from it to customize queries.
  • Set up named scopes with instance methods.
  • Lucky sets up methods for all the columns so that if you mistype a column name it will tell you at compile-time.
  • Use the lower method on a String column to make sure Postgres sorts everything in lowercase.
  • Use gt to get users last active greater than 1 week ago. Lucky has lots of powerful abstractions for creating complex queries, and type specific methods (like lower).

Rendering HTML:

class Users::Index < BrowserAction
  get "/users" do
    users = UserQuery.new.sorted_by_last_name
    render IndexPage, users: users
  end
end

class Users::IndexPage < MainLayout
  needs users : UserQuery

  def content
    render_new_user_button
    render_user_list
  end

  private def render_new_user_button
    link "New User", to: Users::New
  end

  private def render_user_list
    ul class: "user-list" do
      users.each do |user|
        li do
          link user.name, to: Users::Show.with(user.id)
          text " - "
          text user.nickname || "No Nickname"
        end
      end
    end
  end
end
  • needs users : UserQuery tells the compiler that it must be passed users of the type UserQuery.
  • If you forget to pass something that a page needs, it will let you know at compile time. Fewer bugs and faster debugging.
  • Write tags with Crystal methods. Tags are automatically closed and whitespace is removed.
  • Easily extract named methods since pages are made of regular classes and methods. This makes your HTML pages incredibly easy to read.
  • Link to other pages with ease. Just use the action name: Users::New. Pass params using with: Users::Show.with(user.id). No more trying to remember path helpers and whether the helper is pluralized or not - If you forget to pass a param to a route, Lucky will let you know at compile-time.
  • Since we defined column nickname : String? as nilable, Lucky would fail to compile the page if you just did text user.nickname since it disallows printing nil. So instead we add a fallback "No Nickname". No more accidentally printing empty text in HTML!

Testing

You need to make sure to install the Crystal dependencies.

  1. Run shards install
  2. Run crystal spec from the project root.

Contributing

See CONTRIBUTING.md

Lucky to have you!

We love all of the community members that have put in hard work to make Lucky better. If you're one of those people, we want to give you a t-shirt!

To get a shirt, we ask that you have made a significant contribution to Lucky. This includes things like submitting PRs with bug fixes and feature implementations, helping other members work through problems, and deploying real world applications using Lucky!

To claim your shirt, fill in this form.

Contributors

paulcsmith Paul Smith - Original Creator of Lucky

Made with contrib.rocks.

Thanks & attributions

  • SessionHandler, CookieHandler and FlashHandler are based on Amber. Thank you to the Amber team!
  • Thanks to Rails for inspiring many of the ideas that are easy to take for granted. Convention over configuration, removing boilerplate, and most importantly - focusing on developer happiness.
  • Thanks to Phoenix, Ecto and Elixir for inspiring Avram's save operations, Lucky's single base actions and pipes, and focusing on helpful error messages.
  • lucky watch based heavily on Sentry. Thanks @samueleaton!