= Getting your feet wet with ErlyWeb = We´ll start out with a very basic blog application, which will be expanded step by step. At the end of the tutorials section, you will have a working, full blown blog application and should know everything important to roll out your own applications with ErlyWeb. *Help* If you face any kind of problems, don´t hesitate to ask for help on the [http://groups.google.com/group/erlyweb mailing list] or join #erlyweb on irc.freenode.net. Assuming you already have ErlyWeb and Yaws installed, we start off making our first application. == Creating an application == Start Yaws in interactive mode (*yaws -i*) and type in the Yaws shell: {{{ erlyweb:create_app("blog", "/path/to/your/apps"). }}} This will create an ErlyWeb directory structure as well as a few files. (Note: this initial procedure will probably be shorter when ErlyWeb matures.) This is what you should see inside your apps directory: {{{ /apps/blog/ /apps/blog/ebin/ /apps/blog/src/blog_app_controller.erl /apps/blog/src/components/ /apps/blog/src/components/html_container_controller.erl /apps/blog/src/components/html_container_view.et /apps/blog/www/ /apps/blog/www/index.html /apps/blog/www/style.css }}} Edit your yaws.conf file by adding a server configuration with the following docroot, appmod, and opaque directives, then type *yaws:restart()*. {{{ docroot = /path/to/your/apps/blog/www appmods = <"/", erlyweb> appname = blog }}} Open your browser and point it at {{{ http://localhost:8000/ }}} (note: your host/port may be different, depending on your Yaws configuration). You should see the following page: [http://groups.google.com/group/erlyweb/web/blog_welcome.png http://groups.google.com/group/erlyweb/web/blog_welcome_thumb.png] Don´t give yourself a rest on your first success. Let´s move on. == Create a database and tables == Create a database called *blog* with the following tables for (depending on your choice) === MySQL === {{{ CREATE TABLE category ( id integer primary key auto_increment, title varchar(100), description text ) type=INNODB; CREATE TABLE entry ( id integer primary key auto_increment, title varchar(100), body text, created timestamp, category_id integer ) type=INNODB; }}} === PostgreSQL === {{{ CREATE TABLE category ( id SERIAL PRIMARY KEY, title VARCHAR(100), description TEXT ); CREATE TABLE entry ( id SERIAL PRIMARY KEY, title VARCHAR(100), body TEXT, created TIMESTAMP, category_id INTEGER ); }}} === Mnesia === (Not yet added) We start with two tables in our blog database, one for categories and one for entries. The tables contain a many-to-one relation, this is indicated by the category_id column in the entry table. ErlyDb follows some [http://erlyweb.org/doc/erlydb.html#Primary_and_Foreign_Key_Conventions Primary and Foreign Key Naming Conventions]. You have to know these, but can skip it for now as it will be explained later throughout the tutorials section with examples regarding our blog application. Now that the database and tables are in place take a deep breath, we´re diving into ErlyWeb. == Setting up Models, Views and Controllers == Create the following files inside your components directory: === Category === category.erl {{{ -module(category). -export([relations/0]). relations() -> [{one_to_many, [entry]}]. }}} category_controller.erl {{{ -module(category_controller). -export([detail/2, entry/2]). detail(A, Id) -> Category = category:find_id(Id), [{data, {category:title(Category), category:description(Category)}}, [{ewc, category, entry, [A, Entry]} || Entry <- category:entries(Category)] ]. entry(A, Entry) -> {data, {integer_to_list(entry:id(Entry)), entry:title(Entry), entry:body(Entry)} }. }}} category_view.et {{{ <%@ detail([{Title, Description}, Entries]) %>

<% Title %>

<% Description %>

<% Entries %> <%@ entry({Id, Title, Body}) %>

<% Title %>

<% Body %>

}}} === Entry === entry.erl {{{ -module(entry). -export([relations/0]). relations() -> [{many_to_one, [category]}]. }}} entry_controller.erl {{{ -module(entry_controller). -export([index/1, entry/2, detail/2]). index(A) -> Entries = entry:find_with({order_by, [{id, desc}]}), [{ewc, entry, entry, [A, Entry]} || Entry <- Entries]. entry(A, Entry) -> Category = entry:category(Entry), {data, {integer_to_list(entry:id(Entry)), entry:title(Entry), entry:body(Entry), integer_to_list(category:id(Category)), category:title(Category)} }. detail(A, Id) -> Entry = entry:find_id(Id), Category = entry:category(Entry), {data, {entry:title(Entry), entry:body(Entry), integer_to_list(category:id(Category)), category:title(Category)} }. }}} entry_view.et {{{ <%@ index(Entry) %>

Latest Entries

<% Entry %> <%@ entry({Id, Title, Body, Category_Id, Category_Title}) %>

<% Title %>

<% Body %>

Category: <% Category_Title %>

<%@ detail({Title, Body, Category_Id, Category_Title}) %>

<% Title %>

<% Body %>

Category: <% Category_Title %>

}}} ErlyWeb treats all Erlang modules whose names don't end with *_controller* or *_view* and whose files exist under *src/components* as models. Coming back to the many-to-one relation we previously talked about, have a look at the models to guess how its done. Controllers are implemented in Erlang source files. Views are typically implemented in ErlTL files, but views can be implemented in plain Erlang as well. The controller file is named *[ComponentName]_controller.erl* and the view file is named *[ComponentName]_view.[Extension]*, where [ComponentName] is the name of the component, and [Extension] is *erl* for Erlang files and *et* for ErlTL files. For more details about this see the api docs for [http://erlyweb.org/doc/overview-summary.html#Components Components], [http://erlyweb.org/doc/overview-summary.html#Models Models], [http://erlyweb.org/doc/overview-summary.html#Controllers Controllers] and [http://erlyweb.org/doc/overview-summary.html#Views Views]. We´ve set up our Models, Controllers and Views, so its time to start the database and compile our app. == Connect to the database and compile your app == Type this commands in the Yaws Shell for (depending on your choice) === Mysql === {{{ erlydb:start(mysql, [{hostname, "localhost"}, {username, "username"}, {password, "password"}, {database, "blog"}]). erlyweb:compile("/path/to/apps/blog", [{erlydb_driver, mysql}]). }}} === PostgreSQL === (Not yet added) === Mnesia === (Not yet added) We are nearly at the end of this tutorial, but there isn´t much to see right now, so let´s add some records. == Creating Records == While still beeing in the Yaws shell, we´ll first add some categories. {{{ Cheer = category:new(<<"Cheer">>, <<"Kermit shouts: Applause, Applause, Applause!">>). category:insert(Cheer). ErlyWeb = category:new(<<"ErlyWeb">>, <<"The Erlang Twist on Web Frameworks">>). category:insert(ErlyWeb). }}} Now we´ll add some entries with relation to a specific category, don´t forget to unbind the previously set variables with {{{f()}}}. {{{ f(). Cheer = category:find({title,'=',<<"Cheer">>}). E1 = entry:new(<<"Welcome to my new blog">>, <<"Hello World, this is my first ErlyWeb powered application. Yippie-ki-yay!">>, [], Cheer). entry:save(E1). ErlyWeb = category:find({title,'=',<<"ErlyWeb">>}). E2 = entry:new(<<"About ErlyWeb">>, <<"ErlyWeb simplifies building database-driven webapps that follow the tried and true MVC pattern using a great language with many outstanding strengths.">>, [], ErlyWeb). entry:save(E2). }}} Let´s check some ways to query the data we just created. == Explore the database api == A simple module:find() returns all records for a module. {{{ category:find(). [{category,false,1,<<"Cheer">>, <<"Kermit shouts: Applause, Applause, Applause!">>}, {category,false,2,<<"ErlyWeb">>, <<"The Erlang Twist on Web Frameworks">>}] entry:find(). [{entry,false,1,<<"Welcome to my new blog">>, <<"Hello World, this is my first ErlyWeb powered application. Yippie-ki-yay!">>, {datetime,{{2008,1,23},{21,43,42}}}, 1}, {entry,false,2,<<"About ErlyWeb">>, <<"ErlyWeb simplifies building database-driven webapps that follow the tried and true MVC p"...>>, {datetime,{{2008,1,23},{21,44,20}}}, 2}] }}} We can also insert a WHERE clause to find specific data as you have just seen while creating records for entries. {{{ category:find({title,'=',<<"Cheer">>}). }}} Using module:find_with() we can define EXTRA expressions such as ordering and limiting records. {{{ category:find_with({order_by, {id, desc}}). category:find_with([{order_by, {id, desc}}, {limit,1}]). }}} With module:find_id() we can lookup a record with the given id value. {{{ C1 = category:find_id(1). }}} You can also query for a records attributes. {{{ category:title(C1). category:description(C1). }}} Or find related records. {{{ category:entries(C1). entry:category(E1). }}} You´ll read more about the database api in full detail later. We´re done with the introduction, congratulations. == Look Ma, no hassle == Finally, you should see this screens pointing your browser to {{{ http://localhost:8000/entry }}} and browsing around. [http://groups.google.com/group/erlyweb/web/blog_first_records.png http://groups.google.com/group/erlyweb/web/blog_first_records_thumb.png] [http://groups.google.com/group/erlyweb/web/blog_first_records_category.png http://groups.google.com/group/erlyweb/web/blog_first_records_category_thumb.png] [http://groups.google.com/group/erlyweb/web/blog_first_records_entry.png http://groups.google.com/group/erlyweb/web/blog_first_records_entry_thumb.png]