How do I prevent child properties from being updated? - grails

When I use RestfulController in Grails to save data for an object, how can I prevent the client from applying changes to a related child object?
Given the following domain classes:
class Language {
String name
}
class TranslationText {
Language language
String text
}
And the following POST data for a TranslationText:
{
"language": { "id": 1, "name": "InvalidName" },
"text": "Some Text"
}
Here, I want to reference an existing Language resource (with ID=1), but I don't want the name to be altered by the client.
How can I save this resource with the text and language (based on ID), but discard the invalid language name property?
I want to modify RestfulController in the most minimal way possible, preserving default behavior as much as I can.

I think you need to configure the 'cascade' mapping property. This will tell GORM to evict the linked instance, so it won't be in the Hibernate session, changed to a new name and flushed to the DB :
class TranslationText {
Language language
String text
static mapping = {
language cascade: 'evict'
}
}
ref : http://docs.grails.org/3.1.x/ref/Database%20Mapping/cascade.html

Related

Prevent caching on Custom Display Name Attributes in MVC

I have a Custom Display Name attribute that translates the field names based on the user's language preference. Unfortunately what happens is that the first user's language preference is cached for every subsequent request regardless of the subsequent user's language preference. The result is that the page content, header, and menu items display in the proper language, but only the labeled fields display with the incorrect language.
Here is part of the View Model I'm using:
public class RegisterViewModel
{
[CustomEmailAddress]
[CustomDisplayName("lbl_email")]
public string Email { get; set; }
[CustomRequired]
[CustomDisplayName("lbl_fn")]
[StringLength(255)]
public string FirstName { get; set; }
...
}
Here is the Custom Display Name attribute:
public class CustomDisplayNameAttribute : DisplayNameAttribute
{
public CustomDisplayNameAttribute(string value = "")
: base(GetMessageFromResource(value))
{
}
private static string GetMessageFromResource(string value)
{
string CurrentUser;
try
{
CurrentUser = HttpContext.Current.User.Identity.Name;
}
catch
{
CurrentUser = "";
}
string lang = ModelInit.repo.LangCode(CurrentUser);
string ItemLegend = ModelInit.repo.TranslateItem(value, lang);
return ItemLegend;
}
}
While debugging the problem, I found that MVC does NOT bother to hit the "CustomDisplayNameAttribute" class on subsequent requests even after the user logs off and a new user logs on. So I also tried decorating the Custom Display Attribute with:
[OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
but it didn't work either. If this behavior can't be changed (because it's built-in to the framework) then is there a way to clear the cache from the Custom Display Name attribute when the user logs off? (Actually, this would be my preferred solution!) Right now, the only way to clear it is by stopping and restarting the program.
Short answer: no
OutputCacheAttribute is used to cache the output of the entire controller method, but has nothing to do with caching of the model attributes. Since attributes are simply static metadata, MVC needs to use reflection to retrieve it, and the effect of this relatively slow operation is minimized by caching the result.
Unfortunately there is no way to clear this cache, likely because doing so in a multi-threaded, safe manner would require locking that would hinder performance.
Note that there are multiple caches in use throughout MVC, including model metadata, view location, and (optional) controller output. Each uses a separate implementation and cache key strategy, which I discovered when trying to create multi-tenancy on top of MVC. Things have gotten a little better (easier) with MVC 6.

Trim domain field by default

What is the best way to trim field value in domain?
My suggestion is to use beforeSave(), but would work something like this?
class Book {
String name = name?.trim()
}
You have a couple options depending on what behavior you want.
A custom setter, which will trim the value every time you set it
class Book {
String name
void setName(String name) {
this.name = name?.trim()
}
}
A custom getter, which will give you a trimmed value but not store it in the database
class Book {
String name
String getName() {
this.#name?.trim()
}
}
A hibernate event, like beforeSave() as you mentioned, which will only trim it before the object is persisted.
Well, you can enable automatic trimming of string in Grails (version 2.3+) by setting below property in Config.groovy file:
grails.databinding.trimStrings = true
This will automatic trim the string before save or update.
I have have noticed that Grails automatically does a .trim() on fields before persisting them. For example:
null
""
" "
All gets stored as null in Grails 2.3.7 for a nullable string. In addition:
" foobar "
gets stored as "foobar"
These results are using the default h2 database. So you might let Grails do the heavy lifting in this case.
Here is my hack for quickly trimming all fields in a domain object. I often receive JSON data that is not formatted in a way that would allow me to use data-binding techniques. This method can be called after updating or assigning all values in the domain instance.
class Book {
def trimFields() {
this.properties = this.properties
}
}
Requires this configuration which is set by default in Grails
grails.databinding.trimStrings = true
I know this is overkill but it's quick and easy to add to a domain class.

Grails bindData exclude by annotation

I want to exclude domain field from data binding
Is it possible to mark class field by an annotation?
For example domain:
class Article {
String text
.....
Author author
}
in code I have to write bindData(article, params, [exclude: ['author']]) for cheating prevention
But much easier simple to annotate Author author. But I didn't find how.
Since Grails 2.1.0 you can use the bindable constraint to indicate that a property should not be automatically assigned during data binding.
class Article {
String text
...
Author author
static constraints = {
author bindable: false
}
}
Now calling bindData(article, params) will automatically exclude the article's author property.

domains have some common fields,extends domain or embedded?

when i design database.I use embedded to embed common fields.but it's can't init dateCreated and createdBy,what'd i do?extends domain or embedded is right way to handle common fields?
code to say?
class Created {
Date dateCreated
Long createdBy
def beforeInsert()
{
dateCreated= new Date()
createdBy=0
}
}
class Updated {
Date lastUpdated
Long updatedBy
//it works?
def beforeUpdate(){
lastUpdated=new Date()
updatedBy=0
}
//it works?
def beforeInsert(){
lastUpdated=new Date()
updatedBy=0
}
}
class CreatedUpdated {
Created created
Updated updated
//Must use the embedded option, or the type of exception, can not find CreatedUpdated
static embedded = ['created','updated']
}
class Term {
String name
CreatedUpdated createdUpdated
static embedded = ['createdUpdated']
Term parent
static hasMany =[terms:Term]
static mapping = {
version false
}
String toString()
{
name
}
static constraints = {
name unique:true,size: 1..20
parent nullable: true
createdUpdated display:false,nullable:true
terms display:false
url url: true
}
}
or use extends?
class Term extends CreatedUpdated{
String name
Term parent
static hasMany =[terms:Term]
static mapping = {
version false
}
String toString()
{
name
}
static constraints = {
name unique:true,size: 1..20
parent nullable: true
terms display:false
url url: true
}
}
`
what is right to me?
I'd definitely make this example embedded rather than inherited. I don't think you should make this call based solely on the fact that objects contain common fields. Instead, you should use inheritance if it makes sense for your model using standard OO design techniques. For example, if "myClass is a myBaseClass" doesn't hold true, inheritance is probably the wrong solution.
In general, I'd stay away from classes like CreatedUpdated that are just a collection of properties and not an actual object from your domain. Java/Groovy has only single inheritance, so this only works if you have one base class like this.
Also, for that particular case, created and updated timestamps can automatically be applied by GORM. If you're using spring security, check out the audit-trail plugin for automatically creating createdBy and updatedBy columns.
In this particular case audit-trail plugin should suffice the requirements. However if you have such requirement for other fields wherein no plugin is available, then one of the possible solution could be to inject such common fields at compile time via AST Transformation. Internally audit-trail plugin uses this concept to inject those fields. Depending upon your requirement you can either use Global AST Transformations or Local AST Transformations.

Prefix column names in GORM

with every project, I automatically run into a problem with reserved SQL word when I use properties like status or user in my Grails domain classes.
So I always have to add a
static mapping = {
status column:'prefix_status'
}
to my classes.
I now wonder if there is an easy way to prefix all columns with a given string?
If there is nothing out of the box, I guess it would be possible to create a plugin which automagically injects such a mapping in all domain classes - can someone point me to a code example which modifies a class whenever it changes?
This is already answered in the manual:
Object Relational Mapping (GORM) - Custom Naming Strategy
Add to DataSource.groovy Config:
hibernate {
...
naming_strategy = com.myco.myproj.CustomNamingStrategy
}
Custom Naming Class (under src/groovy/com/myco/myproj/CustomNamingStrategy.groovy):
package com.myco.myproj
import org.hibernate.cfg.ImprovedNamingStrategy
import org.hibernate.util.StringHelper
class CustomNamingStrategy extends ImprovedNamingStrategy {
String propertyToColumnName(String propertyName) {
"prefix_" + StringHelper.unqualify(propertyName)
}
}

Resources