Monday, December 11, 2006

ErlyWeb Tutorial Part 2

I have been looking forward to getting back to adding to this tutorial, but I have not had the chance the past few days. Now that I have a little time, I can jump in and finish the tutorial. What this part of the tutorial will address is the edit functionality for our blog application. Taking a hint from the CRUD functions that is in ErlyWeb, I will do something similar.

(Tip for Erlang newbies: use m(module_name) to find out about what functions are exported from a module. Very handy feature!)

ErlyDB looks like a smart fellow, because it knows that, despite using basic tuples, can figure out if the data is in the database or not. It probably isn't anything special, and Yariv will probably agree (since he wrote it), but it is interesting nonetheless.

I said this for a reason. We can similify our code, transforming the functionality in new_post/1 into something that calls a generic function, new_or_edit/2, which will also handle post editing. This is possible because ErlyDB saves records with same function.

In your entries_controller.erl file, get rid of the new_post/1 function, and then stick this in:


new_post(Vals) ->
Entry = entries:set_fields_from_strs(entries:new(), Vals),
new_or_edit(Entry, Vals).


We exported most of the logic that was in new_post/1 into new_or_edit/2. Put the new_or_edit/2 function in:



new_or_edit(Entry, Vals) ->
EntryV = entries:set_fields_from_strs(Entry, Vals),
Errors = helpers:validate(entries_validate, entries, EntryV),

case Errors of
ok ->
entries:save(EntryV),
{ok, EntryV};
_ ->
{Errors, EntryV}
end.



It is a fact that this function applies to both creating a new entry and editing an entry. This is true because what we are going to show now, with the edit functionality. Put this code in:


%% Edit functions.

edit(A, Id) ->
case yaws_arg:method(A) of
'GET' ->
{data, {"", edit_get(Id)}};
'POST' ->
Vals = yaws_api:parse_post(A),
{Errors, Entry} = edit_post(Vals, Id),
case Errors of
ok ->
{ewr, entries, index};
_ ->
{data, {Errors, Entry}}
end
end.


edit_get(Id) ->
Entry = entries:find_id(Id),
Entry.

edit_post(Vals, Id) ->
Entry = entries:find_id(Id),
new_or_edit(Entry, Vals).



WAIT A MINUTE! We are doing almost the same thing that is being done in our new function! Time to do some parameterization, to get rid of that look of cut-and-paste yuckiness. Look at where the differences are ... The function that is called to get an entry in "GET" and possibly, the space where we do a redirect. Let's add a library function! But, for you neophytes to functional programming ... we are going to use higher-order functions.

Here is the generic function:



form_process(A,
GetAction,
ModelAction,
PostSuccessAction,
PostFailureAction) ->
case yaws_arg:method(A) of
'GET' ->
GetAction();
'POST' ->
Vals = yaws_api:parse_post(A),
{Errors, Record} = ModelAction(Vals),
case Errors of
ok ->
PostSuccessAction();
_ ->
PostFailureAction(Errors, Record)
end
end.


Essentially, the form_process/5 function is just a generalization of what we have been doing before. Except, this time, we replaced the specific places with function calls - to functions we will define in our new/1 function.


new(A) ->
GetAction = fun() ->
{data, {[], new_get()}} end,
ModelAction = fun(Vals) ->
new_post(Vals) end,
PostSuccessAction = fun() ->
{ewr, entries, index} end,
PostFailureAction = fun(Errors, Entry) ->
{data, {Errors, Entry}} end,

form_process(A, GetAction, ModelAction, PostSuccessAction, PostFailureAction).


and then edit/1:


edit(A, Id) ->
GetAction = fun() ->
{data, {[], edit_get(Id)}} end,
ModelAction = fun(Vals) ->
edit_post(Vals, Id) end,
PostSuccessAction = fun() ->
{ewr, entries, index} end,
PostFailureAction = fun(Errors, Entry) ->
{data, {Errors, Entry}} end,

form_process(A, GetAction, ModelAction, PostSuccessAction, PostFailureAction).



(NOTE! For some weird reason, when I am running new/1 through the browser, and hit submit, it takes a bit too long to load. Is this a bug in my code? edit/1, though, works like a charm. Go figure.)

So, we developed a pattern using common code and, more importantly, a common convention, meaning a common set of expectations. There is nothing grandiose about the convention, and yes, you can completely ignore it. The lines of code in my function is not my concern, but whether or not I can make the code more declarative, in the sense that I say "do this in this location, do this in this other location." But, I am thinking that the code there can be tightened up even more.

In your entries_view.erl file, add these functions:


new(Data) ->
entry_form:display_form(Data, "../new", "").

edit(Data) ->
entry_form:display_form(Data, "../edit",
integer_to_list(entries:id(element(2,Data)))).


Yep, we are using the same form for editing and displaying. However, we made a change. I needed to make the action in the form generic. So the new parameters represent the url to go to. I moved the form to its own module, in a file called "entry_form.et" - I am going for some sense of template organization, by putting one page per ErlTL file. But, I originally put it in "entries_show.et". Note the changes I made with the parameters. Here is the new lines:

<%@ display_form(Items, GoTo, Id) %>

and

