Create custom Validator - grails

How should I create and configure a validator class to use it as a domain class constraint? For example:
class Link {
String url
static constraints = { url url:true }
}
Motivation: Grails UrlValidator does not allow underline character despite it being valid, see rfc2396, section 2.3. Unreserved Characters.

You can have a utility class in src/groovy with required validators (as static properties) and refer them in the concerned domain class.
//src/groovy
class MyValidators{
static urlCheck = {url, obj ->
//custom validation for url goes here.
}
}
class Link {
String url
static constraints = {
url validator: MyValidators.urlCheck
}
}
If there is no need to externalize the validator to a separate utility class then you can directly use the validator in domain class as:
static constraints = {
url validator: {value, obj -> ...}
}

Related

In Grails, how do I apply an inList constraint from a 3rd party data source?

Let's say I have the following model:
class Product {
String name
String price
String currency
static constraints = {
currency inList: ['USD', 'EUR']
}
Now we have a new requirement that inList constraint for currency must be pulled from a service:
class CurrencyService {
def getAvailableCurrencies = {
...
}
}
How do I make this work? I tried:
class Product {
def currencyService
...
static constraints = {
currency inList: currencyService.getAvailableCurrencies()
}
}
But I can't access the currencyService instance in the static constraints context. I also tried using static currencyService, but this likewise does not work. Any ideas?
As dmahapatro mentioned above, you could use a custom validator which uses your service:
static constraints = {
currency validator: { value, obj ->
if (!(value in obj.currencyService.getAvailableCurrencies()))
return ['invalid.currency']
}
}

Import domain in constraints

I have 2 domain classes
class a {
String name
static constraints = {
name unique:true
}
}
class b {
String description
}
and in domain class b I want to call class a
import a
class b {
String description
static constraints = {
description unique:'a.name'
}
}
and get error
Scope for constraint [unique] of property [description] of class [b] must be a valid property name of same class
How do I get a property from class a to b?
Assuming you try to do this in Grails 2+
You can't use validation that way. In your example you need to reference to a property of the same domain class. To correct the constraint in class B you can write:
class B {
String description
static contraints = {
description unique:true
}
}
But I think you want to import the constraints from class a which is done like this.
class B {
String description
static contraints = {
importFrom A
}
}
See http://grails.org/doc/latest/guide/validation.html#sharingConstraints
This will import all constraints on properties that the two classes share. Which in your case is none.
UPDATE
I got a similar question and found a solution for it. So I thought to share it here with you.
The problem can be solved with a custom validator. In your case constraints for class B:
static constraints = {
description(validator: {
if (!it) {
// validates to TRUE if the collection is empty
// prevents NULL exception
return true
}
def names = A.findAll()*.name
return names == names.unique()
})
}
It's difficult to answer your question correctly since the requirements are a bit odd. But maybe it will help.
You need to write a custom validator to check the uniqueness since it relies on more information than the single instance of b will have.
Something like
static constraints {
description validator: { val ->
!a.findByName(val)
}
}
might do the trick.

Cannot use grails g.link in domain class

I have static method in a domain class that returns a url. I need to build that url dynamically but g.link isn't working.
static Map options() {
// ...
def url = g.link( controller: "Foo", action: "bar" )
// ...
}
I get the following errors:
Apparent variable 'g' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attempted to reference a variable in the binding or an instance variable from a static context.
You misspelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'g' but left out brackets in a place not allowed by the grammar.
# line 17, column 19.
def url = g.link( controller: "Foo", action: "bar" )
^
1 error
Obviously my problem is that I am trying to access g from static context, so how do I get around this?
The g object is a taglib, which is not available inside a domain class like it would be in a controller. You can get at it through the grailsApplication as shown here: How To Call A Taglib As A Function In A Domain Class
A better way to do this in Grails 2+ is through the grailsLinkGenerator service, like so:
def grailsLinkGenerator
def someMethod() {
def url = grailsLinkGenerator.link(controller: 'foo', action: 'bar')
}
In both cases, you'll need to do some extra work to get grailsApplication/grailsLinkGenerator from a static context. The best way is probably to grab it off the domainClass property of your domain class:
def grailsApplication = new MyDomain().domainClass.grailsApplication
def grailsLinkGenerator = new MyDomain().domainClass.grailsApplication.mainContext.grailsLinkGenerator
If you're using Grails 2.x you can use the LinkGenerator API. Here's an example, I am re-using a domain class I was testing with earlier so ignore the non-url related functionality.
class Parent {
String pName
static hasMany = [children:Child]
static constraints = {
}
static transients = ['grailsLinkGenerator']
static Map options() {
def linkGen = ContextUtil.getLinkGenerator();
return ['url':linkGen.link(controller: 'test', action: 'index')]
}
}
Utility Class with Static Method
#Singleton
class ContextUtil implements ApplicationContextAware {
private ApplicationContext context
void setApplicationContext(ApplicationContext context) {
this.context = context
}
static LinkGenerator getLinkGenerator() {
getInstance().context.getBean("grailsLinkGenerator")
}
}
Bean Def for New Utility Bean
beans = {
contextUtil(ContextUtil) { bean ->
bean.factoryMethod = 'getInstance'
}
}
If you need the base URL, add absolute:true to the link call.

How to handle Many-To-Many In Grails without belongsTo?

I need to create a many-to-many relationship in Grails.
I have a "Question" domain and a "Tag" domain.
A Question can have 0 or more tags. A Tag can have 0 or more Questions.
If I put a "hasMany" on each sides, it gives me an error saying I need a "belongTo" somewhere.
However, adding a belongsTo means that the owner must exist...
Like I said, a Tag could have 0 questions, and a Question could have 0 tags.
There is no concept of an owner, it's a many-to-many!
What am I supposed to do?
you can do this (please see the code below). but does it make sense to have a question tag with out both a question and a tag?
package m2msansbt
class Question {
String toString() { return name }
String name
static hasMany=[questionTags:QuestionTag]
static constraints = {
}
}
package m2msansbt
class Tag {
String toString() { return name }
String name
static hasMany=[questionTags:QuestionTag]
static constraints = {
}
}
package m2msansbt
class QuestionTag {
Question question
Tag tag
static QuestionTag link(Question question,Tag tag) {
QuestionTag questionTag=QuestionTag.findByQuestionAndTag(question,tag)
if (!questionTag) {
questionTag = new QuestionTag()
question?.addToQuestionTags(questionTag)
tag?.addToQuestionTags(questionTag)
questionTag.save()
}
return questionTag
}
static void unlink(Question question,Tag tag) {
QuestionTag questionTag=QuestionTag.findByQuestionAndTag(question,tag)
if (questionTag) {
question?.removeFromQuestionTags(questionTag)
tag?.removeFromQuestionTags(questionTag)
questionTag.delete()
}
}
static constraints = {
}
}
import m2msansbt.*
class BootStrap {
def init = { servletContext ->
Question q1=new Question(name:'q1')
Tag t1=new Tag(name:'t1')
Tag t2=new Tag(name:'t2')
q1.save()
t1.save()
t2.save()
QuestionTag q1t1=QuestionTag.link(q1,t1)
q1t1.save()
QuestionTag q1t2=QuestionTag.link(q1,t2)
q1t2.save()
q1.save()
t1.save()
}
def destroy = {
}
}
If your main concern is the cascading delete, you can take a look at 5.5.2.9 in the grails docs to manually disable it for the mapping.
I haven't tried it, but I think the mappedBy property can be used to solve this.
Checkout the Taggable Plugin.
It seems to solve the problem you are having and you could look at the source code if you want to see how they modeled the relationship. BTW this plugin was originally created by Graeme Rocher who is the lead developer on Grails.
This works for me on Grails 2.4.4. Add a "belongsTo" with just the classname.
class Question {
String toString() { return name }
String name
static hasMany=[tags:Tag]
static constraints = {
}
}
class Tag {
String toString() { return name }
String name
static hasMany=[questions:Question]
static belongsTo = Question
static constraints = {
}
}

Grails domain class properties from properties file

In my grails application I want to read some values from properties file and set it to Grails Domain class static property at startup.
Example
Class A{
static myValues="1,2";
}
class B{
static myValues="2,3";
}
In the above example I have directly given the inputs..Instead of that I want to read it from one config.properties file which will have the following
A=1,2
B=2,3
Is it possible to do that in grails.Help me please.
If you put config.properties in grails-app/conf then it'll be in the classpath and this code in grails-app/conf/BootStrap.groovy will load the properties and set the values:
class BootStrap {
def init = { servletContext ->
def props = new Properties()
def cl = Thread.currentThread().contextClassLoader
props.load cl.getResourceAsStream('config.properties')
props.each { key, value ->
def clazz = Class.forName(key, true, cl)
clazz.myValues = value
}
}
}
Obviously you'll need to check that the properties file is available, that the classes, exist, etc.

Resources