Grails: Dynamically change domain's constraints in controller - grails

I'm a Grails beginner. I have a Domain class which has domainName field in Grails (ver. 2.0.1). In my DomainConstraints.groovy, I have:
constraints = {
domainName blank: false, matches: "^([^.]{0,63}\\.)*([^.]{1,63})\$"
}
but depending on some situation, i want to make this domainName field "blank: true" or "blank: false". I'm not validating my domain class against the actual database, so sync with the domain class and the actual table is not an issue.
So, I want to do something like this (code below is from my imagination):
if(something){
Domain.constraints.removeAttr('blank')
} else {
Domain.constraints.addAttr('blank', 'true')
}
Is this possible?

You could do something like this:
class DomainConstraints {
Boolean validateBlankFlag
String domainName
static transients = [validateBlankFlag]
static constraints = {
domainName validator : { val,obj -> !val?.equals("") || !obj.validateBlankFlag}
}
}
Then just set the validateBlankFlag on the domain object depending on whether you want to allow blank values or not. You may not even need the validateBlankFlag property if you can make the decision based on other property values within the DomainConstraints object.

Related

Grails data binding field exclusion

I am using Grails 2.5 and use Grails databinding in request methods.
For a basic example of the situation consider the following:
Domain class
class Product {
String field1
String privateField
}
Controller
class ProductController {
def update(Product productInstance) {
productInstance.save()
}
}
If I pass an existing Product to the controller like
{"id":3, "privateField":"newValue","field1":"whatever"}
the old value of privateField is overwritten. I want to enforce, that privateField is never bound from a request and avoid checking if the field is dirty.
Is there a mechanism in Grails to achieve this?
If I have to do the dirty check, how can I discard the new value and use the old one?
Pretty sure there's a "bindable" constraint.
http://grails.github.io/grails-doc/2.5.x/ref/Constraints/bindable.html
class Product {
String field1
String privateField
static constraints = {
privateField bindable: false
}
}
Should keep that field from binding automatically.
You can enforce which values are bound, but you'll need to change your method signature to get more control of the data binding process.
class ProductController {
def update() {
def productInstance = Product.get(params.id)
bindData(productInstance, params, [exclude: ['privateField']]
productInstance.save()
}
}

domain class constraint in entry creation

In my Grails project I need to add a particular constraint to an entry of my domain class object.
Domain class is as follows:
class HealthServiceType {
String healthService;
static belongsTo = [doctor:Doctor]
static constraints = {
}
static mapping = {
}
}
I need that healthService is not empty and is unique for each Doctor; that is, I can have multiple "test" value for healthService, but each one need to have different Doctor value.
Is it possible to perform this constraint in domain class? Or do I need to implement some check in Controller?
That's quite simple to make a unique property. For example:
static constraints = {
healthService(unique: ['doctor'])
}
The above will ensure that the value of healthService is unique for each value of doctor within your domain class.

How can I change the default Grails/GORM lookup?

I'm new to Grails. I'm developing a web app that handles the records of a gymnasium, to make routines, exercises, etc.
I have this domain class Ejercicios:
class Ejercicios {
String nombreEjercicio
String idHoja
String descripcion
List<String> descripcionO
static hasMany = [descripcionO: Descripciones]
static transients = ['descripcionTrans']
String descripcionTrans
static mapping = {
id column: "idHoja"
version false
}
static constraints = {
nombreEjercicio maxSize: 45
idHoja blank: false
}
The database table has the default Grails id named "idHoja", and another attribute named "id_hoja"
The thing here is that when I make a JSON parse from the rest API, I need GORM to look for exercises via the "id_hoja" attribute, not the "idHoja" because it'll cause a mismatch.
I found the solution by myself!
The only thing I needed to was to make the JSON call with the name "idHoja" and that was it.

Adding Dynamic Fields to Domain Object in Grails

I am trying to find a way to add dynamic fields to a grails domain class. I did find the dynamic domain class plugin based on Burt's article, but this is way too much for our needs.
Supposed we have a domain class of person:
class Person extends DynamicExtendableDomainObject {
String firstName
String lastName
static constraints = {
firstName(nullable: false, blank: false, maxSize: 50)
lastName(nullable: false, blank: false)
}
}
Now customer a wants to also have a birthdate field in this. By using some sort of management tool, he adds this extra field in the database.
Customer b wants to also have a field middle name, so he is adding the field middle name to the person.
Now we implemented a DynamicExtendableDomainObject class, which the Person class inherits from. This adds a custom field to each Domain class inheriting from this to store the dynamic properties as JSON in it (kind of like KiokuDB in Perl stores them).
Now when Person is instantiated, we would like to add those dynamic properties to the Person class, to be able to use the standard Grails getter and setter as well as Templating functions for those.
So on customer a we could use the scaffolding and person would output firstName, lastName, birthDate, on customer b the scaffolding would output firstName, lastName, middleName.
The storing of the properties will be implemented by using the saveinterceptor, to serialize those properties to JSON and store them in the special field.
But we have not yet found a way to add these JSON properties dynamically to the domain class during runtime. Is there a good way to handle this? And if so, how to best implement this?
You can try to add the properties at runtime to the DomainClass of type DynamicExtendableDomainObject by expanding getProperty(), setProperty(), setProperties() in the metaClass and then use beforeUpdate(), beforeInsert() and afterLoad() to hook into Persistence.
For example in Bootstrap (or service):
def yourDynamicFieldDefinitionService
for(GrailsClass c in grailsApplication.getDomainClasses()){
if(DynamicExtendableDomainObject.isAssignableFrom(c.clazz)){
Set extendedFields = yourDynamicFieldDefinitionService.getFieldsFor(c.clazz)
//getProperty()
c.clazz.metaClass.getProperty = { String propertyName ->
def result
if(extendedFields.contains(propertyName)){
result = delegate.getExtendedField(propertyName)
} else {
def metaProperty = c.clazz.metaClass.getMetaProperty(propertyName)
if(metaProperty) result = metaProperty.getProperty(delegate)
}
result
}
//setProperty()
c.clazz.metaClass.setProperty = { propertyName , propertyValue ->
if(extendedFields.contains(propertyName)){
delegate.setExtendedField(propertyName, propertyValue)
delegate.blobVersionNumber += 1
} else {
def metaProperty = c.clazz.metaClass.getMetaProperty(propertyName)
if(metaProperty) metaProperty.setProperty(delegate, propertyValue)
}
}
//setProperties()
def origSetProperties = c.clazz.metaClass.getMetaMethod('setProperties',List)
c.clazz.metaClass.setProperties = { def properties ->
for(String fieldName in extendedFields){
if(properties."${fieldName}"){
delegate."${fieldName}" = properties."${fieldName}"
}
}
origSetProperties.invoke(delegate,properties)
}
}
}
with
abstract DynamicExtendableDomainObject {
String yourBlobField
Long blobVersionNumber //field to signal hibernate that the instance is 'dirty'
Object getExtendedField(String fieldName){
...
}
void setExtendedField(String fieldName, Object value){
...
}
def afterLoad(){
//fill your transient storage to support getExtendedField + setExtendedField
}
def beforeUpdate(){
//serialize your transient storage to yourBlobField
}
def beforeInsert(){
//serialize your transient storage to yourBlobField
}
}

How do I fake a validation error?

I'm using the Grails Webflow plugin. Here are the domain objects I'm working with:
class Foo implements Serializable {
String fooProp1,
fooProp2
static constraints = {
fooProp2 nullable: false
}
}
class Bar implements Serializable {
Foo fooObject
static constraints = {
fooObject nullable: false
}
}
At a point in the webflow, I need to make sure that fooObject.fooProp1 is not null. If it is, I want to throw an error and force the user to supply it with a value. I tried using validate() to do this (on both the Bar and Foo objects), but since fooProp1 has the nullable:true property, it passes validation. Any ideas?
You can probably do this in the Web Flow by adapting the following code:
if(fooObject.fooProp1 == null) {
fooObject.errors.rejectValue('fooProp1', 'nullable')
}
The second argument to that method, 'nullable', might be different for your situation. You'll just need to set it to the message code (from message.properties) to display the error message that you want.
Have a look here for more ways to use reject() and rejectValue().

Resources