< form action="<% GoTo %>/<% Id %>" method="POST" >


We also want to make a small addition, by adding a "view" function. This one is quite simple. In your entries_controller.erl file, add this function:


view(A, Id) ->
Entry = get_entry(Id),
{data, Entry}.


In your entries_view.erl file, add this function:


view(Data) ->
entry_view:view(Data).


Add a file called "entry_view.et" for the view, and add this to the file:


<%@ view(Data) %>
< b><% entries:title(Data) %>< /b>
< br />< br />
<% entries:body(Data) %>
< br />

< i>by: <% entries:author(Data) %>< /i>
< br />< br />
<% erlyweb_html:a(["../edit", integer_to_list(entries:id(Data))], "Edit Entry") %>


Maybe, also, add a link to the view in your entries_show.et file.


<% erlyweb_html:a(["view", integer_to_list(entries:id(Entry))], "view") %>


Put it in your entry/1 function in the template.

Also, maybe you can finish off the show_entries/1 function in the same template file with a link to the new entry form. I'm lazy - you do it yourself. :)

Now, go to Yaws, type "start:boot()" and go to your index page. All of the elements should be visible. Is it? Any problems? If there is, this is a good time to learn what Erlang is saying to you. :P Now, if there is a problem in the tutorial, do contact me.

7 Comments:

Anonymous Anonymous said...

The code of "ErlyWeb Tutorial" can download?

8:10 AM  
Blogger 梦中林 said...

When the Wow Gold wolf finally found the Buy Wow Goldhole in the chimney he crawled wow gold cheap down and KERSPLASH right into that kettle of water and that was cheapest wow gold the end of his troubles with the big bad wolf.
The next day the cheap wow gold little pig invited his mother over . She said "You see it is just as mygamegoldI told you. The way to get along in the world is to do world of warcraft gold things as well as you can." Fortunately for that little pig, he buy cheap wow gold learned that lesson. And he just k4gold lived happily ever after!

4:34 AM  
Blogger 梦中林 said...

When the Wow Gold wolf finally found the wow gold cheap hole in the chimney he crawled cheap wow gold down and KERSPLASH right into that kettle of water and that was cheapest wow gold the end of his troubles with the big bad wolf.
The next day the Buy Wow Goldlittle pig invited hisbuy gold wow mother over . She said "You see it is just as mygamegoldI told you. The way to get along in the world is to do world of warcraft gold things as well as you can." Fortunately for that little pig, he buy cheap wow gold learned that lesson. And he just k4gold lived happily ever after!

6:27 AM  
Blogger milf said...

dessicant air dryerpediatric asthmaasthma specialistasthma children specialistcarpet cleaning dallas txcarpet cleaners dallascarpet cleaning dallas

vero beach vacationvero beach vacationsbeach vacation homes veroms beach vacationsms beach vacationms beach condosmaui beach vacationmaui beach vacationsmaui beach clubbeach vacationsyour beach vacationscheap beach vacations

bob hairstylebob haircutsbob layeredpob hairstylebobbedclassic bobCare for Curly HairTips for Curly Haircurly hair12r 22.5 best pricetires truck bustires 12r 22.5

washington new housenew house houstonnew house san antonionew house ventura

12:17 PM  
Blogger milf said...

new houston house houston house txstains removal dyestains removal clothesstains removalteeth whiteningteeth whiteningbright teeth

jennifer grey nosejennifer nose jobscalebrities nose jobsWomen with Big NosesWomen hairstylesBig Nose Women, hairstyles

12:17 PM  
Blogger milf said...

black mold exposureblack mold symptoms of exposurewrought iron garden gatesiron garden gates find them herefine thin hair hairstylessearch hair styles for fine thin hairnight vision binocularsbuy night vision binocularslipitor reactionslipitor allergic reactionsluxury beach resort in the philippines

afordable beach resorts in the philippineshomeopathy for eczema.baby eczema.save big with great mineral makeup bargainsmineral makeup wholesalersprodam iphone Apple prodam iphone prahacect iphone manualmanual for P 168 iphonefero 52 binocularsnight vision Fero 52 binocularsThe best night vision binoculars here

night vision binoculars bargainsfree photo albums computer programsfree software to make photo albumsfree tax formsprintable tax forms for free craftmatic air bedcraftmatic air bed adjustable info hereboyd air bedboyd night air bed lowest price

12:17 PM  
Blogger milf said...

find air beds in wisconsinbest air beds in wisconsincloud air beds

best cloud inflatable air bedssealy air beds portableportables air bedsrv luggage racksaluminum made rv luggage racksair bed raisedbest form raised air bedsbed air informercialsbest informercials bed airmattress sized air beds

bestair bed mattress antique doorknobsantique doorknob identification tipsdvd player troubleshootingtroubleshooting with the dvd playerflat panel television lcd vs plasmaflat panel lcd television versus plasma pic the bestadjustable bed air foam The best bed air foam

hoof prints antique equestrian printsantique hoof prints equestrian printsBuy air bedadjustablebuy the best adjustable air bedsair beds canadian storesCanadian stores for air beds

migraine causemigraine treatments floridaflorida headache clinicdrying dessicantair drying dessicant

12:18 PM  

Post a Comment

<< Home