From Rails to Erlyweb - Part I
Updated July 20 2007: new params.erl which uses dict to store params and converts to proper type(integer/float/string)
It's time to migrate our project from Rails to Erlyweb (It cost me one month to write an Erlang IDE before this happens :-)). I'll blog some tips of the procedure, focus on the differences between Rails and erlyweb.
1.How to handle params
Rails:page = params.fetch(:p, 1).to_i size = params.fetch(:s, @@RECORDS_PER_PAGE).to_iErlyweb:
-module(mymodel_controller)..
-define(RECORDS_PER_PAGE, 9).
list(A) ->
P = params:from_yaws_arg(A)
Page = params:get("p", P, 1), %% return integer
Size = params:get("s", P, ?RECORDS_PER_PAGE),
....
You can also
Id = params:get("id", P, integer) %% return integer()
Id = params:get("id", P) %% return string()
%% Or, pass a fun to return the converted result
Id = params:get("id", P, fun string:to_integer/1)
To get the above code working, I wrote a params.erl and placed under folder: apps\myapp\lib.
-module(params).
-export([
from_yaws_arg/1,
from_list/1,
get_page_opts/1,
get_page_extras/1,
get/2,
get/3,
get/4,
convert/2,
put/3,
join/1
]).
%% @doc Convert yaws Arg#arg.querydata into a {key,value} stored in a dynamic hash.
from_yaws_arg(Arg) ->
Params = yaws_api:parse_query(Arg),
dict:from_list(Params).
from_list(PropsList) ->
dict:from_list(PropsList).
get_page_opts(Dict) ->
[{page, get("p", Dict, 1)},
{page_size, get("s", Dict, ?DEFAULT_PAGESIZE)}].
get_page_extras(Dict) ->
Page = get("p", Dict, 1),
Size = get("s", Dict, ?DEFAULT_PAGESIZE),
Offset = (Page - 1) * Size,
[{limit, Offset, Size}].
get(Key, Dict) ->
get(Key, Dict, undefined).
%% @spec get(Key::term(), Arg:yawsArg(), Default::term() -> string()
get(Key, Dict, Fun) when is_function(Fun) ->
case get(Key, Dict, undefined) of
undefined -> undefined;
Value -> Fun(Value)
end;
get(Key, Dict, Type) when is_atom(Type) andalso Type /= undefined ->
get(Key, Dict, undefined, Type);
get(Key, Dict, Default) ->
case dict:find(Key, Dict) of
{ok, Value} when is_list(Default) -> convert(Value, string);
{ok, Value} when is_integer(Default) -> convert(Value, integer);
{ok, Value} when is_float(Default) -> convert(Value, float);
{ok, Value} -> Value;
error -> Default
end.
get(Key, Dict, Default, Type) ->
Value = get(Key, Dict, Default),
convert(Value, Type).
convert(Value, _Type) when Value == undefined -> undefined;
convert(Value, Type) ->
try
case Type of
integer when is_list(Value) -> list_to_integer(Value);
integer when is_integer(Value) -> Value;
integer when is_float(Value) -> erlang:round(Value);
float when is_list(Value) -> list_to_float(Value);
float when is_integer(Value) -> Value * 1.0;
float when is_float(Value) -> Value;
string when is_list(Value) -> Value;
string when is_integer(Value) -> integer_to_list(Value);
string when is_float(Value) -> float_to_list(Value);
number when is_list(Value) andalso Value /= "" andalso Value /= "NaN" ->
case string:chr(Value, $.) > 0 of
true -> list_to_float(Value);
false -> list_to_integer(Value)
end;
number when is_integer(Value) -> Value;
number when is_float(Value) -> Value
end
catch error:_ ->
undefined
end.
put(Key, Value, Dict) ->
dict:store(Key, Value, Dict).
join(Params) ->
ParamPairedStrs =
dict:fold(
fun (Key, Value, Acc) ->
[Key ++ "=" ++ yaws_api:url_encode(Value)|Acc]
end, [], Params),
%% Join params string with "&": ["a=a1", "b=b1"] => "a=a1&b;=b1"
join("&", ParamPairedStrs).
%% @spec join(string(), list(string())) -> string()
join(String, List) -> join(String, List, []).
join(_String, [], Joined) -> Joined;
join(String, [H|[]], Joined) -> join(String, [], Joined ++ H);
join(String, [H|T], Joined) -> join(String, T, Joined ++ H ++ String).
![(please configure the [header_logo] section in trac.ini)](/chrome/!97aa87b5/site/your_project_logo.png)
rss
Comments
this way
Thanks. I wrote Ruby code in this way for comparability only.
params.fetch(:p, 1).to_i
That's better. Thanks.