Building a Contact Form with Records
This guide will help you understand the process of building a contact form backed up with Record. Whenever you need to build a simple contact form, blog functionality, or complex API endpoint, you can define any data structure you need with Records.
Requirements
Steps
Building a Contact Form with Records is a nine-step process:
Step 1: Define Contact – Table
To define a new Table, use YAML files placed in the schema
directory. In the key-value format, you can define a name for your Record, and an array of Properties for the Record object. To build a Contact Form, you'll need email, name, and description attributes on the Record that you can call a contact
.
app/schema/contact.yml
name: contact
properties:
- name: name
type: string
- name: email
type: string
- name: description
type: string
The basic Configuration of the Record consists of a name and the list of Properties. In the example above, you have defined three attributes of type string
.
For more information on Properties please visit the Properties Documentation.
Step 2: Define Contact Form – Form Object
Now that you have the definition of a Contact
in place, you can create a Form that will configure the server to accept requests with data in the desired format. Data passed through the form will be stored in the database as a Contact object.
app/forms/contact_form.liquid
---
name: contact_form
resource: modules/contacts/contact
resource_owner: anyone
fields:
properties:
name:
validation:
presence: true
email:
validation:
presence: true
email: true
description:
validation:
presence: true
---
The above definition allows name, email, and description attributes and defines validation for each attribute.
Step 3: Fetch saved data with GraphQL
Now that you have created the Contact
Table in the previous step, you can proceed to fetch this data with GraphQL. To define get_contacts query, create file get_contacts.graphql
file in graphql
directory.
query get_contacts($id: ID) {
records(
filter: {
table: { value: "modules/contacts/contact" },
id: { value: $id }
},
per_page: 100
) {
results {
id
name: property(name: "name")
email: property(name: "email")
description: property(name: "description")
}
}
}
To check if the above query works properly you can head to the next section to learn how to embed query results with page view or use pos-cli gui
Step 4: Render Records within page
Display contacts as a list with the possibility to get to the contact details view.
As a first step, you need a page that will respond to given paths:
GET /contacts
for list viewGET /contacts/[ID]
for detail view
Page slug for the above URL map will simply be contacts
as the ID passed in the URL is dynamically assigned to the context.params.slug2
variable. For more information, visit the Pages documentation.
app/views/pages/contacts.liquid
{% liquid
assign id = context.params.slug2
graphql g = "modules/contacts/get_contacts", id: id
%}
{%- if id == blank -%}
{% include 'modules/contacts/contacts/list', contacts: g.records.results %}
{%- else -%}
{% include 'modules/contacts/contacts/show', contact: g.records.results.first %}
{%- endif -%}
app/views/partials/contacts/list.liquid
<h1>List View</h1>
<table>
<tr>
<th>ID</th>
<th>Email</th>
<th></th>
</tr>
{% for contact in contacts %}
<tr>
<td>{{ contact.id }}</td>
<td>{{ contact.email }}</td>
<td><a href="/contacts/{{ contact.id }}">Details</a></td>
</tr>
{% endfor %}
</table>
app/views/partials/contacts/show.liquid
<h1>Detail view</h1>
<p>{{ contact.name }}</p>
<p>{{ contact.email }}</p>
<p>{{ contact.description }}</p>
Step 5: Build Contact Form with HTML
In Step 2: Define Contact Form-Data Creation, you have created a form file called contact_form
, that configures the form object. This was a minimal example to allow sending requests to our API endpoint, and create Record objects. Now you can extend this file with HTML, that renders the form to our users. The HTML part of the file comes after the configuration part, i.e. after the closing ---
tag.
---
name: contact_form
resource: modules/contacts/contact
resource_owner: anyone
redirect_to: /contacts
fields:
properties:
name:
validation:
presence: true
email:
validation:
presence: true
email: true
description:
validation:
presence: true
---
{% form %}
<label for="name">Name</label>
<input name="{{ form.fields.properties.name.name }}" value="{{ form.fields.properties.name.value }}" id="name" type="text">
{% if form.errors['properties.name'] %}
<p>{{ form.errors['properties.name'] }}</p>
{% endif %}
<label for="email">Email</label>
<input name="{{ form.fields.properties.email.name }}" value="{{ form.fields.properties.email.value }}" id="email" type="email">
{% if form.errors['properties.email'] %}
<p>{{ form.errors['properties.email'] }}</p>
{% endif %}
<label for="description">Description</label>
<textarea name="{{ form.fields.properties.description.name }}" id="description">{{ form.fields.properties.description.value }}</textarea>
{% if form.errors['properties.description'] %}
<p>{{ form.errors['properties.description'] }}</p>
{% endif %}
<button>Submit</button>
{% endform %}
The redirect_to
configuration option defines where to redirect the user after successful form submission. The predefined form
tag allows you to create context for submitted data.
For more information of advanced form configuration please visit Form Documentation.
To display the form on the previously created contacts
page you have to include it with:
app/views/pages/contacts.liquid
{% include_form 'modules/contacts/contact_form' %}
As a result, you should be able to create Record objects, called Contact with simple form submission, and list them after fetching with GraphQL.
Step 6: Delete contact
In order to remove record from the database, create delete_contact_form
:
---
name: delete_contact_form
resource: modules/contacts/contact
resource_owner: anyone
redirect_to: /contacts
fields: {}
---
{% form method: "delete" %}
<button type="submit">Delete</button>
{% endform %}
To display delete button on the list of contacts, include the form as follows:
<td>
{% include_form "modules/contacts/delete_contact_form", id: contact.id %}
</td>
Step 7: Edit Contact
As you already have the form to create contacts, you can reuse it for the purpose of record update. In order to prefill the form with proper data, add id
to include_form
tag.
app/views/pages/contacts/edit.liquid
{% include_form "modules/contacts/contact_edit_form", id: context.params.slug3 %}
Step 8: Add Email Notification
To send an Email Notification to the email that was sent with form submission, create an Email Notification file that will define email configuration and message template.
The file should be located in the emails
directory, name it contact_notification.liquid
:
app/emails/contact_notification.liquid
---
name: contact_notification
from: 'Example Site <[email protected]>'
subject: Contact
to: '{{ form.properties.email }}'
---
<h2>Hi {{ form.properties.name }}</h2>
<p>Thank you for your request, we will contact you shortly!</p>
All request parameters are now accessible in form.record
object, so you can compose any email you want. Next step is linking contact_notification
in the contact_form
by adding to form configuration inside forms/contact_form.liquid
file.
email_notifications:
- contact_notification
Step 9: Secure the form
At this point, you might want to restrict access to the forms and views you have created. You can do that using Authorization Policies.
Live example and source code
To play with a live example (in much fuller form and with additional information) go to the contact example page.
Source code can be found on GitHub.
Next steps
Congratulations! You have learned how to build forms with Record. You can now explore our reference documentation for Properties and Tables: