Grails adding attributes to one-to-many relationship - grails

I have set up a one-to-many relationship in my scaffolded Grails application:
class Course {
County county
Date date
int maxAttendance
static hasMany = [ persons:Person ]
}
class Person {
String firstName
String lastName
String email
Course course
boolean attended
boolean paid
static belongsTo = [ class:Course ]
}
So, when a user views the CourseController, they are able to see Person's registered in the selected Course.
My question is, how can I change the application so that when a user views the people in a given course, they can also view/modify the checkboxes for 'boolean attended' and 'boolean paid', which are also in the Person domain? Here is a screenshot:

The thing is that you are using the scaffolded view, so you are pretty much stuck with the default design.
You can modify the behaviour, by installing and modifying the templates that grails uses to generate those views:
grails install-templates
This will create the templates in src/templates/scaffolding, although I do not recommend that approach. Maybe it is time that you start developing your own controllers and views, since the scaffolding is there mainly for testing and for administrative use.

Related

Grails: How do i select from a list of previously created objects in my view?

Let's say i have the following classes:
package test
class Person {
String name
static hasMany = [stuff:Stuff]
static constraints = {
}
}
and
package test
class Stuff {
String stuff
static belongsTo = Person
static constraints = {
}
}
When i implement the view for Person i want to be able to select from a list of previously created stuff. How do i achieve that? I see that, when i use scaffolding Grails generates that drop down menu where i can do that but since i a designing my own views i would like to understand how that is done.
Thank you.
Probably good to start be reviewing the documentation for the select tag here: https://gsp.grails.org/latest/ref/Tags/select.html
A simple example to present a list of all Stuff would look like:
<g:select name="stuffSelect" from="${Stuff.list()}" optionKey="id" optionValue="stuff"/>
This should give you a dropdown of all Stuff in your database, displaying the String value to the user, but submitting the DB ID when the form submits.
I'm pretty sure you can use the generate-all command in grails, to see what the scaffolding code looks like:
http://docs.grails.org/3.1.1/ref/Command%20Line/generate-all.html
Using this command should generate Controllers, views, etc. so you can see how the scaffolded code works. Don't worry about being able to go back to generated scaffold code, just delete the stuff created by generate-all, and grails will autogenerate it at runtime like it does now.

Understanding hasMany behavior in grails and how to save a relationship

I'm making a model where a User fills out many questionnaires and the responses get saved to Questionresponse. I'm on grails 2.5.2
Test1
So I have two models
class User {
String username
...
static hasMany = [reponse: QuestionResponse]
}
class QuestionResponse {
String question_1
String question_2
...
}
With the above, a new DB table is created: user_questionresponse with two columns user_questionresponses_id and questionresponse_id. This seems like what I want. A user would have many questionresponses and those relationships would be saved in this table. However, I can't find out how to save data to this table.
For example, if I do:
def user = springSecurityService.currentUser
def questionnaire = new QuestionResponse(question_1: "foo", question_2: "bar")
//How do I link the user to this newly created questionnaire?
user.addToResponse(q).save(flush: true) //DOES NOT WORK.
Test2 (just add belongsTo)
class User {
String username
...
static hasMany = [reponse: QuestionResponse]
}
class QuestionResponse {
String question_1
String question_2
static belongsTo = [user: User]
...
}
If I add belongsTo to QuestionResponse a new column, user_id, gets created in the DB. Now if I run the same code as above, this user_id column has the id populated with that of the current user. However, the relationship table, user_questionresponse is still empty.
I am aware of the approach mentioned by Burt but I assume that should be required only for ManyToMany relationship. If that is required for all relationship, why isn't that the default?
In your first case, you have a OneToMany relationship between User and QuestionResponse with no side being the owner of the relationship. In this case to maintain the relationship between User and QuestionResponse, a third table is required. To persist data you need to do the:
userInstance.addToResponse(new QuestionResponse(question_1: "foo", question_2: "bar")).save(flush: true, failOnError: true)
You are doing user.addToReponse(q) instead it should be user.addToReponse(questionnaire), if it's not a typo and the data is actually not being stored, then check by adding the failOnError parameter to save() method. Sometimes grails save() method fails silently, it should tell you if this is the case.
In second case, you have added the parent to the relationship, so that means you don't need the third table to maintain the relationship. Grails will not create and populate the third table in this case.
The second approach (adding belongsTo in QuestionResponse) seems the right thing to do in your case, since QuestionResponse objects cannot exists without a user and cannot belong to different users.
In that case there's no need to use a third table.
When you run the app for the first time, grails created the relation table (because there was no belongsTo). When you run the app again with belongsTo grails adds the user_id field but DOES NOT DROP the relation table. That's why the table is there and is empty: it's not needed, but grails database auto-update feature only adds things, it does not remove anything.
The same applies to fields: if you remove a field from an entity you have to manually remove it from the database.

grails: scaffolding create view for domain with hasMany relation

