| CODENOTIFIER | HelpYou are not signed inSign in |
Project: erlyweb
Revision: 220
Author: yarivvv
Date: 25 Dec 2007 04:34:26
Changes:documentation changes
Files:| ... | ...@@ -35,13 +35,13 @@ | |
| 35 | 35 | new() -> |
| 36 | 36 | #arg{}. |
| 37 | 37 | |
| 38 | %% @equiv Arg#arg{opaque = [Val | A#arg.opaque]}. | |
| 38 | %% @equiv Arg#arg{opaque = [Val | A#arg.opaque]} | |
| 39 | 39 | add_to_opaque(Arg, Val) -> |
| 40 | 40 | Arg#arg{opaque = [Val | Arg#arg.opaque]}. |
| 41 | 41 | |
| 42 | 42 | %% @doc applies add_to_opaque for all values in the list |
| 43 | 43 | %% |
| 44 | %% @spec add_all_to_opaque(A::arg(), Vals::[term()]) | |
| 44 | %% @spec add_all_to_opaque(A::arg(), Vals::[term()]) -> arg() | |
| 45 | 45 | add_all_to_opaque(A, Vals) -> |
| 46 | 46 | lists:foldl( |
| 47 | 47 | fun(Val, A1) -> |
| ... | ...@@ -42,6 +42,7 @@ | |
| 42 | 42 | <table width="100%" border="1"><tr><td valign="top"><a href="#connect-5">connect/5</a></td><td>Call connect/7 with Port set to 3306 and Reconnect set to 'true'.</td></tr> |
| 43 | 43 | <tr><td valign="top"><a href="#connect-7">connect/7</a></td><td>Add a connection to the connection pool.</td></tr> |
| 44 | 44 | <tr><td valign="top"><a href="#connect-8">connect/8</a></td><td>Add a connection to the connection pool, with encoding specified.</td></tr> |
| 45 | <tr><td valign="top"><a href="#connect-9">connect/9</a></td><td>Add a connection to the connection pool, with encoding specified.</td></tr> | |
| 45 | 46 | <tr><td valign="top"><a href="#execute-2">execute/2</a></td><td>Execute a statement that was previously prepared with |
| 46 | 47 | prepare/2.</td></tr> |
| 47 | 48 | <tr><td valign="top"><a href="#execute-3">execute/3</a></td><td>Execute a prepared statement with the list of parameters.</td></tr> |
| ... | ...@@ -53,7 +54,7 @@ | |
| 53 | 54 | update() function.</td></tr> |
| 54 | 55 | <tr><td valign="top"><a href="#execute_update-3">execute_update/3</a></td><td>Execute a prepared statement with the list of parameters and |
| 55 | 56 | and return the result as the the update() function.</td></tr> |
| 56 | <tr><td valign="top"><a href="#get_default_pool_name-0">get_default_pool_name/0</a></td><td>Get the default connection pool name for the driver.</td></tr> | |
| 57 | <tr><td valign="top"><a href="#get_default_pool_id-0">get_default_pool_id/0</a></td><td>Get the default connection pool name for the driver.</td></tr> | |
| 57 | 58 | <tr><td valign="top"><a href="#get_last_insert_id-2">get_last_insert_id/2</a></td><td>Get the id of the last inserted record.</td></tr> |
| 58 | 59 | <tr><td valign="top"><a href="#get_metadata-1">get_metadata/1</a></td><td>Get the table names and fields for the database.</td></tr> |
| 59 | 60 | <tr><td valign="top"><a href="#prepare-2">prepare/2</a></td><td>Register a prepared statement with the MySQL dispatcher.</td></tr> |
| ... | ...@@ -78,17 +79,28 @@ | |
| 78 | 79 | <h3><a name="connect-5">connect/5</a></h3> |
| 79 | 80 | <p><tt>connect(PoolId::atom(), Hostname::string(), Username::string(), Password::string(), Database::string()) -> ok</tt></p> |
| 80 | 81 | <p>Call connect/7 with Port set to 3306 and Reconnect set to 'true'. |
| 82 | If the connection is lost, reconnection is attempted. | |
| 83 | The connection process is linked to the calling process. | |
| 81 | 84 | </p> |
| 82 | 85 | |
| 83 | 86 | <h3><a name="connect-7">connect/7</a></h3> |
| 84 | 87 | <p><tt>connect(PoolId::atom(), Hostname::string, Port::integer(), Username::string(), Password::string(), Database::string(), Reconnect::<a href="#type-boolean">boolean()</a>) -> ok</tt></p> |
| 85 | 88 | <p>Add a connection to the connection pool. If PoolId is |
| 86 | 'undefined', the default pool, 'erlydb_mysql', is used. | |
| 89 | 'undefined', the default pool, 'erlydb_mysql', is used. The connection | |
| 90 | process is linked to the calling process. | |
| 87 | 91 | </p> |
| 88 | 92 | |
| 89 | 93 | <h3><a name="connect-8">connect/8</a></h3> |
| 90 | 94 | <p><tt>connect(PoolId::atom(), Hostname::string, Port::integer(), Username::string(), Password::string(), Database::string(), Encoding, Reconnect::<a href="#type-boolean">boolean()</a>) -> ok</tt></p> |
| 91 | 95 | <p>Add a connection to the connection pool, with encoding specified. |
| 96 | The connection process is linked to the calling process. | |
| 97 | </p> | |
| 98 | ||
| 99 | <h3><a name="connect-9">connect/9</a></h3> | |
| 100 | <p><tt>connect(PoolId::atom(), Hostname::string, Port::integer(), Username::string(), Password::string(), Database::string(), Encoding::string(), Reconnect::<a href="#type-boolean">boolean()</a>, LinkConnection::bool()) -> ok</tt></p> | |
| 101 | <p>Add a connection to the connection pool, with encoding specified. | |
| 102 | If LinkConnection == false, the connection will not be linked to the | |
| 103 | current process. | |
| 92 | 104 | </p> |
| 93 | 105 | |
| 94 | 106 | <h3><a name="execute-2">execute/2</a></h3> |
| ... | ...@@ -126,8 +138,8 @@ | |
| 126 | 138 | and return the result as the the update() function. |
| 127 | 139 | </p> |
| 128 | 140 | |
| 129 | <h3><a name="get_default_pool_name-0">get_default_pool_name/0</a></h3> | |
| 130 | <p><tt>get_default_pool_name() -> atom()</tt></p> | |
| 141 | <h3><a name="get_default_pool_id-0">get_default_pool_id/0</a></h3> | |
| 142 | <p><tt>get_default_pool_id() -> atom()</tt></p> | |
| 131 | 143 | <p>Get the default connection pool name for the driver. |
| 132 | 144 | </p> |
| 133 | 145 |
| ... | ...@@ -204,7 +204,7 @@ | |
| 204 | 204 | |
| 205 | 205 | %% @doc Get the default connection pool name for the driver. |
| 206 | 206 | %% |
| 207 | %% @spec get_default_pool_name() -> atom() | |
| 207 | %% @spec get_default_pool_id() -> atom() | |
| 208 | 208 | get_default_pool_id() -> |
| 209 | 209 | ?Epid. |
| 210 | 210 |
| ... | ...@@ -36,6 +36,9 @@ | |
| 36 | 36 | <tr><td valign="top"><a href="#get_initial_ewc-1">get_initial_ewc/1</a></td><td>Get the expanded 'ewc' tuple for the request.</td></tr> |
| 37 | 37 | <tr><td valign="top"><a href="#out-1">out/1</a></td><td>This is the out/1 function that Yaws calls when passing |
| 38 | 38 | HTTP requests to the ErlyWeb appmod.</td></tr> |
| 39 | <tr><td valign="top"><a href="#out-2">out/2</a></td><td>This function is useful for embedding the result of a 'phased' | |
| 40 | ErlyWeb rendering in an ErlyWeb component from the same application, | |
| 41 | but using a different app controller.</td></tr> | |
| 39 | 42 | </table> |
| 40 | 43 | |
| 41 | 44 | <h2><a name="functions">Function Details</a></h2> |
| ... | ...@@ -61,7 +64,10 @@ | |
| 61 | 64 | ErlyWeb also lets you define the following options:</p> |
| 62 | 65 | |
| 63 | 66 | <p>- <code>{last_compile_time, LocalTime}</code>: Tells ErlyWeb to not compile files |
| 64 | that haven't changed since LocalTime.</p> | |
| 67 | that haven't changed since LocalTime. | |
| 68 | Since ErlyWeb 0.7, you can use 'auto' for LocalTime. This | |
| 69 | instructs ErlyWeb to compile only the files that have changed since | |
| 70 | the last compilation. This is the recommended option.</p> | |
| 65 | 71 | |
| 66 | 72 | <p>- <code>{erlydb_driver, Name}</code>: Tells ErlyWeb which ErlyDB driver to use |
| 67 | 73 | when calling erlydb:code_gen on models that are placed in src/components. |
| ... | ...@@ -180,5 +186,20 @@ | |
| 180 | 186 | <p>This is the out/1 function that Yaws calls when passing |
| 181 | 187 | HTTP requests to the ErlyWeb appmod. |
| 182 | 188 | </p> |
| 189 | ||
| 190 | <h3><a name="out-2">out/2</a></h3> | |
| 191 | <p><tt>out(A::<a href="#type-arg">arg()</a>, AppController::atom()) -> term()</tt></p> | |
| 192 | <p><p>This function is useful for embedding the result of a 'phased' | |
| 193 | ErlyWeb rendering in an ErlyWeb component from the same application, | |
| 194 | but using a different app controller.</p> | |
| 195 | ||
| 196 | This function was originally designed to simplify Facebook app development | |
| 197 | with ErlyWeb using Erlang2Facebook | |
| 198 | (http://code.google.com/p/erlang2facebook). | |
| 199 | In erlang2facebook, the fb_canvas component intercepts requests | |
| 200 | from Facebook and authenticates them. After authentication, it may be | |
| 201 | useful to start a new ErlyWeb "flow" using an alternative app controller | |
| 202 | and display the result in of this flow the output of fb_canvas. | |
| 203 | </p> | |
| 183 | 204 | </body> |
| 184 | 205 | </html> |
| ... | ...@@ -84,7 +84,7 @@ | |
| 84 | 84 | fields.</td></tr> |
| 85 | 85 | <tr><td valign="top"><a href="#aggregate_related_many_to_many-7">aggregate_related_many_to_many/7</a></td><td>This function works as <a href="#aggregate_related_many_to_one-5"><code>aggregate_related_many_to_one/5</code></a>, but |
| 86 | 86 | for modules defining many-to-many relations.</td></tr> |
| 87 | <tr><td valign="top"><a href="#aggregate_related_many_to_one-6">aggregate_related_many_to_one/6</a></td><td>Get aggregate statistics about fields from related records in | |
| 87 | <tr><td valign="top"><a href="#aggregate_related_many_to_one-7">aggregate_related_many_to_one/7</a></td><td>Get aggregate statistics about fields from related records in | |
| 88 | 88 | one-to-many relations.</td></tr> |
| 89 | 89 | <tr><td valign="top"><a href="#before_delete-1">before_delete/1</a></td><td>A hook that gets called before a record is deleted.</td></tr> |
| 90 | 90 | <tr><td valign="top"><a href="#before_save-1">before_save/1</a></td><td>A hook that gets called before a record is saved.</td></tr> |
| ... | ...@@ -126,8 +126,8 @@ | |
| 126 | 126 | according to the Where and Extras expressions.</td></tr> |
| 127 | 127 | <tr><td valign="top"><a href="#find_related_many_to_many-5">find_related_many_to_many/5</a></td><td>This function works as <a href="#find_related_many_to_one-4"><code>find_related_many_to_one/4</code></a>, but |
| 128 | 128 | for modules defining many-to-many relations.</td></tr> |
| 129 | <tr><td valign="top"><a href="#find_related_many_to_one-4">find_related_many_to_one/4</a></td><td>Find the set of related records in a one-to-many relation.</td></tr> | |
| 130 | <tr><td valign="top"><a href="#find_related_one_to_many-2">find_related_one_to_many/2</a></td><td>Find the related record for a record from a module having a | |
| 129 | <tr><td valign="top"><a href="#find_related_many_to_one-5">find_related_many_to_one/5</a></td><td>Find the set of related records in a one-to-many relation.</td></tr> | |
| 130 | <tr><td valign="top"><a href="#find_related_one_to_many-3">find_related_one_to_many/3</a></td><td>Find the related record for a record from a module having a | |
| 131 | 131 | many-to-one relation.</td></tr> |
| 132 | 132 | <tr><td valign="top"><a href="#get-2">get/2</a></td><td>A generic getter function ErlyDB uses to generate getters, e.g.</td></tr> |
| 133 | 133 | <tr><td valign="top"><a href="#get_module-1">get_module/1</a></td><td>Get the name of the module to which the record belongs.</td></tr> |
| ... | ...@@ -159,7 +159,7 @@ | |
| 159 | 159 | <tr><td valign="top"><a href="#set_fields_from_strs-3">set_fields_from_strs/3</a></td><td>Equivalent to <a href="#set_fields-4"><tt>set_fields(Module, Record, Fields, |
| 160 | 160 | fun field_from_string/2)</tt></a>. |
| 161 | 161 | </td></tr> |
| 162 | <tr><td valign="top"><a href="#set_related_one_to_many-2">set_related_one_to_many/2</a></td><td>Set the foreign key fields of a record from a module having a | |
| 162 | <tr><td valign="top"><a href="#set_related_one_to_many-3">set_related_one_to_many/3</a></td><td>Set the foreign key fields of a record from a module having a | |
| 163 | 163 | many-to-one relation to the primary key values of the Other record.</td></tr> |
| 164 | 164 | <tr><td valign="top"><a href="#table-0">table/0</a></td><td>Return the name of the table that holds the records for this module.</td></tr> |
| 165 | 165 | <tr><td valign="top"><a href="#to_iolist-2">to_iolist/2</a></td><td>Equivalent to <a href="#to_iolist-3"><tt>to_iolist(Module, Recs, fun field_to_iolist/2)</tt></a>. |
| ... | ...@@ -255,8 +255,8 @@ | |
| 255 | 255 | </p> |
| 256 | 256 | <p><b>See also:</b> <a href="#aggregate_related_many_to_one-5">aggregate_related_many_to_one/5</a>.</p> |
| 257 | 257 | |
| 258 | <h3><a name="aggregate_related_many_to_one-6">aggregate_related_many_to_one/6</a></h3> | |
| 259 | <p><tt>aggregate_related_many_to_one(OtherModule::atom(), AggFunc::atom(), Rec::<a href="#type-record">record()</a>, Field::atom(), Where::<a href="#type-where_expr">where_expr()</a>, Extras::<a href="#type-extras_expr">extras_expr()</a>) -> float() | integer() | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 258 | <h3><a name="aggregate_related_many_to_one-7">aggregate_related_many_to_one/7</a></h3> | |
| 259 | <p><tt>aggregate_related_many_to_one(OtherModule::atom(), PkFks::term(), AggFunc::atom(), Rec::<a href="#type-record">record()</a>, Field::atom(), Where::<a href="#type-where_expr">where_expr()</a>, Extras::<a href="#type-extras_expr">extras_expr()</a>) -> float() | integer() | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 260 | 260 | <p><p>Get aggregate statistics about fields from related records in |
| 261 | 261 | one-to-many relations.</p> |
| 262 | 262 | |
| ... | ...@@ -583,8 +583,8 @@ | |
| 583 | 583 | </p> |
| 584 | 584 | <p><b>See also:</b> <a href="#find_related_many_to_one-4">find_related_many_to_one/4</a>.</p> |
| 585 | 585 | |
| 586 | <h3><a name="find_related_many_to_one-4">find_related_many_to_one/4</a></h3> | |
| 587 | <p><tt>find_related_many_to_one(OtherModule::atom(), Rec::<a href="#type-record">record()</a>, Where::<a href="#type-where_expr">where_expr()</a>, Extras::<a href="#type-extras_expr">extras_expr()</a>) -> [<a href="#type-record">record()</a>] | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 586 | <h3><a name="find_related_many_to_one-5">find_related_many_to_one/5</a></h3> | |
| 587 | <p><tt>find_related_many_to_one(OtherModule::atom(), PkFks::term(), Rec::<a href="#type-record">record()</a>, Where::<a href="#type-where_expr">where_expr()</a>, Extras::<a href="#type-extras_expr">extras_expr()</a>) -> [<a href="#type-record">record()</a>] | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 588 | 588 | <p><p>Find the set of related records in a one-to-many relation.</p> |
| 589 | 589 | |
| 590 | 590 | <p>This function isn't meant to be used directly; ErlyDB uses this function |
| ... | ...@@ -617,8 +617,8 @@ | |
| 617 | 617 | </p> |
| 618 | 618 | <p><b>See also:</b> <a href="#find-3">find/3</a>, <a href="#find_first-3">find_first/3</a>, <a href="#find_max-4">find_max/4</a>, <a href="#find_range-5">find_range/5</a>.</p> |
| 619 | 619 | |
| 620 | <h3><a name="find_related_one_to_many-2">find_related_one_to_many/2</a></h3> | |
| 621 | <p><tt>find_related_one_to_many(OtherModule::atom(), Rec::<a href="#type-record">record()</a>) -> <a href="#type-record">record()</a> | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 620 | <h3><a name="find_related_one_to_many-3">find_related_one_to_many/3</a></h3> | |
| 621 | <p><tt>find_related_one_to_many(OtherModule::atom(), PkFkfields::<a href="#type-proplist">proplist()</a>, Rec::<a href="#type-record">record()</a>) -> <a href="#type-record">record()</a> | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 622 | 622 | <p><p>Find the related record for a record from a module having a |
| 623 | 623 | many-to-one relation.</p> |
| 624 | 624 | |
| ... | ...@@ -835,8 +835,8 @@ | |
| 835 | 835 | |
| 836 | 836 | <p><b>See also:</b> <a href="#field_from_string-2">field_from_string/2</a>.</p> |
| 837 | 837 | |
| 838 | <h3><a name="set_related_one_to_many-2">set_related_one_to_many/2</a></h3> | |
| 839 | <p><tt>set_related_one_to_many(Rec::<a href="#type-record">record()</a>, Other::<a href="#type-record">record()</a>) -> <a href="#type-record">record()</a> | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 838 | <h3><a name="set_related_one_to_many-3">set_related_one_to_many/3</a></h3> | |
| 839 | <p><tt>set_related_one_to_many(Rec::<a href="#type-record">record()</a>, PkFkFields::<a href="#type-proplist">proplist()</a>, Other::<a href="#type-record">record()</a>) -> <a href="#type-record">record()</a> | <a href="#type-exit">exit(Err)</a></tt></p> | |
| 840 | 840 | <p><p>Set the foreign key fields of a record from a module having a |
| 841 | 841 | many-to-one relation to the primary key values of the Other record.</p> |
| 842 | 842 |
| ... | ...@@ -231,10 +231,8 @@ | |
| 231 | 231 | ''' |
| 232 | 232 | |
| 233 | 233 | ErlyWeb by default would try to invoke the function 'bob/1' in |
| 234 | people_controller. This is probably not what you want. Instead, you | |
| 235 | probably want "bob" to be a parameter to a single generic function in | |
| 236 | people_controller. You can accomplish this by implementing the | |
| 237 | 'people' component as follows: | |
| 234 | people_controller. You can tell ErlyWeb to override this behavior and instead | |
| 235 | pass "bob" as a parameter to people_controller:catch_all/2 as follows: | |
| 238 | 236 | |
| 239 | 237 | people_controller.erl: |
| 240 | 238 | |
| ... | ...@@ -242,9 +240,6 @@ | |
| 242 | 240 | -module(people_controller). |
| 243 | 241 | -export(index/1, catch_all/2). |
| 244 | 242 | |
| 245 | index(_A) -> | |
| 246 | {data, undefined}. | |
| 247 | ||
| 248 | 243 | catch_all(A, [Name]) -> |
| 249 | 244 | {data, Name}. |
| 250 | 245 | ''' |
| ... | ...@@ -252,9 +247,6 @@ | |
| 252 | 247 | people_view.et: |
| 253 | 248 | |
| 254 | 249 | ``` |
| 255 | <%@ index(_) %> | |
| 256 | nothing much here | |
| 257 | ||
| 258 | 250 | <%@ catch_all(Name) %> |
| 259 | 251 | <% Name %>'s homepage |
| 260 | 252 | ... |
| ... | ...@@ -414,6 +406,7 @@ | |
| 414 | 406 | <% index(Album) %> |
| 415 | 407 | Your favorite album is:<br/> |
| 416 | 408 | <% Album %> |
| 409 | ''' | |
| 417 | 410 | |
| 418 | 411 | == The App Controller == |
| 419 | 412 | |
| ... | ...@@ -432,7 +425,7 @@ | |
| 432 | 425 | |
| 433 | 426 | hook_result = ewc() | yaws_term() | response() | |
| 434 | 427 | {phased, Ewc::ewc() | Response::response(), |
| 435 | fun(ExpandedEwc::ewc(), Data::iolist()) -> | |
| 428 | fun(ExpandedEwc::ewc(), Data::iolist(), PhasedVars::proplist()) -> | |
| 436 | 429 | FinalEwc::ewc()} |
| 437 | 430 | |
| 438 | 431 | ewc() = any `ewc' tuple |
| ... | ...@@ -461,45 +454,112 @@ | |
| 461 | 454 | returned by calling {@link erlyweb:get_initial_ewc/1}), ErlyWeb expects you |
| 462 | 455 | to ensure the safety of your components manually. |
| 463 | 456 | |
| 464 | In ErlyWeb 0.5, the `phased' return type was introduced to faciliate | |
| 465 | the conditional embedding of any rendered data in containers | |
| 466 | (before ErlyWeb 0.5, a similar, but weaker functionality was provided by | |
| 457 | === Phased Rendering === | |
| 458 | ||
| 459 | In ErlyWeb 0.5, the `phased' return type for hook/1 was introduced to let you | |
| 460 | embed components in containers after those components are rendered | |
| 461 | but before they are sent to the browser | |
| 462 | (before ErlyWeb 0.5, a similar but weaker functionality was provided by | |
| 467 | 463 | app views, which ErlyWeb no longer supports). By returning |
| 468 | `{phased, Ewc, Fun}', you are instructing ErlyWeb to first render the | |
| 464 | `{phased, Ewc, Fun}', you instruct ErlyWeb to first render the | |
| 469 | 465 | requested component, and if the result includes a rendered |
| 470 | 466 | iolist (i.e., the requested component didn't return only headers), |
| 471 | then nest the resulting iolist in a container before returning it. | |
| 467 | then pass it to the function Fun, which would decide if/how the iolist should | |
| 468 | be embedded in a container. | |
| 472 | 469 | |
| 473 | This approach is superior to directly embedding the requested component in a | |
| 474 | container because it allows the requested component to return headers | |
| 475 | (sub-components aren't allowed to return the `{response, Elems}' tuple, | |
| 476 | as discussed above). In addition, this approach lets ErlyWeb skip the | |
| 477 | unnecessary rendering of the container when the requested component | |
| 478 | returns only headers. | |
| 470 | The reason this is feature called 'phased' rendering is that ErlyWeb renders | |
| 471 | the response in 2 phases: first, the requested component, and second, the | |
| 472 | container in which the component should be embedded. | |
| 479 | 473 | |
| 480 | Consider this trivial example: returning | |
| 474 | Fun takes 3 parameters: the fully expanded 'ewc' tuple | |
| 475 | that ErlyWeb has rendered (this is usually the result of calling | |
| 476 | erlyweb:get_initial_ewc({ewc, A})), the rendered | |
| 477 | iolist, and an opaque parameter called 'PhasedVars' ('PhasedVars' was | |
| 478 | introduced in ErlyWeb 0.7). PhasedVars is a list of values returned from | |
| 479 | the rendered controller function, in a special tuple of the type | |
| 480 | {phased_vars, Vars}. The purpose of 'PhasedVars' is to let the controller | |
| 481 | function pass arbitrary values to the component that | |
| 482 | is rendered in the second phase. It is useful, for example, for letting | |
| 483 | the controller function set the title of a page when the page's header | |
| 484 | is rendered by the container in the second rendering phase. | |
| 485 | ||
| 486 | Fun may return any 'ewc' or 'data' tuple. ErlyWeb takes the result of Fun, | |
| 487 | renders it, and send the result back to the browser. | |
| 488 | ||
| 489 | Consider this example return value from hook/1: | |
| 481 | 490 | |
| 482 | 491 | ``` |
| 483 | {phased, {ewc, A}, fun(_Ewc, Data) -> {data, Data} end} | |
| 492 | {phased, {ewc, A}, fun(_Ewc, Data, _PhasedVars) -> {data, Data} end} | |
| 484 | 493 | ''' |
| 485 | 494 | |
| 486 | is tantamount to returning | |
| 495 | It is tantamount to returning | |
| 487 | 496 | |
| 488 | 497 | ``` |
| 489 | 498 | {ewc, A} |
| 490 | 499 | ''' |
| 491 | 500 | |
| 492 | Another example: the return value below | |
| 501 | This return value tells ErlyWeb to render the component | |
| 502 | that corresponds to the arg's appmoddata field, and then return | |
| 503 | the rendered iolist to the browser verbatim. | |
| 504 | ||
| 505 | Below is a more advanced example. | |
| 493 | 506 | |
| 494 | 507 | ``` |
| 495 | 508 | {phased, {ewc, A}, |
| 496 | fun(_Ewc, Data) -> | |
| 497 | {html_container, index, [A, {data, Data}]} | |
| 509 | fun(_Ewc, Data, PhasedVars) -> | |
| 510 | {html_container, | |
| 511 | [A, {data, Data}, proplists:get_value(title, PhasedVars)]} | |
| 498 | 512 | end} |
| 499 | 513 | ''' |
| 500 | 514 | |
| 501 | tells ErlyWeb to embed any rendered data in html_container by passing | |
| 502 | the parameters `[A, {data, Data}]' to its 'index' function. | |
| 515 | This return value tells ErlyWeb to first render the component that corresponds | |
| 516 | to the arg's appmoddata field, and then embed the rendered iolist | |
| 517 | (the 'Data' variable) in html_container. After ErlyWeb renders | |
| 518 | the requested component, it calls | |
| 519 | `html_container_controller:index(A, {data, Data}, proplists:get_value(title, PhasedVars))' and passes the result to html_container_view:index/1. | |
| 520 | ||
| 521 | How do you set the value of the 'title' property in PhasedVars? Below is | |
| 522 | an example controller function for an 'album' component that fetches from | |
| 523 | the database an album and its related songs, passes the song names to the | |
| 524 | view function, and sets the page's title according to the album name. | |
| 525 | ||
| 526 | album_controller.erl: | |
| 527 | ||
| 528 | ``` | |
| 529 | show(A, Id) -> | |
| 530 | Album = album:find_id(Id), | |
| 531 | AlbumName = album:name(Album), | |
| 532 | Songs = album:songs(Album), | |
| 533 | {response, | |
| 534 | [{phased_vars, [{title, [<<"song list for ">>, AlbumName]}]}, | |
| 535 | {body, {data, [{song:name(S) || S <- Songs}]}}]}. | |
| 536 | ''' | |
| 537 | ||
| 538 | Finally, below is an example html_container that takes the iolist and the | |
| 539 | 'title' parameter and inserts them into the proper positions in the HTML | |
| 540 | page. | |
| 541 | ||
| 542 | html_container_controller.erl: | |
| 543 | ||
| 544 | ``` | |
| 545 | index(A, Ewc, Title) -> | |
| 546 | [Ewc, {data, Title}]. | |
| 547 | ''' | |
| 548 | ||
| 549 | html_container_view.et: | |
| 550 | ||
| 551 | ``` | |
| 552 | <%@ index([Data, Title]) %> | |
| 553 | <html> | |
| 554 | <head> | |
| 555 | <title><% Title %></title> | |
| 556 | </head> | |
| 557 | <body> | |
| 558 | <% Data %> | |
| 559 | </body> | |
| 560 | </html> | |
| 561 | ''' | |
| 562 | ||
| 503 | 563 | |
| 504 | 564 | === error/3 === |
| 505 | 565 |
| ... | ...@@ -28,7 +28,10 @@ | |
| 28 | 28 | with the modified value. |
| 29 | 29 | |
| 30 | 30 | <h2><a name="index">Function Index</a></h2> |
| 31 | <table width="100%" border="1"><tr><td valign="top"><a href="#appmod_prepath-1">appmod_prepath/1</a></td><td/></tr> | |
| 31 | <table width="100%" border="1"><tr><td valign="top"><a href="#add_all_to_opaque-2">add_all_to_opaque/2</a></td><td>applies add_to_opaque for all values in the list.</td></tr> | |
| 32 | <tr><td valign="top"><a href="#add_to_opaque-2">add_to_opaque/2</a></td><td>Equivalent to <tt>Arg#arg{opaque = [Val | A#arg.opaque]}</tt>. | |
| 33 | </td></tr> | |
| 34 | <tr><td valign="top"><a href="#appmod_prepath-1">appmod_prepath/1</a></td><td/></tr> | |
| 32 | 35 | <tr><td valign="top"><a href="#appmod_prepath-2">appmod_prepath/2</a></td><td/></tr> |
| 33 | 36 | <tr><td valign="top"><a href="#appmoddata-1">appmoddata/1</a></td><td/></tr> |
| 34 | 37 | <tr><td valign="top"><a href="#appmoddata-2">appmoddata/2</a></td><td/></tr> |
| ... | ...@@ -44,6 +47,7 @@ | |
| 44 | 47 | <tr><td valign="top"><a href="#docroot-2">docroot/2</a></td><td/></tr> |
| 45 | 48 | <tr><td valign="top"><a href="#fullpath-1">fullpath/1</a></td><td/></tr> |
| 46 | 49 | <tr><td valign="top"><a href="#fullpath-2">fullpath/2</a></td><td/></tr> |
| 50 | <tr><td valign="top"><a href="#get_opaque_val-2">get_opaque_val/2</a></td><td>Return the value corrsponding to the Key in the opaque proplist.</td></tr> | |
| 47 | 51 | <tr><td valign="top"><a href="#headers-1">headers/1</a></td><td/></tr> |
| 48 | 52 | <tr><td valign="top"><a href="#headers-2">headers/2</a></td><td/></tr> |
| 49 | 53 | <tr><td valign="top"><a href="#method-1">method/1</a></td><td/></tr> |
| ... | ...@@ -66,6 +70,16 @@ | |
| 66 | 70 | |
| 67 | 71 | <h2><a name="functions">Function Details</a></h2> |
| 68 | 72 | |
| 73 | <h3><a name="add_all_to_opaque-2">add_all_to_opaque/2</a></h3> | |
| 74 | <p><tt>add_all_to_opaque(A::<a href="#type-arg">arg()</a>, Vals::[term()]) -> <a href="#type-arg">arg()</a></tt></p> | |
| 75 | <p>applies add_to_opaque for all values in the list | |
| 76 | </p> | |
| 77 | ||
| 78 | <h3><a name="add_to_opaque-2">add_to_opaque/2</a></h3> | |
| 79 | <tt>add_to_opaque(Arg, Val) -> term() | |
| 80 | </tt><p>Equivalent to <tt>Arg#arg{opaque = [Val | A#arg.opaque]}</tt>.</p> | |
| 81 | ||
| 82 | ||
| 69 | 83 | <h3><a name="appmod_prepath-1">appmod_prepath/1</a></h3> |
| 70 | 84 | <tt>appmod_prepath(Arg) -> term() |
| 71 | 85 | </tt> |
| ... | ...@@ -130,6 +144,12 @@ | |
| 130 | 144 | <tt>fullpath(Arg, Val) -> term() |
| 131 | 145 | </tt> |
| 132 | 146 | |
| 147 | <h3><a name="get_opaque_val-2">get_opaque_val/2</a></h3> | |
| 148 | <p><tt>get_opaque_val(A::<a href="#type-arg">arg()</a>, Key::term()) -> term() | undefined</tt></p> | |
| 149 | <p>Return the value corrsponding to the Key in the opaque proplist. | |
| 150 | If the key isn't found, return 'undefined'. | |
| 151 | </p> | |
| 152 | ||
| 133 | 153 | <h3><a name="headers-1">headers/1</a></h3> |
| 134 | 154 | <tt>headers(Arg) -> term() |
| 135 | 155 | </tt> |
| ... | ...@@ -1104,7 +1104,9 @@ | |
| 1104 | 1104 | %% @see find_first/3 |
| 1105 | 1105 | %% @see find_max/4 |
| 1106 | 1106 | %% @see find_range/5 |
| 1107 | %% @spec find_related_many_to_one(OtherModule::atom(), Rec::record(), | |
| 1107 | %% @spec find_related_many_to_one(OtherModule::atom(), | |
| 1108 | %% PkFks::term(), | |
| 1109 | %% Rec::record(), | |
| 1108 | 1110 | %% Where::where_expr(), Extras::extras_expr()) -> [record()] | exit(Err) |
| 1109 | 1111 | find_related_many_to_one(OtherModule, PkFks, Rec, Where, |
| 1110 | 1112 | Extras) -> |
| ... | ...@@ -1135,7 +1137,9 @@ | |
| 1135 | 1137 | %% {@link aggregate/5}. |
| 1136 | 1138 | %% |
| 1137 | 1139 | %% @see aggregate/5 |
| 1138 | %% @spec aggregate_related_many_to_one(OtherModule::atom(), AggFunc::atom(), | |
| 1140 | %% @spec aggregate_related_many_to_one(OtherModule::atom(), | |
| 1141 | %% PkFks::term(), | |
| 1142 | %% AggFunc::atom(), | |
| 1139 | 1143 | %% Rec::record(), Field::atom(), |
| 1140 | 1144 | %% Where::where_expr(), Extras::extras_expr()) -> float() | integer() | |
| 1141 | 1145 | %% exit(Err) |
| ... | ...@@ -1,5 +1,9 @@ | |
| 1 | 1 | v0.7 |
| 2 | 2 | |
| 3 | - Added yaws_arg:add_to_opaque/2, yaws_arg:add_all_to_opaque/2, and | |
| 4 | yaws_arg:get_opaque_val/2 to simplify accessing the 'opaque' field of the | |
| 5 | Yaws arg record. | |
| 6 | ||
| 3 | 7 | - Added support for multiple databases. More information is in the |
| 4 | 8 | documentation. (yariv) |
| 5 | 9 |
| ... | ...@@ -99,7 +99,7 @@ | |
| 99 | 99 | <h2><a name="types">Data Types</a></h2> |
| 100 | 100 | |
| 101 | 101 | <h3><a name="type-driver">driver()</a></h3> |
| 102 | <p><tt>driver() = {Driver, Options::<a href="#type-proplist">proplist()</a>} | {Driver, Options::<a href="#type-proplist">proplist()</a>, [<a href="#type-pool">pool()</a>]}</tt></p> | |
| 102 | <p><tt>driver() = atom() | {Driver::atom(), DriverOptions::<a href="#type-proplist">proplist()</a>} | {Driver::atom(), DriverOptions::<a href="#type-proplist">proplist()</a>, [<a href="#type-pool">pool()</a>]}</tt></p> | |
| 103 | 103 | |
| 104 | 104 | |
| 105 | 105 | <h3><a name="type-pool">pool()</a></h3> |
| ... | ...@@ -107,8 +107,11 @@ | |
| 107 | 107 | |
| 108 | 108 | |
| 109 | 109 | <h2><a name="index">Function Index</a></h2> |
| 110 | <table width="100%" border="1"><tr><td valign="top"><a href="#code_gen-2">code_gen/2</a></td><td>Generate code for the list of modules using the provided drivers.</td></tr> | |
| 111 | <tr><td valign="top"><a href="#code_gen-3">code_gen/3</a></td><td/></tr> | |
| 110 | <table width="100%" border="1"><tr><td valign="top"><a href="#code_gen-2">code_gen/2</a></td><td>Equivalent to <a href="#code_gen-3"><tt>code_gen(Modules, Drivers, [])</tt></a>. | |
| 111 | </td></tr> | |
| 112 | <tr><td valign="top"><a href="#code_gen-3">code_gen/3</a></td><td>Equivalent to <a href="#code_gen-4"><tt>code_gen(Modules, Drivers, Options, [])</tt></a>. | |
| 113 | </td></tr> | |
| 114 | <tr><td valign="top"><a href="#code_gen-4">code_gen/4</a></td><td>Generate code for the list of modules using the provided drivers.</td></tr> | |
| 112 | 115 | <tr><td valign="top"><a href="#start-1">start/1</a></td><td>Start an ErlyDB session for the driver using the driver's default |
| 113 | 116 | options.</td></tr> |
| 114 | 117 | <tr><td valign="top"><a href="#start-2">start/2</a></td><td>Start an ErlyDB sessions for the driver using the list of |
| ... | ...@@ -118,94 +121,132 @@ | |
| 118 | 121 | <h2><a name="functions">Function Details</a></h2> |
| 119 | 122 | |
| 120 | 123 | <h3><a name="code_gen-2">code_gen/2</a></h3> |
| 121 | <p><tt>code_gen(Modules::[Module::atom() | string()], Options::[<a href="#type-driver">driver()</a>]) -> ok | {error, Err}</tt></p> | |
| 124 | <tt>code_gen(Modules, Drivers) -> term() | |
| 125 | </tt><p>Equivalent to <a href="#code_gen-3"><tt>code_gen(Modules, Drivers, [])</tt></a>.</p> | |
| 126 | ||
| 127 | ||
| 128 | <h3><a name="code_gen-3">code_gen/3</a></h3> | |
| 129 | <tt>code_gen(Modules, Drivers, Options) -> term() | |
| 130 | </tt><p>Equivalent to <a href="#code_gen-4"><tt>code_gen(Modules, Drivers, Options, [])</tt></a>.</p> | |
| 131 | ||
| 132 | ||
| 133 | <h3><a name="code_gen-4">code_gen/4</a></h3> | |
| 134 | <p><tt>code_gen(Modules::[Module::atom() | string()], Driver::[<a href="#type-driver">driver()</a>] | <a href="#type-driver">driver()</a>, Options::[term()], IncludePaths::[IncludePath::string()]) -> ok | {error, Err}</tt></p> | |
| 122 | 135 | <p><p>Generate code for the list of modules using the provided drivers.</p> |
| 123 | 136 | |
| 137 | <p>If you're using ErlyWeb, you shouldn't need to call this function directly. | |
| 138 | Instead, refer to <a href="erlyweb.html#compile-2"><code>erlyweb:compile/2</code></a>.</p> | |
| 139 | ||
| 140 | <h4><a name="Usage">Usage</a></h4> | |
| 141 | ||
| 124 | 142 | <p>In ErlyWeb 0.7, the signature for this function has changed. |
| 125 | 143 | ErlyDB used to support only a single driver with a single connection |
| 126 | 144 | pool in a session. As of ErlyWeb 0.7, ErlyDB supports multiple |
| 127 | 145 | drivers in a session, and multiple connection pools for each |
| 128 | 146 | driver.</p> |
| 129 | 147 | |
| 130 | <p>The 'Modules' parameter is a list of files or modules for which to | |
| 148 | <h5><a name="Modules">Modules</a></h5><p> | |
| 149 | The 'Modules' parameter is a list of files or modules for which to | |
| 131 | 150 | generate ErlyDB code. If a list item is an atom, ErlyDB assumes it's |
| 132 | a module that has been loaded into the VM or that resides in the | |
| 151 | a module that has been loaded into the VM or that resides in the VM's | |
| 133 | 152 | code path. In either case, the module's source code should be discoverable |
| 134 | either through path conventions or because it includes debug_info. | |
| 135 | If a list item is a string, ErlyDB treats it as a file name (relative | |
| 153 | either through Erlang's path conventions or because the module | |
| 154 | was compiled with debug_info.</p> | |
| 155 | ||
| 156 | <p>If a list item is a string, ErlyDB treats it as a file name (relative | |
| 136 | 157 | or absolute) and attempts to read it from disk.</p> |
| 137 | 158 | |
| 138 | <p>The 'Driver's parameter is a list of Driver::atom(), | |
| 139 | {Driver::atom(), Options::proplist()} or | |
| 140 | {Driver::atom(), Options::proplist(), Pools::pool()} tuples. | |
| 141 | The first tuple in the Drivers list is | |
| 159 | <h5><a name="Drivers">Drivers</a></h5><p> | |
| 160 | The 'Drivers' parameter is either a single element or a list of | |
| 161 | elements of the form | |
| 162 | <code>Driver::atom()</code>, | |
| 163 | <code>{Driver::atom(), DriverOptions::proplist()}</code>, or | |
| 164 | <code>{Driver::atom(), DriverOptions::proplist(), Pools::pool()}</code>.</p> | |
| 165 | ||
| 166 | <p>The first element in the Drivers list is | |
| 142 | 167 | the default driver that ErlyDB will use for all modules that don't |
| 143 | 168 | override the driver option.</p> |
| 144 | 169 | |
| 145 | <p>Driver can be 'mysql', 'psql' or 'mnesia'. Options is a list of | |
| 170 | <p>'Driver' can be <code>mysql</code>, <code>psql</code> or <code>mnesia</code>. 'Options' is a list of | |
| 146 | 171 | driver-specific options. For a list of available options, refer to |
| 147 | 172 | the driver's documentation.</p> |
| 148 | 173 | |
| 149 | <p>Pools is a list of available connection pools for the driver. | |
| 150 | Note that the driver must be started and the pools must be connected | |
| 151 | before code_gen/2 is called. Each item in Pools is an atom indicating | |
| 152 | the pool id, or a tuple of the form {default, PoolId}, indicating | |
| 153 | that this pool will be used as the default pool for the driver. | |
| 154 | If you don't provide a {default, PoolId} pool option, ErlyDB will use | |
| 155 | the built-in default pool id.</p> | |
| 174 | <p>'DriverOptions' is a property list that contains driver-specific options | |
| 175 | (e.g. '{allow_unsafe_statements, Bool}'). | |
| 176 | For more information refer to the driver's documentation.</p> | |
| 177 | ||
| 178 | <p>'Pools' is a list of available connection pools for the driver. | |
| 179 | Note that the driver must be started and the pools must be connected | |
| 180 | before code_gen/2 is called. Each item in 'Pools' is an atom indicating | |
| 181 | the pool id, or a tuple of the form <code>{PoolId, default}</code>, which indicates | |
| 182 | that this pool will be used as the default pool for the driver. | |
| 183 | If you don't provide a <code>{PoolId, default}</code> pool option, ErlyDB will use | |
| 184 | the driver-defined default pool id if it exists (you can obtain it by | |
| 185 | calling Mod:get_default_pool_id(), where 'Mod' is the driver's | |
| 186 | module, e.g. 'erlydb_mysql').</p> | |
| 187 | ||
| 188 | <h5><a name="Options">Options</a></h5> | |
| 189 | ||
| 190 | <p>'Options' is a list of options that are used for all modules. This may | |
| 191 | include global driver options as well as options that are passed to | |
| 192 | compile:file/2. For more information, refer to this function's documentation | |
| 193 | in the OTP documentation.</p> | |
| 194 | ||
| 195 | <h5><a name="IncludePaths">IncludePaths</a></h5> | |
| 196 | ||
| 197 | <p>Additional include paths that will be used to search for header files | |
| 198 | when compiling the modules.</p> | |
| 156 | 199 | |
| 157 | <p>Below are some examples:</p> | |
| 200 | <h4><a name="Examples">Examples</a></h4> | |
| 158 | 201 | |
| 159 | 202 | <p>Generate code for "musician.erl" using the MySQL driver. Only the default |
| 160 | 203 | pool is enabled.</p> |
| 161 | 204 | |
| 162 | <pre> code_gen(["musician.erl"], [mysql]).</pre> | |
| 205 | <pre> code_gen(["musician.erl"], mysql).</pre> | |
| 163 | 206 | |
| 164 | <p>To use the previous settings but allow unsafe SQL statements, use | |
| 165 | the following:</p> | |
| 207 | <p>Use the previous settings but allow unsafe SQL statements, and compile | |
| 208 | with debug_info:</p> | |
| 166 | 209 | |
| 167 | <pre> code_gen(["musician.erl"], [{mysql, [{allow_unsafe_statements, true}]}]).</pre> | |
| 210 | <pre> code_gen(["musician.erl"], | |
| 211 | {mysql, [{allow_unsafe_statements, true}]}, | |
| 212 | [debug_info]).</pre> | |
| 168 | 213 | |
| 169 | <p>Generate code for the modules using the MySQL driver with two additional | |
| 170 | pools, 'pool1' and 'pool2'. The default pool is not overridden.</p> | |
| 214 | <p>Generate code for the modules using the MySQL driver with two additional | |
| 215 | pools, 'pool1' and 'pool2'. The default pool is remains <code>erlydb_mysql</code>:</p> | |
| 171 | 216 | |
| 172 | 217 | <pre> code_gen(["musician.erl", "instrument.erl"], |
| 173 | [{mysql, [], [pool1, pool2]}]).</pre> | |
| 218 | {mysql, [], [pool1, pool2]}).</pre> | |
| 174 | 219 | |
| 220 | <p>Similar to the previous setting, but allow unsafe statement and use | |
| 221 | <code>pool2</code> as the default pool name:</p> | |
| 175 | 222 | |
| 223 | <pre> code_gen(["src/musician.erl", "src/instrument.erl"], | |
| 224 | {mysql, [{allow_unsafe_statements, true}], | |
| 225 | [{pool1, {pool2, default}}]})</pre> | |
| 226 | ||
| 227 | <p>Generate code for the modules using both the MySQL and Postgres driver. | |
| 228 | The MySQL driver has 2 pools enabled: mysql_pool1 and mysql_pool2, which is | |
| 229 | the default. The Postgres driver has a single default pool, pg_pool1. | |
| 230 | The MySQL driver allows unsafe statements:</p> | |
| 231 | ||
| 232 | <pre> code_gen(["src/musician.erl", "src/instrument.erl", "src/song.erl"], | |
| 233 | [{mysql, [{allow_unsafe_statements, true}], | |
| 234 | [{mysql_pool1, {mysql_pool2, default}}]}, | |
| 235 | {psql, [], [{pg_pool1, default}]}])</pre> | |
| 176 | 236 | |
| 177 | <p>tells ErlyDB to use the 'mysql' driver with the default | |
| 178 | code_gen(["src/musician.erl", "src/instrument.erl"], | |
| 179 | [{mysql, [{allow_unsafe_statements, true}], | |
| 180 | [{pool1, {default, pool2}}]}]) | |
| 181 | '''</p> | |
| 237 | <h4><a name="Module-Specific_Settings">Module-Specific Settings</a></h4> | |
| 182 | 238 | |
| 183 | 239 | <p>To specify which connection pool ErlyDB should for a specific module, add |
| 184 | 240 | the following line to the module's source code:</p> |
| 185 | 241 | |
| 186 | <pre> -erlydb_options(pool_id, PoolId).</pre> | |
| 242 | <pre> -erlydb_options([{driver, Driver}, {pool_id, PoolId}]).</pre> | |
| 187 | 243 | |
| 188 | <p>This tells ErlyDB to use the default driver, but a non-default pool id. | |
| 189 | If you want the module to use a non-default driver, use the attribute</p> | |
| 190 | ||
| 191 | <p>''' | |
| 192 | -erlydb_options(driver, Driver). | |
| 193 | ''' | |
| 194 | or</p> | |
| 195 | ||
| 196 | <p>''' | |
| 197 | -erlydb_options(driver, {Driver, PoolId}). | |
| 198 | '''</p> | |
| 199 | ||
| 200 | The first option tells ErlyDB to use a non-default driver with the | |
| 201 | default pool id for the driver. The second option tells ErlyDB | |
| 202 | to use a non-default driver, and a non-default pool id for the driver. | |
| 244 | The 'driver' option tells ErlyDB to use a non-default driver for the | |
| 245 | module. The 'pool_id' option tells ErlyDB to use a non-default pool id | |
| 246 | for the module. Neither option is required -- you can specify only | |
| 247 | a 'driver' option or only a 'pool_id' option. | |
| 203 | 248 | </p> |
| 204 | 249 | |
| 205 | <h3><a name="code_gen-3">code_gen/3</a></h3> | |
| 206 | <tt>code_gen(Modules, Options, IncludePaths) -> term() | |
| 207 | </tt> | |
| 208 | ||
| 209 | 250 | <h3><a name="start-1">start/1</a></h3> |
| 210 | 251 | <p><tt>start(Driver::atom()) -> ok | {error, Err}</tt></p> |
| 211 | 252 | <p>Start an ErlyDB session for the driver using the driver's default |
| ... | ...@@ -234,28 +234,20 @@ | |
| 234 | 234 | <pre>http://my-cool-app.com/people/bob</pre> |
| 235 | 235 | |
| 236 | 236 | <p>ErlyWeb by default would try to invoke the function 'bob/1' in |
| 237 | people_controller. This is probably not what you want. Instead, you | |
| 238 | probably want "bob" to be a parameter to a single generic function in | |
| 239 | people_controller. You can accomplish this by implementing the | |
| 240 | 'people' component as follows:</p> | |
| 237 | people_controller. You can tell ErlyWeb to override this behavior and instead | |
| 238 | pass "bob" as a parameter to people_controller:catch_all/2 as follows:</p> | |
| 241 | 239 | |
| 242 | 240 | <p>people_controller.erl:</p> |
| 243 | 241 | |
| 244 | 242 | <pre>-module(people_controller). |