Lucky Logo
JUNE 12, 2019

Introducing Lucky 0.15 and a brand new website to go with it.

Lucky v0.15 is a big new release. Brand new class based UI components, lots of bug fixes, and support for Crystal 0.29. We are also releasing a brand new website to go with it.

Lucky 0.15.0 has been in the making for a few months and has lots of new goodies, bug fixes, and support for the newest version of Crystal (0.29.0)

We’re also releasing a brand new website along with this new version of Lucky.

# New website

We’ve totally revamped the Lucky website. Check it out:

And the new website uses Lucky instead of Middleman 🎉

# Lucky 0.15

Lucky 0.15 contains lots of bug fixes and improvements. We’d like to highlight a few of our favorite new features.

# New class based components

You can now use classes for components. You declare what the component needs and then you can mount it on a page.

This greatly simplifies code reuse, allows you to have named private methods, and makes testing a breeze

# lucky gen.component UserRow
class UserRow < BaseComponent
  needs user : User

  def render
    div class: "user-row-style" do
      h2 @user.name
    end
  end
end

Now we can use it in a page with mount:

mount UserRow.new(UserQuery.first)

Or test it by rendering the component to a string:

user = UserQuery.first
html = UserRow.new(user.first).render_to_string
html.should contain user.name

# New built-in security features

There are now a bunch of new security headers that you can easily add and configure for your app. Check it out under our new security guide.

# Asset host for CDN

You can configure an asset host for asset paths. This makes it simple to use your CDN for fast content delivery.

Lucky::Server.configure do |settings|
  if Lucky::Env.production?
    settings.asset_host = "https://myfastcdn.com"
  else
    settings.asset_host = "/"
  end
end

# Fallback routing

You can think of this like a “catch-all” route. If no other route matches in your application, Lucky will run this as a last try. To use it, just create your action and use fallback.

This can be a great way to have Lucky pass route handling over to your front-end framework!

class VueHandlerAction < BrowserAction
  fallback do
    if html?
      html VueApp::IndexPage
    else
      raise Lucky::RouteNotFoundError.new(context)
    end
  end
end

Learn more about fallback routing

# New goodies in Avram (Lucky’s ORM)

# Introducing nilable_eq

Previously you could pass a nil value when comparing values in a query. The problem with this is that you may not be expecting to compare to nil.

Now Lucky helps make this distinction clear by only allowing eq for non-nil values and using nilable_eq for things that may be nil. This will help catch subtle nil bugs.

# 'name' might be a String or Nil
name = ["John", nil].sample

# When using 'eq' Lucky will stop at compile time and tell
# you that you are comparing to a possible 'nil' value
UserQuery.new.name.eq(name)

We can make this work by using nilable_eq or handling the nil with a conditional

name = ["John", nil].sample
UserQuery.new.name.nilable_eq(name)

# Or if we want to handle 'nil' differently
if name
  UserQuery.new.name.eq(name)
else
  raise "Oh no! There is no name"
end

# Easily generate unique data for tests

Avram Boxes are how we generate test data. This release introduces sequence for easily generating unique values.

class UserBox < Avram::Box
  def initialize
    # username-1, username-2, etc.
    username sequence("username")
    # email-1@example.com, email-2@example.com, etc.
    email "#{sequence("email")}@example.com"
  end
end

# Lots of other bug fixes and improvements

There are lots of other improvements and bug fixes in this release. Thanks to all our contributors that made this release possible!

We hope you love it!