
www.youtube.com/watch?v=NisCkxU544cAfter watching the presentation of Yuri (
yrashk ) with Erlang Conference about web frameworks in Erlang, I became interested and decided to make saytik not on node.js, as I originally intended, but using some Erlang framework.
In the end, I came across a
Chicago Boss framework. I have heard about the framework myself before, but I havenāt been able to use it yet.
')
What does the boss give us? In general, they position themselves as ārails-type, but on an erlang.ā With the rails, by the way, I also didnāt have anything at all, so I didnāt care. But Iāve dealt with MVC because at work we have a solid ASP.NET MVC2. So the basic concepts are clear.
BossDB is available; it is, in fact, ActiveRecord, written using parameterized modules, supporting different backends. Memory, Mnesia, MongoDB, MySQL, Postgres. According to the
developers, to support the new database, you need to write about three hundred lines of code.
There are Django Templates, with almost full coverage of all features, filters, and more.
There are other things that I havenāt really played with yet ...
Installation
With the installation on ubunt there was a small problem that is treated by downloading the old version of erlang and copying one header file from there (lib / kernel / src / inet_dns.hrl), which for some reason is missing from the ubuntov delivery; still had to put the erlang-dev package.
After this is done
make make app NewSite cd ../NewSite
Getting to understand ...
In principle, there is a good tutorial
An Evening with Chicago Boss . But it is a little outdated, and slightly does not correspond to the realities of the latest versions.
Tasks
- Write a couple of pages "for all"
- Write authorization
- Write a user profile editor
Project structure
/controller /view /model /log /static /test
all three are clear
/admin - , / , /ebin - , /lang - . /lib - , . /mail - ,
If you run the project through ./start-dev.sh, then the boss will do a hot reboot of the whole machine, so you can develop it without restarting the server, which is very convenient.
Model
Model APIThe model is a parameterized erlang module, a specific thing, I don't know much about it. For now, just using it as is.
For example, user model
-module(user, [Id, FirstName, LastName, Email, PasswordHash, CreateTime]). -compile(export_all).
This is already a model. It has properties, as well as automatically generated field access methods. Properties that end in
Id or
Time are special. Some - to create links and dependencies between objects, the second will only accept tuples in a format that gives
erlang: now ()After the model code has been saved in
/models/user.erl , the admin
panel will access the list of current models and class documentation.
You can create validation methods for the model, but weāll skip this for now.
Bossdb
BossDB APIThis is an API for working with a database.
The boss stores all entries with an Id of the following form:
<model_atom> is <unique_id> , where model_atom is an atom described in the model module :), and unique_id is a numeric identifier that does not repeat even for different models, so if you have the user and article,
user-1 and
article-1 models cannot exist. Considering that the numbers in the Erlang are limited by the amount of RAM, you can not worry about id overflow :).
Of particular interest are search operations. They have a short form, writing down with mathematical symbols, such as ε, ā, ā and others.
Sampling can be done by transferring string Id records. Because it is prefixed with the model name - there will be no confusion.
User = boss_db:find("user-1").
Controller
Controller APIThe controller is also a parameterized module. But he has only one parameter. This is the field in which the http request will be located. The request has methods for accessing form fields (in the case of POST) and headers.
-module(user_controller, [Req]). -compile(export_all). index('GET', []) -> ok.
Here is a simple controller that simply renders the default template when a GET request is made to the address
/ user / indexYou can write a controller that displays the user on his Id, as well as understanding the different methods of issuance.
Parsing a URL is as follows:
-module(user_controller, [Req]). -compile(export_all). index('GET', []) -> {ok, [{users, boss_db:find(user, [])}]}; index('GET', ["id", Id, "method", Method]) -> case boss_db:find(Id) of {error, Reason} -> boss_flash:add(Req, error, "Invalid User", "User not found"), ok; {user, User} -> case Method of "json" -> {json, User}
What is going on here?
If an empty request comes to us - then find all the objects of the User model, and render the default template by passing a list of parameters to it, one of which will be users, containing all users.
If the request has id & method parameters - try to find the user by Id, in case of failure, create a boss_flash with an error message and render the template.
If the user is found then do the following ā if the method contains the string ājsonā, return the data as a JSON object. For any other method, render the HTML template with user data.
Template
Template APIuses the Django template system, through the
ErlyDTL library
For example, here is a template for our / user page.
{{boss_flash}} {% if users %} <h1>{% trans "User List" %}</h1> {% for user in users %} {% trans "First Name" %} : {{ user.first_name }}</br> {% trans "Last Name" %} : {{ user.last_name }}</br> <a href="/user/id/{{user.id}}/method/html">{% trans "View" %}</a> <a href="/user/id/{{user.id}}/method/json">{% trans "JSON" %}</a> {% endfor %} {% endif %} {% if user %} <h1>{% trans "User Info" %}</h1> {% trans "First Name" %} : {{ user.first_name }}</br> {% trans "Last Name" %} : {{ user.last_name }} {% endif %}
The
trans function will automatically translate strings. Also, all the strings for translation are automatically selected from the template files and go to the translation web interface in the admin panel. Files - regular * .po
boss_flash is a special construct for displaying temporary messages. No need to steam with sessions or passing a message through parameters or hidden fields. Very comfortably. An identical mechanism is used in validator messages in ASP.Net MVC.
Authorization
Login made cleverly. In each controller, you can write the
before_ / 1 function, which receives the name action and for it should return either a tuple
{ok, AdditionalParameters} , or
{redirect, "/ url / to / redirect"} .
Usually it is stored in a separate module in the
/ lib folder
. -module(auth_lib). -export(require_authentication/1). require_authentication(Req) -> case boss_session:get_session_data(Req, principal) of {error, Reason} -> {redirect, "/login"}; PrincipalId -> case boss_db:find(PrincipalId) of {error, Reason} -> boss_flash:add(Req, error, "User not found", Reason), {redirect, "/error"}; {user, Principal} -> {ok, Principal}
In order to use this method, the controller must have methods with three parameters
-module(protected_controller, [Req]). -compile(export_all). before_("public") -> ok;
If authentication is successful, then the current user will be passed to the third parameter. Otherwise, it will be redirected to / login.
If the user has been authenticated, but the record has disappeared from the database, it will be redirected to / error, and an error message will be added.
Now you need to write a controller to check.
-module(login_controller, [Req]). -compile(export_all). index('GET', []) -> ok; index('POST', []) -> Email = Req:post_param("email"), PasswordHash = erlang:md5(Req:post_param("password")), case boss_db:find(user, [ email = Email, password_hash = PasswordHash], 1) of {user, Principal} -> boss_session:set_session_value(Req, principal, Principal.id), {redirect, "/protected"}; {error, Reason} -> boss_flash:add(Req, error, "Invalid User"), ok end.
Note, the 'equals' character in the expression is not (ASCII =), but (UTF-8 =).Conclusion
You can still write a lot of things, but slightly tired :)
In principle, everything is written fairly quickly and fun. This is my first working Erlang code. For now, I like everything.
Note: in the article code, it is clear that mistakes, unfinished guards and other trifles. Please do not kick much, I write on the Erlang the second day.
Write in a personal, correct article.