Леса Grails 2.5 не удаляют последние hasMany во время связывания

Я создал новый проект Grails 2.5.1 с двумя доменами и использовал функцию generate-all для создания каркаса. Один из доменов имеет много, другой домен: у пользователя много ролей. Когда я запускаю приложение, создаю нового пользователя и выбираю роль для пользователя, оно добавляет его. Я могу добавить несколько ролей для пользователя или удалить их, кроме последней. Я не могу удалить последнюю. Если я попытаюсь удалить все роли для пользователя, он проигнорирует это и оставит роли, которые были выбраны ранее. (Я обнаружил такое же поведение в Grails 2.4.4.)

Домены:

class Role {
    String name
}

class User {
    String name
    static hasMany = [roles: Role]
}

Представление scaffolding создает поле выбора html с:

<g:select name="roles" from="${myapp.Role.list()}" 
    multiple="multiple" optionKey="id" size="5"
    value="${userInstance?.roles*.id}" class="many-to-many"/>

Создание этого HTML:

<select id="roles" class="many-to-many" size="5" multiple="multiple" name="roles">
<option selected="selected" value="1">myapp.Role : 1</option>
<option value="2">myapp.Role : 2</option>
</select>

Воспроизвести:

  1. Запустите приложение
  2. Создайте несколько ролей
  3. Создайте нового пользователя, введите имя, выберите одну или несколько ролей и нажмите «Создать».
  4. Отредактируйте пользователя, отмените выбор ролей и нажмите «Обновить».
  5. Обратите внимание, что предыдущие роли по-прежнему выбраны

Я понимаю, что с формой для этого поля ничего не отправляется, если ничего не выбрано. Я могу исправить это, выполнив user.roles.clear() перед привязкой. Это работает, но мне интересно ...

Неужели строительные леса не предназначены для этого случая? Или я что-то делаю неправильно, например, в коде моих доменов? Есть ли лучшее решение, чем редактирование строительных лесов, чтобы очистить роли перед связыванием?


person tbird    schedule 17.08.2015    source источник
comment
попробуйте добавить belongsTo=[user:User] в модель ролевой области. В документации есть строчка По умолчанию каскадное поведение заключается в каскадном сохранении и обновлении, но не удалении, если также не указан ownTo; Я не уверен, что это сработает, но попробовать стоит. Если это не сработает, я бы посоветовал позвонить user.roles.clear() перед привязкой, как вы предложили.   -  person ionutab    schedule 18.08.2015
comment
@ionutab: Я хочу отношения "многие ко многим". У нескольких пользователей может быть одна и та же роль. И, конечно же, у пользователя может быть много ролей. Итак, я не могу использовать ownTo.   -  person tbird    schedule 18.08.2015
comment
Если вам нужна связь «многие ко многим», то приведенный выше код неверен. У вас также должно быть объявление hasMany = [] в модели ролевой области. Кроме того, в классе Role вам необходимо указать владельца отношения, User, в вашем случае с помощью карты ownTo. прочтите здесь   -  person ionutab    schedule 18.08.2015
comment
Я не кодировал его как двунаправленный, но он функционирует как «многие ко многим», просто без удобства легкого двунаправленного доступа. Все работает правильно, за исключением того, что скаффолдинг не удалит последнюю ссылку из набора ролей. Я мог бы использовать ownTo, если бы сделал его двунаправленным. Я попробовал ваше предложение и перестроил строительные леса, но он ведет себя так же, поскольку не может удалить последнюю роль. Я обнаружил, что в документах прямо говорится, что леса не поддерживают "многие ко многим".   -  person tbird    schedule 19.08.2015


Ответы (1)


Я не уверен, как отменить выбор ролей, поскольку при редактировании в форме всегда будет выбрана хотя бы одна роль, если вы добавили роль во время создания.

Чтобы добиться желаемого, вам нужно будет изменить представления, построенные на основе шаблонов. Используйте свойство noSelection для g: select, чтобы указать, каким должно быть значение по умолчанию, если пользователь не хочет выбирать какую-либо существующую роль.

Тогда ваш тег g: select будет:

<g:select name="roles" from="${myapp.Role.list()}" 
    noSelection="['': '--NoSelection--']"
    multiple="multiple" optionKey="id" size="5"
    value="${userInstance?.roles*.id}" class="many-to-many"/>

И Scaffolding позволяет вам создавать некоторые базовые интерфейсы CRUD для класса предметной области. Он не поддерживает многие вещи, и вам нужно реализовать их самостоятельно.

person Sandeep Poonia    schedule 18.08.2015
comment
Вы правы, функция в настоящее время не поддерживает многие -то-многим. Ваше noSelection исправление работает, если пользователь действительно его выбирает. Если они отменит выбор всех опций, это будет та же проблема. И, если вы выберете сразу и без выбора, и с ролью, появится ошибка Не удалось найти соответствующий конструктор. Javascript может все это исправить, но становится беспорядочным. Решение clear() кажется лучше, поскольку оно работает без выделения и ни в коем случае не выдает ошибки. - person tbird; 19.08.2015