Let's assume the following (simplified) domain classes:
class Person {
static hasMany = [stringProperties: StringProperty]
static constraints = {
}
}
and
class StringProperty {
String name
String value
static constraints = {
name blank:false
value blank: true
}
}
When scaffolding generates the create view, there is no option in the gsp to create a StringProperty from Person.
Does a plugin exist or does somebody know a best practice, that can render a sort of create ui that allows to create members of a hasmany relation.
I'm just asking before i take the time to modify the scaffolding templates.
This is one of the areas where a plugin or enhanced scaffolding would be welcomed by the community. If I had the time I would take the information presented here and make a plugin for it. I have used this approach a few times and it works well.

How do I use JAXB types as Grails domain classes?

My system consists of a back-end part, written in Java, exposing a set of web services which are defined contract-first using WSDL and XSD. Among the data transported over the web services are a large set of product types (they are different kinds of bank accounts, to be precise). Our front-end is a Grails web application. It uses and exposes the data and operations hosted by the back-end. The front-end has no database on its own for security reasons; all data is stored on the back-end. Pretty standard architecture.
Now, the set of products is large, growing, and volatile. Each product type has to be CRUD-ed on the web application user interface. It would be lovely if I could tell Grails to use the XSD specifications of the product types as domain types, and generate views and controllers for them.
I have not found a solution for this puzzle yet, even after extensive experiments and lots of web browsing. I have about a year's worth of professional experience with Grails. Any help or ideas would be appreciated.
Some details:
A product type is a simple POJO data carrier. Some simplified examples:
package jaxbgenerated;
public class Product1 {
protected Account from;
protected Account to;
protected String name;
// + getters and setters
}
public class Product2 {
protected List<Account> accounts;
protected String name;
// + getters and setters
}
public class Account {
protected String id1;
protected String id2;
// + getters and setters
}
Note that "Account" is not a product type but it is a JAXB-generated type. Products can contain such in addition to properties of simple data types like String, int and Date but they never contain other product types.
The end result I am aiming for is a Grails-generated form where a user can edit a Product1 instance with nested forms for editing its constituent Accounts. And likewise for Product2.
My idea is to first manually code a Grails domain class for each JAXB-generated type:
//in grails-app/domain:
 
import utilities.Copier
 
class Product1 extends jaxbgenerated.Product1 {
Product1(jaxbgenerated.Product1 jaxb) {
Copier.copy(jaxb, this)
    }
static constraints = {
}
}
There is a bit of boilerplate code here but nothing more than I can live with. The Copier.copy() function is (I think) needed to convert a jaxbegenerated.Product instance fetched from the back-end to a Product1 instance which can be used in Grails. It recursively looks for jaxbgenerated properties in the jaxb source, and copies their values to the corresponding Grails domain type. The constructor is invoked from a layer that fetches data from the back-end.
I can use the constraints block to manually add semantic constraints where needed, e.g. that the "from" and "to" accounts are not the same.
Next, I generate controllers and views for all the Grails domain classes thus constructed, and run the application. And get a stack of exceptions:
Caused by MappingException: Could not determine type for: Account, at table:
product1_type, for columns: [org.hibernate.mapping.Column(from)]
I think the trouble here is that Product1's "from" and "to" properties are not of type Account but of type jaxbgenerated.Account.
I have tried different approaches but to no avail. Some notes:
As I said, all data storage happens on my back-end, so I do not need
the GORM/Hibernate aspect of Grails. Therefore I tried adding
"static mapWith = "none" to the domain classes but that did not
help.
I tried explicitly telling Hibernate the type of the Accounts
in Product1 by adding "static mapping = { from type: Account }" but
that did not work either.
Any help or ideas would be appreciated.
/Jan Reher, Systematic A/S, Denmark
I think you have do write a dababase plugin similar in concept to this simpledb

Need ideas in designing Domain classes Grails

I am learning Grails, I am trying to build a small application. And for now I am working on the registration part.
There are 3 different views for registration process
1) As an employee my registration view is different with different fields
2) As an employer registration view would be different where I would be collecting company details, an authorized representative who can act on behalf of the company. So as a matter of fact I was thinking that company(employer) is not the actor but representative is an actor and hence need a representative domain class.
3) retailer registration view is different.
So I need to define the domain classes and its relationships I am very much new to grails and I need some guidance in designing
I was initially thinking of User domain class and have UserTypes(which defines different types of users ex. representative,retailer and employee) but not sure if that works.
Appreciate if someone could help me in building my domain classes.
Thanks
You definitely want to map out your domain classes before you start working on the views. Is the authorized rep always going to be an employee, or is it a completely different entity?
Think of it in terms of objects, and try to mimic it as much as possible. A company has employees, and can have an authorized representative. Here's a sample mock up:
class Employee {
String firstName, lastName /* etc... */
}
class Company {
String name /* etc */
Representative authorizedRepresentative
static hasMany = [ employees : Employee ]
}
class Representative {
}
Of course, you may want to have references from the Employees back to its Company. Have a look at the Object Relational Mapping portion of the Grails docs.

Resources