Comparing Rails and Lucky: Partials
If you’re a Rails developer, you’ve likely used partials. They’re a great way of splitting up a view into many reusable parts.
Consider displaying a search form:
<nav class="main"> <%= render "search" %> </nav>
render to insert a partial with the filename
_search.html.erb. In this instance, it will render an input field and a button to fetch search results. This is especially useful when we want to use this search form all over the app.
Lucky also has the ability to reuse parts of a page, but in a slightly different way. These differences make for a more streamlined and safe approach.
Lucky will generate HTML programmatically rather than with templates. For example:
def content nav class: "main" do h1 "My Awesome App" link "Sign In", to: Users::New end end
This gets converted into HTML. It’s a fresh change of pace from flipping back and forth between regular HTML and Ruby. But rendering partials is even nicer. Partials in Lucky are called Components. Here’s how to use one.
src/components/searches/search_component.cr you would create a module:
module Searches::SearchComponent def render_search(search_form : SearchForm) form_for Searches::New do text_input search_form.query submit "Search" end end end
This is the same as our
_search.html.erb partial in Rails. If we wanted to use this on a page, we can include our new module and call the
include Searches::SearchComponent needs search_form : SearchForm def content nav class: "main" do h1 "My Awesome App" render_search @search_form link "Sign In", to: Users::New end end
This looks a lot like rendering a partial in Rails and the result is very similar. The big difference here is Lucky is written with Crystal which uses type checking. Type checking ensures that the only way to call a method is by passing all arguments.
render_search method requires a
SearchForm object. Because of type checking, there is no way to call that method unless we pass a
Compare this to the Rails
render method. We can’t guarantee a
SearchForm will always be available to the partial. I’ll bet that anyone who has worked with Rails for a year or more has experienced this pain.
Lucky makes it impossible to forget these required objects. If we left out
@search_form above, the app won’t even compile, let alone crash when running.
Put another way, to use a partial or component we need some kind of identifier. In the case of Rails, the only identifier is the file name, not the objects that are used inside of it. In the case of Lucky, it’s the name of the method and the objects you pass to it, including the objects that are used inside. If you can’t pass all the objects every time, the app will refuse to compile.
Of course, we can (and should!) use this technique often:
render_search(@search_form) render_sign_in(@sign_in_form) banner(@annoucments) user_list(@users)
I haven’t decided on the best way to name these. They could all be
display and are only differentiated by their method arguments. Or maybe they’re all verbose like
render_search_form. Or maybe something else! I haven’t settled on the best pattern for this, yet.
One thing that comes up over and over again when working with Lucky is safety. As wonderful as Rails is, we can often find ourselves rendering a view with a
nil or incomplete object. Since Lucky has Crystal as its foundation, it’s a much safer framework to work with than Rails. With safety comes benefits like fewer crashes and unwanted side-effects. But it also enables flexibility and developer confidence.