beforeUpdate не вызывается, когда изменились только переходные процессы - PullRequest
2 голосов
/ 01 декабря 2011

Я использую Grails 2.0.0.RC2, и у меня есть класс User, подобный этому:

class User {
    String username
    String password

    // Idea from http://grailsrecipes.wordpress.com/2009/04/19/grails-user-registration-and-login/ .
    String formPassword
    String formPasswordConfirm

    // Constraints and validation ommited

    static transients = ['formPassword', 'formPasswordConfirm']

    def beforeUpdate() {
        println("Inside beforeUpdate")
        if (formPassword != null)
            encodePassword()
    }

    protected void encodePassword() {
        password = formPassword // Just for this case
    }
}

Когда пользователь запрашивает сброс пароля, я отправляю ему электронное письмо со ссылкой для сброса пароляФорма сброса пароля проста - она ​​содержит только два поля: formPassword и formPasswordConfirm.Я делаю простое действие в контроллере: user.formPassword = params["formPassword"] и user.formPasswordConfirm = params["formPasswordConfirm"].Затем я делаю (user.save()) - и начинается проблема.

Моя проблема в том, что beforeUpdate() не вызывается.Я думал, что это проблема проверки (здесь она опущена), но это не так.Оказывается, user.save() не сохранял пользователя в базе данных!Зачем?Я хотел, чтобы это было сохранено, пароль должен быть изменен.Но user.isDirty() ложно как раз перед user.save().Это потому, что ни одно из постоянных свойств не было изменено.Это правда.Поскольку user.save() не был вызван - beforeUpdate() также не был вызван.

Это желаемое поведение?Может быть, это ошибка Grails, и beforeUpdate() всегда нужно вызывать перед обновлением, а затем проверять isDirty()?Что ты думаешь?

Ответы [ 2 ]

3 голосов
/ 01 декабря 2011

Я не знаю, следует ли вызывать beforeUpdate при обновлении переходных полей, но, учитывая выбор между

  1. , это ошибка Grails / Hibernate
  2. этоожидаемое поведение, потому что при изменении временных полей обновления БД не происходили бы

Я бы поставил много денег на 2 и очень мало на 1.

Так что оставив это в стороне, яЯ думаю, что вы сделали свой домен более сложным, чем нужно.В частности, вы должны быть в состоянии достичь своей цели с помощью 2 полей пароля вместо 3.

class User {

    static transients = ['passwordConfirm']
    def springSecurityService

    String password
    String passwordConfirm

    static constraints = {
        password blank: false, validator: {password, self ->

            // We only need to check the password confirmation when it is not empty, i.e.
            // when a user registers or resets their password
            if (self.passwordConfirm) {
                password == self.passwordConfirm
            }
        }
    }

    def beforeInsert() {
        encodePassword()
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
        }
    }

    private void encodePassword() {
        password = springSecurityService.encodePassword(password)
        passwordConfirm = springSecurityService.encodePassword(passwordConfirm)
    }

}

Ваше действие контроллера сброса пароля должно выглядеть следующим образом:

def resetPassword = {

    User user = User.findByUsername(params.username)
    user.password = params.formPassword
    user.passwordConfirm = params.formPasswordConfirm

    if (user.save()) {
        // It worked, send them to the login page or whatever...
    } else {
        // Validation failed, send them back to the reset password page    
    }
}
1 голос
/ 01 декабря 2011

Это желаемое поведение.

Семантика, на мой взгляд, довольно кристально чистая, вы не изменили никаких постоянных полей, поэтому не нужно ничего сохранять. .Save () не может угадать, что в этом случае какое-то временное свойство должно заставить вас выполнить save () (а затем beforeUpdate ()).

Просто добавьте метод, который обновляет пароль, и все готово.

...