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 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)

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!