In today tutorial, I will show you how to create an image uploader with Lotus.
You will learn:
- Create file input and multipart HTML form
- Process uploaded file request
- Good practices on making your code nice and clean
Lotus is progressing so quickly that I am afraid this post might get out-of-date quickly. I will try my best to keep it up-to-date as much as I can. For the time being, please ensure you meet following requirements:
- Lotus 0.3.1
Generate a new demo app:
The above command will generate a new lotus container with one web app that
Create Web Form
Make new controller actions
I create a new RESTful controller action
which would create a new
Web::Controllers::Images controller where we will
put our form for the image resource.
We also need
images#create controller to handle submitted form:
By default, lotus action generator generates a GET route to
tweak this route to POST by modifying the
1 2 3 4 5 6 7
Even better, we can turn our route to be RESTful resource by getting rid of our 2 existing routes and replace them with one line route:
Let’s double-check before moving on by command:
1 2 3
The output above indicates that our app now has 2 routes that we wanted :).
Besides, we should also clean up the view part of create action:
Create the upload form HTML template
We add our HTML form by modifying
1 2 3 4
Please pay attention that our
form uses POST method with action attribute points to
images#create action and encryption type is
multipart/form-data. The last
option tells Lotus that we are going to take in non-text or binary submitted data.
Additionaly, we have one input field of type file so user could choose file to upload.
Let’s give it a check, start the server first with:
http://localhost:2300/images/new and you see our new form.
Refactor upload form with lotus helpers (optional)
While we are on this template layer, I’d like to show you how to create a template helper for this upload form. Unlike Rails, Lotus has a clear separation between the controller and the presenter. In other words, Lotus’s controller does not render HTML template, but taking parsed request parameters then calling to model for processing and delgate the presentation to View class (presenter class).
We create our upload form in
Web::Views:Images class. We modify
file with following content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The example codes above indicates the inclusion of
Lotus::Helpers of which
method that we used in
Web::Views::Images#upload_form. Lotus makes writing
helpers simple, users don’t have to deal with string concatenation like Rails.
And I think you can work out how to use Helpers on yourself.
Please make sure we update our template to use our new presenter method, by
apps/web/templates/images/new.html.erb file with:
Please be noted that future version will likely introduce
Handle submitted payload in controller action
The last part of the tutorial is to handle the submitted image in controller.
We modify our
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Let’s dive in a bit, as you can see in the above code,
the uploaded file (which is now temporarily stored) and the filename. We copy this
temp file to to
apps/web/public/uploads. You can see this directory is always
get created with
mkdir_p to ensure we always have this folder setup. We could
refactor the code by having this folder created manually by hand and getting rid
of that line. Lastly, it’s a good practice to clean up tempfile :)
You can give this a test go by using the browser and try to upload file. If nothing goes wrong, you should see a new page with message filenmas has been successfully uploaded.
Refactor controller action with interactor (optional)
We could refactor our controller code to have less intimate knowledge about the file moving logic by moving those chunks of business domain logics to Service Object. Fortunately, Lotus offers Lotus::Interactor right out of the box for this scenario.
We create a new folder for our interactor:
Web::Application to load this path by modifying
1 2 3 4 5
then create our service class at
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
and change our controller to:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Interactor returns a result object after calling
#call. The result object
will determine the success of the usecase by checking if there is any errors.
If there are any, we tell controller to list them out with result errors.
As you can see, controller now only do params parsing and delegate the responsiblity to the use case object. This is a beautiful patter that I think Rails should have by default.
If you pay close attention, you can see that we do not have any codes to check for the presence of required params. If you are familiar with Rails, you might think of something similar to Strong Parameters for whitelisting params and having Service class check for the presence. With Lotus, you could easily do that within your controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
As you can see in the above code, we added new
params block. We tell Lotus to whitelist
the nested params
:image as well as check for presence of
I hope you are now familiar with the process uploading file in Lotus. Here is few key points that you should be remember:
- Create upload HTML form with POST type and
- Controller access to upload files via
- Business Logic can be extracted to Interactor class
- Params whitelisting/validation can be done within controller action
If you have any question, please do not hesitate to ask.
The sample code can be found at github.com/ruby-journal/lotus-file-upload-demo