Alkemist v1.0.1-rc Alkemist.Controller behaviour
Provides helper macros to use inside of CRUD controllers.
Example with minimal configuration:
defmodule MyAppWeb.MyController do
use MyAppWeb, :controller
# Specify the Ecto Schema as resource - it is important to call this above
# use Alkemist.Controller!
@resource MyApp.MySchema
use Alkemist.Controller
# use if you want to customize the menu
menu "My Custom Label"
def index(conn, params) do
render_index(conn, params)
end
def show(conn, %{"id" => id}) do
render_show(conn, id)
end
def edit(conn, %{"id" => id}) do
render_edit(conn, id)
end
def new(conn, _params) do
render_new(conn)
end
def create(conn, %{"my_schema" => params}) do
do_create(conn, params)
end
def update(conn, %{"id" => id, "my_schema" => params}) do
do_update(conn, id, params)
end
def delete(conn, %{"id" => id}) do
do_delete(conn, id)
end
def export(conn, params) do
csv(conn, params)
end
end
The following methods can be implemented to set configuration on a global level:
repo
- needs to return a validEcto.Repo
preload
- return a keyword list of resources to preload in all controller actionscollection_actions
- a list of actions to list in the collection action menu. They need to be implemented in your controller and a custom route to that function needs to be added to your router.member_actions
- a list of actions that is available for each individual resource. They need to be implemented in your controller and a custom router needs to be added to your router
Example for a custom member action:
In your router.ex:
scope "/admin", MyApp, do
...
get "/my_resource/:id/my_func", MyController, :my_func
alkemist_resources("/my_resource", MyController)
end
In your controller:
def member_actions do
[:show, :edit, :delete, :my_func]
end
def my_func(conn, %{"id" => id}) do
# do something with the resource
conn
|> put_layout({Alkemist.LayoutView, "app.html"})
|> render("my_template.html", resource: my_resource)
end
Link to this section Summary
Types
Used to create custom filters in the filter form. Type can be in [:string, :boolean, :select, :date]
,
default is :string
. If the type is :select
, a collection to build the select must be passed (see Phoenix.HTMl.Form.select/4
)
Functions
Creates a csv export of all entries that match the current scope and filter. An export does not paginate
Creates a new resource TODO: document opts
Performs a delete of the current resource. When successful, it will redirect to index
Performs an update to the resource
Simple helper method to use link in callbacks
Loads the resource from the repo and adds any preloads
Customize the Menu item in the sidebar. You can call this function within the controller root after including Alkemist.Controller and setting the @resource
Renders the “edit action”
See Alkemist.Controller.render_form/3
Renders the form for edit and create actions
Renders the default index view table
Renders the “new” action
see Alkemist.Controller.render_form/3
Renders the default show page
Link to this section Types
Used to create custom filters in the filter form. Type can be in [:string, :boolean, :select, :date]
,
default is :string
. If the type is :select
, a collection to build the select must be passed (see Phoenix.HTMl.Form.select/4
)
Link to this section Functions
Creates a csv export of all entries that match the current scope and filter. An export does not paginate.
For available_options see Alkemist.Controller.render_index/2
Creates a new resource TODO: document opts
Performs a delete of the current resource. When successful, it will redirect to index.
Options:
delete_func
- use a custom method for deletion. Takes the resource as argument.success_callback
- custom function on success. Takes the deleted resource as argumenterror_callback
- custom function on error. Takes the resource as argument
Examples:
def delete(conn, %{"id" => id}) do
opts = [
delete_func: fn r ->
MyApp.MyService.deactivate(r)
end,
error_callback: fn r ->
my_custom_error_function(conn, r)
end
]
do_delete(conn, id, opts)
end
Performs an update to the resource
Options:
changeset
- use a custom changeset. Example:changeset: :my_update_changeset
success_callback
- custom function that will be performed on update success. Accepts the new resource as argumenterror_callback
- custom function that will be performed on failure. Takes the changeset as argument.
Examples:
def update(conn, %{"id" => id, "resource" => resource_params}) do
do_update(conn, id, resource_params, changeset: :my_update_changeset)
end
Or use a custom success or error function:
def update(conn, %{"id" => id, "resource" => resource_params}) do
opts = [
changeset: :my_udpate_changeset
success_callback: fn my_resource ->
conn
|> put_flash(:info, "Resource was successfully updated")
|> redirect(to: my_resource_path(conn, :index))
end
]
do_update(conn, id, resource_params, opts)
end
Simple helper method to use link in callbacks
Loads the resource from the repo and adds any preloads
Renders the “edit action”
See Alkemist.Controller.render_form/3
Renders the form for edit and create actions.
Options
preload
- Resources to preload. SeeEcto.Query
repo
- Define a custom repo to execute the queryform_partial
- a tuple in the format{MyViewModule, "template.html"}
or{MyViewModule, "template.html", assigns}
fields
- a list of either atoms representing the resource fields, maps with field groups or a keyword list in the format[field_name: %{type: :type, other opts...}]
changeset
- use a custom changesetsuccess_callback
- use a custom callback function that takes the newly updated/created resource as an argumenterror_callback
- use a custom callback function on error, takes changeset as argument
Examples:
def edit(conn, %{"id" => id}) do
opts = [
preload: [:my_relationship]
form_partial: {MyView, "edit.html"},
changeset: :my_changeset,
error_callback: fn(changeset) -> ... end
]
render_edit(conn, id, opts)
end
fields
and form_partial
also can be defined as custom methods in the controller.
Example with methods:
def edit(conn, %{"id" => id}) do
render_edit(conn, id)
end
# resource will be nil on create
def fields(_conn, _resource) do
[
:title,
:body
]
# or with custom types:
# [title: %{type: :string, placeholder: "Enter title"}, body: %{type: :text}]
# or use some custom form groups
# [
# %{title: "My Model details", fields: [:title, :body]},
# %{title: "Next panel header", fields: [:category]}
# ]
end
Renders the default index view table.
Params:
- conn - the conn from the controller action
- params - the params that are passed to the controller action
- opts - a
Keyword.t/0
with options
Options:
- repo - use a custom
Ecto.Repo
- member_actions - customize the actions that will display for each resource
- collection_actions - customize the global actions that are available for a collection of resources (e. g.
new
) - batch_actions - add custom batch actions to be performed on a number of selected resources.
When set, a
selectable_column
will be added to the index table and a batch menu will display above the table. - columns - List of
column/0
customize the columns that will display in the index table - scopes - List of
scope/0
to define custom filter scopes - filters - List of
filter/0
to define filters for the search form - preload - resources to preload along with each resource (see
Ecto.Query
) - search_provider - define a custom library for building the search query
Example with options:
def index(conn, params) do
opts = [
# Columns can either be an atom, or a `tuple` with a label and a custom modifier function
columns: [
:id,
:title,
:body,
{"Author", fn i -> i.author.name end}
],
batch_actions: [:delete_batch],
member_actions: [:show, :edit, :my_custom_action],
scopes: [
{:published, [], fn(q) -> where(q, [p], p.published == true) end}
],
preload: [:author]
]
render_index(conn, params, opts)
end
Example with custom functions:
def index(conn, params) do
render_index(conn, params)
end
def my_custom_action(conn, %{"id" => id}) do
...
end
def delete_all(conn, %{"batch_ids" => ids}) do
# implement custom batch action
end
def columns do
[
:id,
:title,
:body,
{"Author", fn i -> i.author.name end}
]
end
def scopes do
[published: [], fn i -> i.published == true end]
end
def preload do
[:author]
end
def member_actions do
[:show, :edit, :my_custom_action]
end
def batch_actions do
[:delete_batch]
end
Renders the “new” action
see Alkemist.Controller.render_form/3
Renders the default show page.
Options:
preload
- Resources to preload. SeeEcto.Query
repo
- Define a custom repo to execute the queryrows
- The values to display. Same syntax ascolumn/0
show_panels
- define custom panels that are shown underneath the resource table. Each panel consists of a tuple in the form{"Panel Heading", content: my_html_content} Each of the above options can also be specified as controller functions, whereas rows and show_panels take to arguments
connand
resource. The
resource` is the current resource (e. g. a specific user) ## Example with options:elixir def show(conn, %{"id" => id}) do post = Repo.get(Post, id) |> Repo.preload(:author) opts = [ rows: [ :id, :title, :body, {"Author", fn p -> unless p.author != nil do p.author.name end end} ], show_panels: [ {"Author", content: Phoenix.View.render( MyApp.PostView, "author.html", author: post.author )}} ] ] render_show(conn, post, opts)
## Example with custom functions:elixir def show(conn, %{"id" => id}) do render_show(conn, id, preload: [:author]) end def show_panels(_conn, post) do if post.author do [{ "Author", content: Phoenix.View.render( MyApp.PostView, "author.html", author: post.author ) }] else [] end end def rows(_conn, post) do [:id, :title, :body] end
Link to this section Callbacks
fields(Plug.Conn.t(), struct() | nil) :: [field() | map()]
form_partial(Plug.Conn.t(), struct() | nil) :: tuple()