groovy, grails: high level questions on extraneous properties and command objects / data binding - grails

Just a few high-level, hopefully very quick questions:
1) If I have a class A with a single field x, is constructing it
def A = new A(x:someVal, y:someVal)
totally fine?
2) Related, is the following a good way to copy relevant parts of a command object into a domain object?
def domainObject = new DomainObject(commandObject.properties).
Where command object has extra properties. Or should it be done instead:
def domainObject = new DomainObject()
domainObject.properties['prop1', 'prop2', ...] = commandObject.properties
or ?
Thanks

For the first question, it's important to distinguish between a vanilla groovy object, and a grails domain object. Groovy objects with throw a MissingPropertyException. Grails domain objects will silently ignore extra properties.
Regarding the second question, initializing grails domain objects with a command object is a common pattern, and generally ok. Params can be a little bit more dangerous. A malicious user can put anything into params so it's best to explicitly spell out what properties you want to assign. Otherwise, things like timestamps and users, or even non-mapped columns like injected spring beans could be affected.

Related

How to limit properties bound when using domain model as a command object

This really powerful feature of grails
def save(MyDomain model) {
model.save()
render ''
}
will parse the request body or params, run MyDomain.get(id), fill in the properties from the request body or params and save. That's a lot for this little bit of code.
How do I limit the properties to bind to model? Say I have an accountBalance property that is read only and I don't want a malicious user to be able to change their account balance.
Also, I want to have multiple actions that save a different subset of properties of MyDomain... say one action could be for a bank teller user that is making a deposit for the account holder. In this case the teller should be able to set accountBalance but not password.
I realize that an actual banking app wouldn't work like this, it's just an example.
I had other problems that led me to use command objects to bind data (see Grails fails to parse request when content type is specified during post). Any solution would also have to address that post. I imagine if the solution uses command objects then it will work, but if command objects aren't in the solution, then the request body problem has to be addressed.
Have not tried on an actual domain class but can you try using bindData instead of implicitly binding where you can particularly specify which property to exclude?
def save() {
//params - A Map of source parameters
//It can be params or any other representation of request body
//request.JSON, request.XML
MyDomain model = MyDomain.get(params.id?.toLong())
bindData(model, params, [exclude: ['accountBalance']])
model.save()
render ''
}
I suggest you take a look at the documentation about binding. There is a lot of information, in particular the section about security which is similar to your concerns. Looking at the fact bindData() allows you include/exclude properties you should be able to write any variation of your binding you need.

how to serialize domain classes grails

I tried to serialize grails domains classes to Maps or similar in order to be able to store it in memcached.
I want to be able to read the objects only, I don't need gorm crud. Only to read them without breaking the kind of interfaces they have.
For instance: I could convert domains to maps, becouse it wouldn't break the interface for access like .<property> or .findall or similar
First I tried to do a manual serialization but it was very error prone. So I needed something more general.
Then I tried to serialize as a map with a grails codec.
Here is the testing repo.
Here is the snippet.
But I get StackOverFlowException.
I also tried to mark all the domains as Serializable but I need to reattach every domain when I bring them back from memcached to avoid hibernate errors like org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Do you know a way to achieve this?
Is very frustrating to google search for something like this "storing domain classes in memcached" and find out is not a common problem.
I haven't see an out-of-the-box solution for doing this, but if you wanted to keep it generic you could do it manually (and consistently) like this:
def yourDomainInst = DefaultGrailsDomainClass(YourDomainClazz)
List listOfOnlyPersistantProperties = yourDomainInst.persistantProperties
def yourNewMap
yourObjects.each { obj ->
listOfOnlyPersistantProperties.each { prop ->
def propName = prop.name
yourNewMap.put(propName, obj."$propName")
}
}
Something like that should work. Note there's probably a hundred errors because I can't try it out right now, but that is the general idea.
Have a look at: Retrieving a list of GORM persistent properties for a domain

Grails Domain Classes in Sets

