Validating a group of fields in grails domain object - grails

I have a command object that captures a feedback form with 3 textareas.
class FeedbackCommand {
String textarea1
String textarea2
String textarea3
String username
static constraints = {
textarea1(nullable:true, blank:true)
textarea2(nullable:true, blank:true)
textarea3(nullable:true, blank:true)
username(nullable:false, blank:false)
}
}
I'd like to ensure that at least ONE of the textareas is filled out.
I came up with adding a fake flag field as a 'constraint' field, and then doing a bunch of object checks in the custom validator for that field. If after looking around in myself and i dont find what I want, I throw an error.
Right now, I'm doing this:
class FeedbackCommand {
String textarea1
String textarea2
String textarea3
boolean atLeastOne = true
String username
static constraints = {
textarea1(nullable:true, blank:true)
textarea2(nullable:true, blank:true)
textarea3(nullable:true, blank:true)
atLeastOne(validator: { boolean b, FeedbackCommand form, Errors err ->
if (b) {
if ( (form.textarea1==null || form.textarea1?.isAllWhitespace()) &&
(form.textarea2==null || form.textarea2?.isAllWhitespace()) &&
(form.textarea3==null || form.textarea3?.isAllWhitespace()))
{
// They havent provided ANY feedback. Throw an error
err.rejectValue("atLeastOne", "no.feedback")
return false
}
}
return true
})
username(nullable:false, blank:false)
}
}
Is there a better way to
validate a related/group of fields (at least one can't be blank, 2 should have values, etc)?
a groovier way to express "at least one shouldnt be null/blank" rather than my gross if-statement block?
Thanks

The Extended Validation plugin also adds support for instance validators, which allow to define constraints over several field without defining an artificial flag field or without repeating the validator for each field involved.

validate a related/group of fields (at least one can't be blank, 2 should have values, etc)?
Try this:
if ( (form.textarea1?.trim() ? 1 : 0) +
(form.textarea2?.trim() ? 1 : 0) +
(form.textarea3?.trim() ? 1 : 0) < 2) {
err.rejectValue("atLeastTwo", "no.feedback")
return false
}
a groovier way to express "at least one shouldnt be null/blank" rather than my gross if-statement block?
This is slightly Groovier...
if (!( (form.textarea1?.trim() ?: 0) ||
(form.textarea2?.trim() ?: 0) ||
(form.textarea3?.trim() ?: 0) )) {
err.rejectValue("atLeastOne", "no.feedback")
return false
}

WRT validating a group of fields, you could assign the validator closure to one of the fields. You don't need any extra/ficticious field.
If it's going to be used often, create a plugin
http://www.zorched.net/2008/01/25/build-a-custom-validator-in-grails-with-a-plugin/
or use a plugin for constraints
http://grails.org/plugin/constraints
About grooviness I'm not an expert. But the safe navigator operator ?. makes unnecessary to ask for null
if ( form.textarea1?.isAllWhitespace() &&
form.textarea2?.isAllWhitespace() &&
form.textarea3?.isAllWhitespace() )
{
// They havent provided ANY feedback. Throw an error
err.rejectValue("atLeastOne", "no.feedback")
return false
}

You can use the min-criteria plugin for that.
http://www.grails.org/plugin/min-criteria

Related

Logic error in null clause

hi I have the following function :
def signup(String name){
def x =Human.where{name == name}
if(x != null)
{
def myhuman=new Human(name: name)
if(myhuman.save() && myhuman.validate())
{
redirect(url:"https//localhost:8080")
}
}
else
{
return
}
}
It works fine. I can create people with different names and I can't create a person with the same name, however I was wondering in that if why do we check for x!=null, shouldn't we check for x == null because we first look if such a person exists and if does not we create it. I tried with x==null and I can't ever create Human, can someone explain?
You check for x != null because you can not perform operations on a null object now can you? In fact it's more Groovy to do the following:
if (!x) {
// Logic
}
This works because of the Groovy Truth.
If x == null validates to true, then you proceed as normal performing whatever operations you need. However, since in your case x is not null, x == null will validate to false and skip the if block. This isn't specific to Grails, it's general programming.
You can use an Elvis operator, if the user does not exist you create a new one.
When a Human exist, it has an id, so you check if has an id, if not, you save it and do the redirect.
You don't need to validate the object, the save method validates the object before saving it, and if it is not validated, returns false.
Human human = Human.findByName(name)?: new Human(name: name)
if(!human.id && human.save()){
redirect(url:"https//localhost:8080")
}else{
return
}

Groovy removeAll closure not removing objects in Set

I'm using data binding with parent/child relationships in Grails 2.3.7 and am having trouble with deletes. The form has many optional children, and to keep the database tidy I'd like to purge blank (null) values. I've found some nice articles which suggest using removeAll to filter my entries but I can't get remove or removeAll to work!
For example... (Parent has 10 children, 5 are blank)
def update(Parent parent) {
parent.children.getClass() // returns org.hibernate.collection.PersistentSet
parent.children.size() // returns 10
parent.children.findAll{ it.value == null }.size() // returns 5
parent.children.removeAll{ it.value == null } // returns TRUE
parent.children.size() // Still returns 10!!!
}
I've read PersistentSet is finicky about equals() and hashCode() being implemented manually, which I've done in every domain class. What baffles me is how removeAll can return true, indicating the Collection has changed, yet it hasn't. I've been stuck on this for a couple days now so any tips would be appreciated. Thanks.
Update:
I've been experimenting with the Child hashcode and that seems to be the culprit. If I make a bare-bones hashcode based on the id (bad practice) then removeAll works, but if I include the value it stops working again. For example...
// Sample 1: Works with removeAll
int hashCode() {
int hash1 = id.hashCode()
return hash1
}
// Sample 2: Doesn't work with removeAll
int hashCode() {
int hash1 = id.hashCode()
int hash2 = value == null ? 0 : value.hashCode()
return hash1 + hash2
}
// Sample Domain classes (thanks Burt)
class Parent {
static hasMany = [children: Child]
}
class Child {
String name
String value
static constraints = {
value nullable: true
}
}
This behavior is explained by the data binding step updating data, making it dirty. (ie: child.value.isDirty() == true) Here's how I understand it.
First Grails data binding fetches the Parent and children, and the hashcode of each Child is calculated. Next, data updates are applied which makes child.value dirty (if it changed) but the Set's hashcodes remain unchanged. When removeAll finds a match it builds a hashCode with the dirty data, but that hashcode is NOT found in the Set so it can't remove it. Essentially removeAll will only work if ALL of my hashCode variables are clean.
So if the data must be clean to remove it, one solution is to save it twice. Like this...
// Parent Controller
def update(Parent parent) {
parent.children.removeAll{ it.value == null } // Removes CLEAN children with no value
parent.save(flush:true)
parent.refresh() // parent.children is now clean
parent.children.removeAll{ it.value == null } // Removes (formerly dirty) children
parent.save(flush:true) // Success!
}
This works though it's not ideal. First I must allow null values in the database, though they only exist briefly and I don't want them. And second it's kinda inefficient to do two saves. Surely there must be a better way?
hashCode and equals weirdness aren't an issue here - there are no contains calls or something similar that would use the hashCode value and potentially miss the actual data. If you look at the implementation of removeAll you can see that it uses an Iterator to call your closure on every instance and remove any where the closure result is truthy, and return true if at least one was removed. Using this Parent class
class Parent {
static hasMany = [children: Child]
}
and this Child
class Child {
String name
String value
static constraints = {
value nullable: true
}
}
and this code to create test instances:
def parent = new Parent()
5.times {
parent.addToChildren(name: 'c' + it)
}
5.times {
parent.addToChildren(name: 'c2' + it, value: 'asd')
}
parent.save()
it prints 5 for the final size(). So there's probably something else affecting this. You shouldn't have to, but you can create your own removeAll that does the same thing, and if you throw in some println calls you might figure out what's up:
boolean removeAll(collection, Closure remove) {
boolean atLeastOne = false
Iterator iter = collection.iterator()
while (iter.hasNext()) {
def c = iter.next()
if (remove(c)) {
iter.remove()
atLeastOne = true
}
}
atLeastOne
}
Invoke this as
println removeAll(parent.children) { it.value == null }

Using a query in an Adapter for listview

I have a listview that I fill from an Adapter. My original code the data was being returned from a table, but now I need to get the code from a query with a join so the examples I used will no longer work and I haven't been able to find out how to use a query for this. I'm using an ORMrepository.
In my ORMrepository I have this function
public IList<Coe> GetmyCoe()
{
using (var database = new SQLiteConnection(_helper.WritableDatabase.Path))
{
string query = "SELECT Coe.Id, Adult.LName + ', ' + Adult.MName AS Name, Coe.Createdt FROM Adult INNER JOIN Coe ON Adult.CoeMID = Coe.Id";
return database.Query<Coe>(query);
}
}
which actually returns the data I want.
then in my Activity page I have this.
_list = FindViewById<ListView>(Resource.Id.List);
FindViewById<ListView>(Resource.Id.List).ItemClick += new System.EventHandler<ItemEventArgs>(CoeList_ItemClick);
var Coe = ((OmsisMobileApplication)Application).OmsisRepository.GetmyCoe();
_list.Adapter = new CoeListAdapter(this, Coe);
My Adapter page is where I have the problem, I know it is set up to to looking at a table which I'm not doing anymore. But I don't know how to change it for what I'm passing into it now. Current CoeListAdapter is:
public class CoeListAdapter : BaseAdapter
{
private IEnumerable<Coe> _Coe;
private Activity _context;
public CoeListAdapter(Activity context, IEnumerable<Coe> Coe)
{
_context = context;
_Coe = Coe;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = (convertView
?? _context.LayoutInflater.Inflate(
Resource.Layout.CoeListItem, parent, false)
) as LinearLayout;
var Coe = _Coe.ElementAt(position);
view.FindViewById<TextView>(Resource.Id.CoeMID).Text = Coe.Id.ToString();
//view.FindViewById<TextView>(Resource.Id.GrdnMaleName).Text = Coe.Name;
view.FindViewById<TextView>(Resource.Id.CreateDt).Text = Coe.CreateDt;
return view;
}
public override int Count
{
get { return _Coe.Count(); }
}
public Coe GetCoe(int position)
{
return _Coe.ElementAt(position);
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return position;
}
}
How do I set up the CoeListAdapter.cs page so that it can use the passed in data. As you can see I have a commented out lines where I fill a TextView which error because Coe.Name is not in the table model for Coe. but it is returned in the query. I believe my problem is IEnumerable but what do I change it to. I'm new to Mobile developement and suing VS2010 for Mono
The problem probably lies with the binding/mapping of the object not the creation of the view.
Or probably more specifically, the query.
Adult.LName + ', ' + Adult.MName AS Name
this should be:
Adult.LName || ', ' || Adult.MName AS Name
See also: String concatenation does not work in SQLite
From the sqlite docs: http://www.sqlite.org/lang_expr.html under the Operators heading:
The unary operator + is a no-op. It can be applied to strings,
numbers, blobs or NULL and it always returns a result with the same
value as the operand.
Note that there are two variations of the equals and not equals
operators. Equals can be either = or ==. The non-equals operator can
be either != or <>. The || operator is "concatenate" - it joins
together the two strings of its operands. The operator % outputs the
value of its left operand modulo its right operand.
The result of any binary operator is either a numeric value or NULL,
except for the || concatenation operator which always evaluates to
either NULL or a text value.
This shows that the + will evaluate to zero. If you use ||, the value will either be the correct value or NULL (if either of Adult.LName or Adult.MName is NULL).
This can be fixed by:
coalesce(first, '') || ', ' || coalesce(second, '')
but this may result in , LastName or FirstName,.
Another way would be to create another two properties in Coe called LName and MName.
Then bind the values to those properties and use the Name property like this:
public string Name
{
get { return string.Join(", ", LName, MName); }
}
This will probably be better as you can change how the Name appears especially if there are different combinations of First, Middle and Last names in different places.
And off topic:
I believe my problem is IEnumerable...
This is probably not too true as it returns the correct values. A better way would be to use IList as IEnumerable will iterate through the list each time to get the item as it does not know that the collection is actually a list. (I think)
thanks for the help on the concantination, I did find that was wrong, I did fix my problem, I was using an example by Greg Shackles on how to set up using a data base. what I had to do was create a new model with the elements I was wanting. So I created a new Model and called it CoeList, then everywhere I had List or IEnumerable I changed it to List or IEnumerable and it worked.

Groovy - Type testing?

I'm really brand new to Groovy and I'm trying to get something done. I've written some Groovy code (which works just fine) which receives some text. This text should be an integer (between 0 and 10). It may just happen a user enters something different. In that case I want to do some specific error handling.
Now I'm wondering, what's the best / grooviest way to test if a string-typed variable can be casted to an integer?
(what I want to do is either consume the integer in the string or set the outcome of my calculation to 0.
Thanks!
The String class has a isInteger() method you could use:
def toInteger (String input) {
if (input?.isInteger()) {
return input.toInteger()
}
return 0
}
use groovy contains
if ( x?.isInteger()) {
return (0..10).contains(x)
} else {
return false
}
Is this what you're saying?
Integer integer = 0
try {
integer = (Integer) string
assert integer > 0
assert integer < 10
catch(e) {
integer = 0
}
There are lots of ways this can be done in groovy, if you're comfortable with regular expressions, this is about as concise as you can get:
def processText(String text) {
text ==~ /(10|\d)/ ? text.toInteger() : 0
}
assert 0 == processText("-1")
(0..10).each {
assert it == processText("$it")
}
assert 0 == processText("11")
I'm a little unsure what you mean by "specific error handling" if the user does something different.
If this is a web application, I'd take a look at grails and the constraints that you can put on the fields of a domain object, that would let you easily express what you're trying to do.
You have the grails tag on your question, so if you are using Grails, you might consider making this an Integer property on a domain class. The param may come in as text, but you can bind it to an integer property with a default value of 0:
class MyDomain {
Integer whatever = 0
static constraints = {
whatever( min:0, max:10)
}
}

Making Grails data-binding interpret empty String values ("") as zero (0)

This question is about altering how the Grails data-binding handles string-to-integer conversion.
Consider the following domain object:
class Foo {
String name
Integer price
}
Furthermore, assume that the domain object is populated from HTTP request parameters:
def foo = new Foo(params).save()
The save() method above will fail if params.price == "" (empty string). I'd like to change this behaviour globally so that an empty string is parsed as zero (0) when converting from a string to an integer in Grails data-binding. How do I achieve that?
added a filter see the setion 5.5.1 Events and Auto Timestamping in the grails documentation (http://grails.org/doc/1.1.x/index.html)
def beforeInsert = {
if (price == '') { price = 0}
}
Instead of changing the data binding why not just write your own setter? In the setter test to see if the string is empty, if it is set price to 0. If it isn't do a normal integer conversion.
try this constraint instead
static constraints = {
price(validator: {val, obj ->
if (val == '' || val == 0) {
obj.price = 0
return true
} else if (val < 1) {
return false;
}
})
}
import org.grails.databinding.BindUsing
class Foo {
String name
#BindUsing({ obj, source ->
source["price"] ?: 0
})
Integer price
}

Resources