Assume I have the following Foo object:
Foo foo = new Foo(foo: "foo", bar: "bar", baz: "baz")
I know how to validation specific constraints:
foo.validate(["foo", "bar"]) // validates the "foo" property and the "bar" property, but not the "baz" property
I also know how to forego validation all together:
foo.save(validate: false)
But I don't know how to tell Grails to validate all constraints except those in a list. I could make a method that does what I want, but I wanted to make sure there wasn't a Groovy way to do it first.
Update
Here is how I will do this if there isn't a "groovier" way.
// This method exists in my Util.groovy class in my src/groovy folder
static def validateWithBlacklistAndSave(def obj, def blacklist = null) {
def propertiesToValidate = obj.domainClass.constraints.keySet().collectMany{ !blacklist?.contains(it)? [it] : [] }
if(obj.validate(propertiesToValidate)) {
obj.save(flush: true, validate: false)
}
obj
}
Considering the below Foo domain class
class Foo {
String foo
String bar
String baz
static constraints = {
foo size: 4..7
bar size: 4..7
baz size: 4..7
}
}
Validation for baz can be excluded as follows:
Foo foo = new Foo(foo: "fool", bar: "bars", baz: "baz")
//Gather all fields
def allFields = foo.class.declaredFields
.collectMany{!it.synthetic ? [it.name] : []}
//Gather excluded fields
def excludedFields = ['baz'] //Add other fields if necessary
//All but excluded fields
def allButExcluded = allFields - excludedFields
assert foo.validate(allButExcluded)
assert foo.save(validate: false) //without validate: false, validation kicks in
assert !foo.errors.allErrors
There is no direct way to send a list of excluded fields for validation.
You can define customized constraints maps, which you can then effectively filter from either supporting command classes or Config.groovy via exclude parameter.
Related
We're migrating from Grails 2.x to 3.x. I can observe some different behaviour when using the forward function:
class FooController {
def index() {
forward controller: 'foo', action : 'bar', params: params
}
def bar() {
render(
view: "/foo/foo"
)
}
}
When calling http://localhost:8080/foo?test=1 and halting in the bar() method I can see that params looks like that:
params = {GrailsParameterMap#11597} size = 4
0 = {LinkedHashMap$Entry#11607} "test" ->
key = "test"
value = {String[2]#11612}
0 = "1"
1 = "1"
1 = {LinkedHashMap$Entry#11608} "controller" -> "foo"
2 = {LinkedHashMap$Entry#11609} "format" -> "null"
3 = {LinkedHashMap$Entry#11610} "action" -> "bar"
As you can see the value of test is saved twice as a String[]. This behaviour is different than it used to be in Grails 2.5.6.
Is there any way to set a flag to the Grails forward function in order to not get the params passed to the redirect controller?
I think you don't need to add the param. forward automatically forwards your parameters. It's optional. If you add it, it will duplicate the values. Try with only:
forward controller: 'foo', action : 'bar'
I want to return an object(#state) along with true or false from rails method in application helper.
I have a model named User which calls an action which is in applicaiton helper.
class User
include ApplicationHelper
*****-----_********
def user_state
user = self
state = get_state(user)
end
end
in applicaiton helper,
def get_state (user)
#user = User.find(user.id)
#state = UserState.where('user_id = ?',#user.id)
if #state.present?
*** here I want to return #state along with true ****
return true
else
return false
end
end
I tried 'return #state and true' didn't work but, 'return #state' worked.
Seems to me either object or a boolean can be returned and not both at once.
Is there any way to return both of them. Thankyou in advance.
Well, I'm not sure a "Helper" is what you need here, but returning multiple values from a ruby method is pretty easy:
def myfun(x)
if x
[true, "one"] # or use return true, "one"
else
false
end
end
a, b = myfun(true)
p a, b # prints true, "one"
a, b = myfun(false)
p a, b # prints false, nil
I've been trying to take advantage of operator overloading in Groovy by defining a custom putAt method in my POGO like this:
class Book {
Map additionalInfo = [:]
def putAt(key, value) {
additionalInfo[key] = value
}
}
So that I can do something like, book['notes'] = 'I like this one.' (let's say this makes sense). However, I've been getting:
groovy.lang.MissingPropertyException: No such property: notes for class: Book
at BookSpec.Set property using putAt(BookSpec.groovy:40)
My class is part of a Grails application so I'm not sure if Grails has something to do with the problem. Can anyone enlighten me on this?
The signature should be
def putAt(String key, value)
Instead of doing putAt and then override the operator, there is an easy/better way by adding the propertyMissing methods.
Here is the link for more explanation.
class Foo {
def storage = [:]
def propertyMissing(String name, value) { storage[name] = value }
def propertyMissing(String name) { storage[name] }
}
def f = new Foo()
f.foo = "bar"
assertEquals "bar", f.foo
I need to perform a null or empty check on a collection; I think that !members?.empty is incorrect. Is there a groovier way to write the following?
if (members && !members.empty) {
// Some Work
}
There is indeed a Groovier Way.
if (members) {
//Some work
}
does everything if members is a collection. Null check as well as empty check (Empty collections are coerced to false). Hail Groovy Truth. :)
FYI this kind of code works (you can find it ugly, it is your right :) ) :
def list = null
list.each { println it }
soSomething()
In other words, this code has null/empty checks both useless:
if (members && !members.empty) {
members.each { doAnotherThing it }
}
def doAnotherThing(def member) {
// Some work
}
!members.find()
I think now the best way to solve this issue is code above. It works since Groovy 1.8.1 http://docs.groovy-lang.org/docs/next/html/groovy-jdk/java/util/Collection.html#find(). Examples:
def lst1 = []
assert !lst1.find()
def lst2 = [null]
assert !lst2.find()
def lst3 = [null,2,null]
assert lst3.find()
def lst4 = [null,null,null]
assert !lst4.find()
def lst5 = [null, 0, 0.0, false, '', [], 42, 43]
assert lst5.find() == 42
def lst6 = null;
assert !lst6.find()
Is their a dynamic namedquery on grails? Im not sure if its the right term but, I mean a namedquery that can be true to all.
Something like:
namedQueries = {
dynamicQuery{ term, name, value ->
term(name, value)
}
}
Then it can be called maybe like but not exactly:
def testClass = TestClass.dynamicQuery('eq', 'lastname', 'Bill').list()
and so you call it too like:
def testClass = TestClass.dynamicQuery('gt', 'id', 12).list()
This one might not work but is their something similar in grails?
UPDATE
The idea is that so I can chained it as many as I want like:
def testClass = TestClass.dynamicQuery('gt', 'id', 12).dynamicQuery('eq', 'stat', 11).list()
This is so that I dont have to create many namedqueries. I was hoping I can create one and use it multiple times.
Grails' createCriteria method generates Grails HibernateCriteriaBuilder instance, within which you can call invokeMethod method to dynamically create query criteria, which usually is defined by the standard DSL.
Here is a example in some controller:
private String dynamicCriteriaTest(String term, name, value) {
def c = TestClass.createCriteria()
def param = []
param << name
param << value
def result = c.list{
c.invokeMethod(term, param as Object[])
}
return result.toString()
}
def test() {
render dynamicCriteriaTest('eq','lastname','Bill')
}
That will get something you want.
update
If you want to call this method multiple times, pass the criteria parameters in an a List then execute the query:
private List dynamicCriteriaTest(List param) {
def c = TestClass.createCriteria()
def paramList = param.collate(3) //split the parameters into groups
def result = c.list{
paramList.each { paramInstance ->
def command = paramInstance[0]
paramInstance.remove(0)
c.invokeMethod(command, paramInstance as Object[])
}
}
return result
}
def test() {
ArrayList param = new ArrayList()
//the 1st criteria
param << 'gt'
param << 'id'
param << (long)12 //you have to check the Grails [HibernateCriteriaBuilder] API to make sure the parameter passed to `invokeMethod` is in the right type (e.g. **long** in this case)
//the 2nd one
param << 'eq'
param << 'stat'
param << (long)11
//even more
param << 'like'
param << 'description'
param << 'some text%'
render dynamicCriteriaTest(param)
}
In Grails you have NamedQueries and also Where Queries. The example you give can possibly be implemented by using a namedqueries and placing this in a abstract domain class. Your domain classes should extend this abstract domain.