I've got this database schema for a new user.
defmodule XYZ.User do
use XYZ.Web, :model
schema "users" do
field :lawyer, :boolean
field :firm, :boolean
field :first_name, :string
field :last_name, :string
field :phone, :string
field :email, :string
timestamps
end
def changeset(model, params \\ :empty) do
model
|> cast(params, [:lawyer, :firm, :first_name, :last_name, :phone, :email])
|> validate_required([:first_name, :last_name, :phone, :email])
end
end
The UserController handles /users/new by creating a new User changeset and passing it to a web view/template for rendering.
defmodule XYZ.UserController do
use XYZ.Web, :controller
def new(conn, _params) do
changeset = User.changeset(%User{})
render conn, "new.html", changeset: changeset
end
The new.html.eex template uses a Phoenix.HTML helper function to render the lawyer/firm as two radio buttons.
<%= form_for @changeset, user_path(@conn, :create), fn f -> %>
<div class="form-group">
<%= radio_button f, :lawyer, "true", checked: "checked %>
<%= label f, :user_lawyer, "Lawyer" %>
<%= radio_button f, :firm, "true" %>
<%= label f, :user_firm, "Firm" %>
</div>
...
The rendered HTML for the source code above is as follows.
div class="form-group">
<input checked="checked" id="user_lawyer_true" name="user[lawyer]" type="radio" value="true">
<label for="user_user_lawyer">Lawyer</label>
<input id="user_firm_true" name="user[firm]" type="radio" value="true">
<label for="user_user_firm">Firm</label>
div>
With the code above submitting the form will save the value of true to the the column in the database record that corresponds to the radio button that was selected on the form.
However, the two radio buttons don't function as a group. It is possible to select both radio buttons when only one should be selected.
Changing the Phoenix.HTML helper functions, adding name: "type" to the options, will group the two radio buttons, but the true value of the selected radio button is not persisted to the database when the form is submitted.
Here's the modified helper functions.
<%= form_for @changeset, user_path(@conn, :create), fn f -> %>
<div class="form-group">
<%= radio_button f, :lawyer, "true", name: "type", checked: "checked" %>
<%= label f, :user_lawyer, "Lawyer" %>
<%= radio_button f, :firm, "true", name: "type" %>
<%= label f, :user_firm, "Firm" %>
</div>
...
And here's the rendered HTML for the above source code.
div class="form-group">
<input checked="checked" id="user_lawyer_true" name="type" type="radio" value="true">
<label for="user_user_lawyer">Lawyer</label>
<input id="user_firm_true" name="type" type="radio" value="true">
<label for="user_user_firm">Firm</label>
/div>
How can I make the two radio buttons behave as a group while still persisting the correct values to the database?
I'm using the following versions of software:
- Elixir v1.3.4
- Phoenix v1.2.1
- PostgreSQL v9.5.4
Thanks in advance.
----- SOLUTION -----
I ended up implementing one of @cpjolicoeur suggestions, modifying the User schema, removing the boolean lawyer and firm fields and adding a single string field called type.
schema "users" do
field :type, :string
field :first_name, :string
field :last_name, :string
field :phone, :string
field :email, :string
timestamps
end
I then modified the new.html.eex template:
<%= form_for @changeset, user_path(@conn, :create), fn f -> %>
<div class="form-group">
<%= radio_button f, :type, "lawyer", checked: "checked" %>
<%= label f, :user_lawyer, "Lawyer" %>
<%= radio_button f, :type, "firm" %>
<%= label f, :user_firm, "Firm" %>
</div>
...
With those changes the radio button selection, "lawyer" or "firm", is saved to the type field when a new user is created.