Lucky catches bugs, returns responses quickly, and helps you write maintainable code. Lucky’s actions help you to process requests and return responses as reliably and productively as possible.

To make Lucky actions rock solid, we looked at the problems we often experience while building apps.

These issues often slow down development or cause embarrassing bugs:

Route helpers that require documentation to use and aren’t discoverable for new developers.

Incorrect or missing parameters.

Using a path that doesn’t have a corresponding route or action.

Bloated controllers.

Forgetting to render in complex conditionals.

Using the wrong HTTP verb for an action.

Renaming params or routes and forgetting to change a reference.

Lucky aims to help solve these problems with actions.

class Projects::Show < BrowserAction action do render_text "show project with id: #{ id } " end end

This class handles HTTP routing, generating paths, working with params, and sending responses.

Originally Lucky was going to use controller classes with different methods for each action, similar to Rails, Phoenix, and many other frameworks.

In the end, Lucky uses one class per action because it allows Lucky to create methods for route params, generate intuitive and type-safe route helpers, and infer routes so you don’t need a separate routes file. It also keeps the file clean and focused, which is a nice side effect.

Let’s dive into how this works in practice.

Reliability should not come at the price of productivity. Creating a single class per action means a bit more typing to set up the class, and the creation of another file. This doesn’t take that long, but it’s still extra work to both read and write.

To balance out those slowdowns, Lucky handles routing in the action itself. This means you no longer need to open a routes file, add the route, and switch back to the controller. Instead, Lucky looks at the class name to determine the RESTful route for you. For example Users::Show handles GET requests at "/users/:id" and Users::Delete handles DELETE requests at /users/:id .

This means less typing, less reading, and no switching to route files to figure out what’s going on.

Don’t worry, Lucky can also handle nested resources, namespaces, and custom routes like “/dashboard”. See more in depth examples in the guides.

Because the action knows which route it handles, it will generate route helpers. So instead of using route helpers like new_admin_projects_path(project.id) in Rails, you’d do this in Lucky: Admin::Projects::New.with(project.id)

You use the name of the action and pass the necessary params. This is really nice in link and redirect helpers:

link "New message in this project" , to: Admin :: Projects :: New . with ( project . id )

Lucky will also help guide you toward the right parameters. If you try to pass the wrong params or misspell something, Lucky will let you know:

link "New message in this project" , to: Admin :: Projects :: Messages :: New . with ( project . id ) # You'll see a compile-time error like this Expected 2 arguments to Admin :: Projects :: Messages :: New #with Overloads are: Admin :: Projects :: Messages :: New #with(project_id, id)

This may not be as helpful to experienced devs, but it is extra helpful to new developers. It’s easier to remember, and Lucky will help you find the right way to do things.

One of the more annoying issues I’ve run into is using the right path, but the wrong HTTP method.

Here’s an example in Rails for deleting a comment:

link_to "Delete" , comment_path ( @comment )

Can you spot the issue? The path is right, but I forgot to specify the HTTP verb. This is especially confusing for team members that are new to web development or REST.

In Lucky, the HTTP verb is automatically used in links, forms, and buttons. You never have to even think about it. It just works.

# The right verb (delete) is automatically set for you link "Delete comment" , to: Comment :: Delete . with ( @comment . id )

I was working on a project where we handled the request differently based on a number of conditionals. It looked something like this:

# Simplified for this example def new if user . present? && sso_enabled? redirect_to saml_provider_login_url elsif user . present? && ! sso_enabled? flash [ :error ] = "This email address does not have SSO enabled" redirect_to :back end end

Can you spot the error? There is no final else so Rails tries to render the default view for this action. This was not something we tested for or expected so we didn’t add a view and we got a failure in production.

In Lucky, actions must return a response. So if you did something like this in Lucky:

class MyAction < BrowserAction action do if user . present? && sso_enabled? redirect to: SamlProviderLogin :: New elsif user . present? && ! sso_enabled? flash . info = "This email address does not have SSO enabled" redirect to: SignIns :: New end end end

Lucky will inform you that there is a problem:

MyAction returned Lucky::Response | Nil, but it must return a Lucky::Response. Try this... ▸ Make sure to use a method like `render`, `redirect`, or `json` at the end of your action. ▸ If you are using a conditional, make sure all branches return a Lucky::Response.

This means you need to write fewer tests, and you will have fewer bugs in production.

Generating routes in the class also allows Lucky to generate methods for the params in the path.

Here’s what Lucky does for a Users::Show action:

class Users::Show < BrowserAction action do render_text "Find a user with id of: #{ id } " end end

Lucky will generate an id method for accessing the id param because it has to be there for the route to match. This means you can be 100% sure that if you call id , the param will be there.

This may not seem that helpful, but it gets nicer when you use more complex routes. For example, if you create a Projects::Messages::Index action, Lucky will create a message_id method. Now, you don’t ever need to worry about a typo in the param name, or accidentally trying to use id (which doesn’t exist for that path because it is an index). It’s a little thing, but it means you get clean looking actions and helpful errors during development.

Check out the guides to get started, or learn more about why Lucky was made.