Grails 1.1 Web Application Development
上QQ阅读APP看书,第一时间看更新

Meeting the relations

In Hibernate, and therefore in Grails, persistent objects can be given relationships to other persistent objects. Grails supports the following types of relationships:

  • One-to-one — where one instance of a class can have a relationship to a single instance of another class. For example, a person can have only one heart, so the relationship between person and heart would be one-to-one.
  • One-to-many — where one instance of a class can have a relationship to a number of instances of another class. For example, a person can have many telephone numbers.
  • Many-to-one — the other side of one-to-many, where many instances of a class have relationships to one single instance of another class. For example, many children can have the same father.
  • Many-to-many — where many instances of a class can be related to many instances of another class. For example, a child can have many parents, and a parent can have many children.

Relating roles and users

So far, you have a Role class and a User class, and you can create users and roles in the application. However, there is no relationship between the two classes; so you have no way of knowing which role a user is in. Scaffolding allows you to manage relationships between objects. All you need to do is create the relationships in the domain. You can create the relationship between the Role class and the User class by adding the highlighted code given here to the Role.groovy class:

package app
class Role {
static hasMany = [users: User] 
String name
static constraints = { name(blank: false, size: 1..20) } public String toString() { return name } 
}

The relationship between a Role and a User is one-to-many, which is defined by the hasMany property. You have also added a constraint to the name of a role to make sure that it is not empty, and is not more than 20 characters. The toString method on Role has been overridden, so that the scaffolding can present meaningful role options when creating a user.

You should also associate the User class with the Role class:

package app
class User {
String username
String title
String firstName
String lastName
String password
Date dateCreated
Date lastModified
Role role 
static constraints = {
username(blank: false, size: 4..20, unique:true)
title(blank:false, inList:["", "Dr", "Miss", "Mr", "Mrs"])
firstName(blank: false, size:1..20)
lastName(blank: false, size:1..30)
password(blank: false, size:6..20, password:true)
role() 
dateCreated(nullable: true)
lastModified(nullable: true)
}
}

A role will apply to many users, but a user can belong only to one role. By simply adding a property of the type Role to the User class, you have created the other side of the many-to-one relationship between roles and users. You can then control where role information is displayed in the user scaffolding by adding it as a constraint.

The effect of making these changes on the scaffolding is that when a new user is created, you are prompted to select the role that they belong to. Additionally, if you edit a role, you will be allowed to add a new user to the role.

Ordering fields through constraints

Finally, it would be a good idea to hide the passwords of our users on the User List page. By default, the scaffolding for the list action displays only six columns. The first column is always the database ID of the object, which is rendered as a link to the view action. The other five columns are taken in the order specified by the constraints on the domain class. In our example, we can show the users' roles and hide the users' passwords by swapping the order of the role and password in the constraints for the User class. So,

password(blank: false, size:6..20, password:true)
role()

becomes:

role()
password(blank: false, size:6..20, password:true)

Once this change is made, you can see that passwords are no longer displayed on the User List page:

Ordering fields through constraints