Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Ticket #2366 (closed task: migrated)

Opened 5 years ago

Last modified 3 years ago

Find better solution for validation of arguments to controller methods set as error_handler

Reported by: Chris Arndt Owned by: Chris Arndt
Priority: normal Milestone: 1.1.x bugfix
Component: TurboGears Version: 1.1 HEAD
Severity: normal Keywords: validate, validation, error_handler
Cc:

Description

The current limit of one validation pass per request is not ideal in some situations. For example, for CRUD controllers, I constantly have to use the following pattern:

# This checks if the value is a valid foo ID and converts it into a matching Foo object
# This keeps the controller methods free from boiler-plate database access code.
foo_validator = ValidFoo()

class FooCRUDController(controller.Controller)

    @expose(template="mypkg.templates.foo_new")
    @validate(validators=dict(foo=foo_validator))
    def new(self, tg_errors=None, **kw):
        # When this method is run as the error handler of the 'create' method
        # the validate decorator of this method will not be effective
        # we therefore need to turn the foo ID into a Foo object manually.
        group = kw.get('foo')
        if not isinstance(foo, Foo):
            try:
                group = ValidFoo()._to_python(group, state=None)
            except validators.Invalid, exc:
                if tg_errors is None:
                    tg_errors = dict()
                tg_errors['foo'] = exc
        values = dict()
        if not tg_errors and isinstance(group, Group):
            # display foo_create_form

    @expose()
    @validate(form=foo_create_form)
    @error_handler(new)
    def create(self, foo, attr1, attr2, ...):
        # create Foo object

The same pattern is used for the edit/update methods. Not only is this very tedious, error_prone and redundant (though I could probably write a custom validator for it), it is also only a workaround for a symptom and doesn't address the real problem, i.e. that validate decorater on the "new" method is ineffective, when "new" is run as the error handler of the "create" method.

Without knowing the internals of the validation framework, someone would probably just write:

class FooCRUDController(controller.Controller)

    @expose(template="mypkg.templates.foo_new")
    @validate(validators=dict(foo=ValidFoo()))
    def new(self, foo, tg_errors=None, **kw):
        if not tg_errors:
            # display foo_create_form

    @expose()
    @validate(form=foo_create_form)
    @error_handler(new)
    def create(self, foo, attr1, attr2, ...):
        # create Foo object

... and things would work as long there is no validation error. It has bitten me a hundred times when I forgot to use the above pattern and suddenly got strange results, because my "new" method received a string argument instead of an model object because the ValidFoo validator was ineffective.

I have opened this ticket as a reminder to think about a better and more general solution for the whole validation / error_handler issue.

Change History

comment:1 Changed 5 years ago by Chris Arndt

  • Owner set to Chris Arndt
  • Status changed from new to assigned

comment:2 Changed 5 years ago by Chris Arndt

  • Milestone changed from 1.1 to 1.1.x bugfix

Moving to 1.1.x bugfix release in preparation for 1.1rc1 release.

comment:3 Changed 3 years ago by chrisz

  • Status changed from assigned to closed
  • Resolution set to migrated
Note: See TracTickets for help on using tickets.