Как мне сохранить состояния переключателя Phoenix.HTML в базе данных PostgreSQL, но при этом сделать их группой?

У меня есть схема базы данных для нового пользователя.

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

UserController обрабатывает / users / new, создавая новый набор изменений User и передавая его в веб-представление / шаблон для рендеринга.

defmodule XYZ.UserController do
  use XYZ.Web, :controller

  def new(conn, _params) do
    changeset = User.changeset(%User{})
    render conn, "new.html", changeset: changeset
  end

В шаблоне new.html.eex используется вспомогательная функция Phoenix.HTML для отображения юриста / фирмы в виде двух переключателей.

<%= 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> 
  ...

Отрендеренный HTML для исходного кода, приведенного выше, выглядит следующим образом.

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>

С помощью приведенного выше кода отправка формы сохранит значение true в столбце в записи базы данных, который соответствует переключателю, выбранному в форме.

Однако две радиокнопки не работают как группа. Можно выбрать обе радиокнопки, если нужно выбрать только одну.

Изменение вспомогательных функций Phoenix.HTML, добавление name: "type" к параметрам, сгруппирует два переключателя, но истинное значение выбранного переключателя не сохраняется в базе данных при отправке формы.

Вот модифицированные вспомогательные функции.

<%= 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>
  ...

А вот визуализированный HTML-код для приведенного выше исходного кода.

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>

Как заставить два переключателя работать как группа, сохраняя при этом правильные значения в базе данных?

Я использую следующие версии программного обеспечения:

  • Эликсир v1.3.4
  • Феникс v1.2.1
  • PostgreSQL v9.5.4

Заранее спасибо.

----- РЕШЕНИЕ -----

В итоге я реализовал одно из предложений @cpjolicoeur, изменив схему User, удалив логические поля lawyer и firm и добавив одно строковое поле с именем type .

schema "users" do
  field :type, :string
  field :first_name, :string
  field :last_name, :string
  field :phone, :string
  field :email, :string

  timestamps
end

Затем я изменил шаблон new.html.eex:

<%= 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>
  ...

С этими изменениями выбор переключателя «юрист» или «фирма» сохраняется в поле type при создании нового пользователя.


person billmaya    schedule 19.02.2017    source источник


Ответы (1)


Я думаю, что есть несколько возможностей.

Во-первых, вы можете изменить атрибут value элементов <radio /> на разные значения. Прямо сейчас они оба имеют значение true, что означает, что независимо от того, какой из них выбран, параметр «type», который отправляется на ваш контроллер, всегда будет иметь значение true, что означает, что вы не можете узнать, какой переключатель был выбран. Вы можете изменить значения на что-то вроде value="firm" и value="lawyer", чтобы параметр «тип» в контроллере вместо этого содержал строку «фирма» или «юрист» вместо того, чтобы всегда быть «истинным».

Однако приходит на ум второй вариант, если это действительно взаимоисключающие варианты. Просто сохраните в базе данных один столбец вместо двух. Это могло произойти в нескольких возможных заклинаниях.

  • Может быть, столбец boolean под названием lawyer, который верен, если они юристы, а если нет, то вы знаете, что они firm. В этом случае переключатель для lawyer будет иметь value="true", а переключатель для firm будет иметь value="false"
  • Измените поле базы данных на тип enum, где вы сопоставляете значение с известными типами (юристы, фирмы и т. Д.). Это позволит вам также расширить список типов в будущем, если вам понадобится. Тогда значения ваших переключателей - это просто значения "перечисления", которые вы используете.
person cpjolicoeur    schedule 22.02.2017