Is it a bad practice to use domain objects in Sets or as keys in Maps?
In the past I've done things like this a lot
Set<Book> someBooks = [] as Set
someBooks.addAll (Book.findAllByAuthorLike('%hofstadter%'))
someBooks.add (Book.findByTitleLike ('%eternal%'))
However I have noticed that I often encounter problems when findAllByAuthorLike might return a list of Hibernate Proxy objects com.me.Book_$$_javassist_128 but findByTitleLike will return a proper com.me.Book object. This causes duplicates in the set because the real object and the proxy are considered not equal.
I find I need to be extremely careful when using Sets of domain objects like this, and I get the feeling it might be something I should not be doing in the first place.
The alternative is of course to use a set/map of id's, but it makes my code verbose and prone to misunderstanding
Set<Integer> someBooks = [] as Set // a set of id's for books
#Burt: I thought Grails domain classes already did this, at least so that equals/compare was done on class/id's rather than the object instance. Do you mean a special comparator for hibernate proxies?
return (this.class == obj.class && this.id == obj.id) ||
(obj.class == someHibernateProxy && this.id == obj.id)
It's not bad practice at all, but just like in a non-Grails application you should override equals and hashCode if you'll be putting them in hash-based collections (HashSet, HashMap, etc.) and also implement Comparable (which implies a compareTo method) if you're going to use TreeSet/TreeMap/etc.
Proper implementation of equals() and hashcode() in a Hibernate-backed situation is far from trivial. Java Collections require that hashcodes of objects and behaviour of equals() don't change, but the id of an object can change when it's a newly created object, and other fields can change for a wide variety of reasons. Sometimes you have a good unchangeable business id that you can use, but quite often that's not the case. And obviously default Java behaviour is also not suitable in a Hibernate situation.
The best solution I've seen is described here: http://onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=2
The solution it describes is: initialize the id as soon as the object is created. Don't wait for Hibernate to assign an id. Configure Hibernate to use version to determine whether it's a new object. This way, id in unchangeable, and can be safely used for hashcode() and equals().

How to reference a grails GSP model variable indirectly e.g. via .get(...)

I'm using a GSP for sending out emails based on the MailService plug-in. The sendMail closure passes (amongst others) body(view:..., model:myModel)
I know that I can access every item of the myModel Map just using ${itemName} in the GSP. However as I sometimes want to build the item name dynamically like 'item'+i, I need to have some surrounding method to access the variable.
I already tried ${model.get('item'+i), and ${params.get('item'+i), but model is null and params is an empty Map. I also tried pageScope, but though I can access an item via ${pageScope.itemName, I can not use ${pageScope.get('item'+i)} because pageScope is not a Map.
Probably there are multiple solutions to solve this; I'd be glad about an easy one ;-). One solution I see is to pass myModel as the only parameter and then always use myModel.get(...), however this would mean that I had to change all my existing GSPs to always refer to myModel instead of accessing items (with fixed names) directly; so if there's a way where I don't have to change the model passed to the GSP, this would be my favorite.
If someone could also say a few words about the difference of model and params in this context, this would be additionally helpful!
I've managed it now using ${pageScope.getProperty(...)}.
There's no 'model' scope or variable. Instead objects in the model map are set as Request attributes to make them available to the GSP. This is a Spring feature which makes it easy to access variables in JSPs using JSTL and since the GSP syntax is very similar to JSTL it works the same way in Grails.
So you can use this:
${request.getAttribute('item'+i)}
to access model variables using dynamic names.
You can use ${fieldValue(bean: book, field: 'title')}
See: http://grails.github.io/grails-doc/latest/ref/Tags/fieldValue.html

How do I handle data which must be persisted in a database, but isn't a proper model, in Ruby on Rails?

Imagine a web application written in Ruby on Rails. Part of the state of that application is represented in a piece of data which doesn't fit the description of a model. This state descriptor needs to be persisted in the same database as the models.
Where it differs from a model is that there needs to be only one instance of its class and it doesn't have relationships with other classes.
Has anyone come across anything like this?
From your description I think the rails-settings plugin should do what you need.
From the Readme:
"Settings is a plugin that makes managing a table of global key, value pairs easy. Think of it like a global Hash stored in you database, that uses simple ActiveRecord like methods for manipulation. Keep track of any global setting that you dont want to hard code into your rails app. You can store any kind of object. Strings, numbers, arrays, or any object."
http://github.com/Squeegy/rails-settings/tree/master
If it's data, and it's in the database, it's part of the model.
This isn't really a RoR problem; it's a general OO design problem.
If it were me, I'd probably find a way to conceptualize the data as a model and then just make it a singleton with a factory method and a private constructor.
Alternatively, you could think of this as a form of logging. In that case, you'd just have a Logger class (also a singleton) that reads/writes the database directly and is invoked at the beginning and end of each request.
In Rails, if data is in the database it's in a model. In this case the model may be called "Configuration", but it is still mapped to an ActiveRecord class in your Rails system.
If this data is truly static, you may not need the database at all.
You could use (as an example) a variable in your application controller:
class ApplicationController < ActionController::Base
helper :all
#data = "YOUR DATA HERE"
end
There are a number of approaches that can be used to instantiate data for use in a Rails application.
I'm not sure I understand why you say it can't fit in a Rails model.
If it's just a complex data structure, just save a bunch of Ruby code in a text field in the database :-)
If for example you have a complex nested hash you want to save, assign the following to your 'data' text field:
ComplexThing.data = complex_hash.inspect
When you want to read it back, simply
complex_hash = eval ComplexThing.data
Let me point out 2 more things about this solution:
If your data structure is not standard Ruby classes, a simple inspect may not do it. If you see #<MyClass:0x4066e3c> anywhere, something's not being serialized properly.
This is a naive implementation. You may want to check out real marshalling solutions if you risk having unicode data or if you really are saving a lot of custom-made classes.

Resources