There is a class
class Trip {
static constraints = {
sTrip(blank: true, nullable: true)
}
static hasMany = [trip: Trip]
static belongsTo = [sTrip: Trip]
String name
String toString() {
return this.name
}
}
I need to add an optional field in which I can select the data already available for this class.
That is, many-to-many relationships with the class itself
I did this:
static hasMany = [trip: Trip]
static belongsTo = [sTrip: Trip]
But from displays only a drop-down list
How can I submit a multiple list?
You need to add the multiple="true" attribute to your select e.g.
<g:select multiple="true" name="item" id="item" from="['item1', 'item2', 'item3']" />
Then in your controller/service:
params.list( 'item' ).each {
println it
}
Related
How to get the value as following codes with my show view page on Grails?
Person.groovy
package com
class Person {
String person
static constraints = {
person blank:false,nullable:true
}
static hasMany=[task:Task]
String toString(){return person}
static mapping={
}
}
Task.groovy
package com.moog
class Task {
String task
static constraints = {
task blank:false,nullable:true,unique:true
}
static belongsTo=[person:Person]
static hasMany=[tag:Tag]
String toString(){return task}
}
Tag.groovy
package com
class Tag {
String tag
static constraints = {
tag blank:false, nullable:true
}
static belongsTo=[task:Task]
String toString(){
return tag
}
}
First of all try a better wording for your collections
static hasMany=[tasks:Task] // in Person.groovy
static hasMany=[tags:Tag] // in Task.groovy
In your person show.gsp try something like
<g:each in=${person.tasks} var="task">
<p>${task}</p>
</g:each>
If you do not use scaffolding and write you own controller methods to create your entities than maybe this helps you further:
def task = new Task(task:"Clean room")
def person = Person.get(1)
person.addToTasks(task)
person.save()
I'm learning grails by trying to create a simple twitter copy. I'm currently trying to incorporate followers and groups. I originally came up with a very basic database structure, and I've had no luck in implementing it. The design for relationships is as follows:
Person:
has many: Groups, Tweets, (Person as followers through User2Person)
Group:
has many: (Person as followers through User2Person)
belongs to: Person as owner
User2Person:
belongs to: (Person or Group)
belongs to: Person
Basically, I want Person and Group to be an instance of User, and then create a table that maps User to Person. This way, only one table is created/used for the relationship between Group2Person and Person2Person.
More information: A Group is created by a Person and so it should have an "owner" (person_id). It also has many followers (i.e. members). Group cannot follow other groups, but a Person can follow either another Person or a Group.
Below is how I implemented this in grails:
User
abstract class User {
static hasMany = [followers: Person]
static mappedBy = [followers: "followed"]
String name
Date dateCreated
Date lastUpdated
static constraints = {
name shared: "mustFill", size: 3..20
}
}
Person
class Person extends User {
static belongsTo = [followed: User]
static hasMany = [tweets: Tweet, groups: Group]
static mappedBy = [groups: "owner"]
String username
String email
static constraints = {
username shared: "mustFill", unique: true, size: 4..15
email shared: "mustFill", email: true
}
static mapping = {
tweets sort: 'dateCreated', order: 'desc'
}
}
Group
class Group extends User {
Person owner
String description
def getTweets() {
return followers.tweets.flatten()
}
static transients = {
tweets
}
}
Tweet (Just in case?)
class Tweet {
static belongsTo = [author: Person]
String text
Date dateCreated
static constraints = {
text shared: "mustFill", maxSize: 140
}
}
When I run the cmd grails schema-export, I get the following error: "| Error Error loading plugin manager: Domain classes [class tweeter.Group] and [class tweeter.Person] cannot own each other in a many-to-many relationship. Both contain belongsTo definitions that reference each other. (Use --stacktrace to see the full trace)"
I was able to get the database to create almost the correct schema. Unfortunately, the join table's primary key for User2Person (a.k.a. followers) used (user_id, person_id). That meant that I could not have two records such as: (1, 2) and (2, 1) (e.g. two users are following each other). Below is the updated classes (commit):
User
class User {
static belongsTo = Person
static hasMany = [followers: Person]
String name
Date dateCreated
Date lastUpdated
static constraints = {
name shared: "mustFill", size: 3..20
}
}
Person
class Person extends User {
static hasMany = [tweets: Tweet, groups: Group, follows: User]
static mappedBy = [tweets: "author", groups: "owner"]
String username
String email
static constraints = {
username shared: "mustFill", unique: true, size: 4..15
email shared: "mustFill", email: true
}
static mapping = {
tweets sort: 'dateCreated', order: 'desc'
}
}
The follower table in the schema looked like:
create table user_follows (
user_id bigint,
follows__id bigint,
primary_key(user_id, follows__id)
)
I scoured the web for information about changing the primary key for a join table. The best I could find was about using code like:
static mappedBy = { followers joinTable: [name:"someName", ...] }
Unfortunately, I had a hard time finding good documentation on the joinTable mapping, and most sources seemed to indicate that it was not possible to change the primary key of join tables easily. I then decided to use a separate domain class to define the join table following this guide: Many-to-Many Mapping without Hibernate XML. Below is the final updated code (commit):
User
class User {
static belongsTo = Person
static hasMany = [people: UserFollower]
static mappedBy = [people: "followed"]
String name
Date dateCreated
Date lastUpdated
static constraints = {
name shared: "mustFill", size: 3..20
}
static transients = {
followers
}
def getFollowers() {
return people.collect { it.follower }
}
void addToFollowers(Person person) {
UserFollower.link(this, person)
}
void removeFromFollowers(Person person) {
UserFollower.unlink(this, person)
}
}
Person
class Person extends User {
static hasMany = [tweets: Tweet, groups: Group, users: UserFollower]
static mappedBy = [tweets: "author", groups: "owner", users:"follower"]
String username
String email
static constraints = {
username shared: "mustFill", unique: true, size: 4..15
email shared: "mustFill", email: true
}
static mapping = {
tweets sort: 'dateCreated', order: 'desc'
}
static transients = {
follows
}
def getFollows() {
return users.collect { it.followed }
}
void addToFollows(User user) {
UserFollower.link(user, this)
}
void removeFromFollows(User user) {
UserFollower.unlink(user, this)
}
}
UserFollower
class UserFollower {
User followed
Person follower
static constraints = {
followed nullable: false
follower nullable: false
}
static void link(User user, Person person) {
UserFollower f = UserFollower.findByFollowedAndFollower(user, person)
if(!f) {
f = new UserFollower()
user.addToPeople(f)
person.addToUsers(f)
f.save()
}
}
static void unlink(User user, Person person) {
UserFollower f = UserFollower.findByFollowedAndFollower(user, person)
if(f) {
f = new UserFollower()
user.removeFromPeople(f)
person.removeFromUsers(f)
f.delete()
}
}
}
I am trying to add Category and Sub Categories to Organization(Currently logged in User). I can add category but failed to add subCategories to Organization. When I try, get following message:
No signature of method: com.vproc.market.Follower.addToSubCategories() is applicable for argument types: (com.vproc.market.SubCategory) values: [com.vproc.market.SubCategory : 4].
I try to add category and subcategories to Organization in follow method of Organization Controller which is below.
OrganizationController.groovy
def follow() {
Subscriber loggedinSubscriber = subscriberService.getLoggedinSubscriber()
Party organization = loggedinSubscriber?.customer?.party
def marketInstance = Category.get(params.abc)
def follower = new Follower()
follower.followedBy = organization
follower.category = marketInstance
def sub = params.list('subcategories')
sub.each { id ->
follower.addToSubCategories(SubCategory.get(id))
}
follower.save(failOnError: true);
flash.msg = "Okay. This market is now on your watchlist."
redirect (action: "profile")
}
In this method I get error in following line:
follower.addToSubCategories(SubCategory.get(id))
which is mentioned in title of question.
Organization.groovy
package com.vproc.member
import java.util.Date;
import com.vproc.market.SubCategory;
class Organization extends Party{
String orgName
Person contact
String orgSize
boolean isVendor = false
static hasMany = [follows: SubCategory]
static constraints = {
orgName blank: false
orgSize blank: false
}
}
Follower.groovy
package com.vproc.market
import com.vproc.member.Organization;
class Follower {
Category category
Organization followedBy
SubCategory subCategory
static constraints = {
}
}
Follower is domain where Category and subcategories are added to Organization and stored.
Category.groovy
package com.vproc.market
import com.vproc.enquiry.Enquiry;
class Category {
String name
String description
static constraints = {
}
static hasMany = [ subCategories: SubCategory ]
}
SubCategory.groovy
package com.vproc.market
import com.vproc.enquiry.Enquiry;
class SubCategory {
String name
static hasMany = [requirements: Enquiry]
static belongsTo = [ category: Category]
static constraints = {
requirements nullable:true
}
}
gsp file
<g:form controller="organization" params="[temp : marketInstance?.id]" action="follow" method="post">
<g:hiddenField name= "abc" value="${marketInstance?.id}" />
<g:hiddenField name="id" value="${subcategory?.id}" />
<div style="margin-left:200px">
<input type="button" class="button-inner" id="check1" value="Check All" />
<input type="hidden" id="isChkd" value="true" />
<g:each var="subcategory" in="${subCategroyInstanceList}">
<div>
<g:checkBox class="cb1-element" name="subcategories" value="${subcategory.id}"/>
<label for="subcategories"> ${subcategory.name}</label>
</div>
</g:each>
<button class="btn btn-inverse">Submit</button>
</div>
</g:form>
Summary: I want to add category and subcategories to Organization. I can successfully add category but failed to get subcategories to Organization.
Error occurs in following lines:
def sub = params.list('subcategories')
sub.each { id ->
follower.addToSubCategories(SubCategory.get(id))
}
No signature of method: com.vproc.market.Follower.addToSubCategories() is applicable for argument types:
Just a quick look at your domains, the Follower domain has direct association with SubCategory. You can simply assign subCategoty to that no need for follower.addToSubCategories(SubCategory.get(id))
Could be something like this:
follower.subCategory = SubCategory.get(id)
I am working on Grails currently and also found similar issue. I am using Grails 2.3.7 and I found this https://github.com/grails/grails-datastore-test-support/issues/1
Even from this link it mentioned it's a bug but I am still not really sure. So far I just do as following and it works for me:
if(follower.subCategories == null){
follower.subCategories = []
}
def sub = params.list('subcategories')
sub.each { id ->
follower.subCategories.add(SubCategory.get(id))
}
please let me know if you have better solution for this problem.. I am also keen to know it.
I have 2 domain classes: Category and CatAttribute, they have a many-to-one relationship, Category has 2 List of CatAttribute.
class Category {
static constraints = {
description nullable: true
name unique: true
}
static hasMany = [params:CatAttribute, specs:CatAttribute]
static mappedBy = [params: "none", specs: "none"]
static mapping = {
}
List<CatAttribute> params //required attributes
List<CatAttribute> specs //optional attributes
String name
String description
}
and my CatAttribute class:
class CatAttribute {
static constraints = {
}
static belongsTo = [category: Category]
String name
}
When I tried to create new objects, it fails to save:
def someCategory = new Category(name: "A CATEGORY")
.addToSpecs(new CatAttribute(name: "SOMETHING"))
.addToParams(new CatAttribute(name: "onemore attribute"))
.save(flush: true, failOnError: true)
The domain classes here are simplified/data are mocked for illustration purposes only, the real production code is a lot more complex, but the relationship between the two domains is the same.
Validation errors occur on .addToSpec line:
Field error in object 'Category' on field 'specs[0].category': rejected value [null];
This error has to do with me putting 2 lists of CatAttribute objects in the same domain Category, if I remove either of those and proceed with my object creation,everything is perfectly fine, the way I mapped the domain class Category is all based on grails ref
, so i don't think there is anything wrong with the mapping, but if there is, please let me know.
Do you really need the associations as List (do you index), by default they are Set.
Modify Category as below and you should be good:
class Category {
String name
String description
static hasMany = [params: CatAttribute, specs: CatAttribute]
static mappedBy = [params: "category", specs: "category"]
static constraints = {
description nullable: true
name unique: true
params nullable: true //optional
}
}
if you need a 1:m relation.
I'd like to do paging and sorting from a collection in a relationship
For example with the following model:
class User {
String userName, password
static hasMany = [roles: UserRole, preferences: Preference]
}
class UserRole {
String name, description
static hasMany = [actions: Action]
}
I'd like to recover all the roles for a specific user. I already have the user loaded so the normal way to do it would be using
user.roles
But I want to sort them by UserRole properties and I want to paginate them dynamically
I know that if I want to get all the UserRoles sorted and paginated I can use:
UserRole.list([sort: 'name', order: 'asc',max: 5,offset:0])
But I want to do it just for the roles that are associated to my user. I was trying to use criteria, but I think I'm missing something.
I also had a look here:
http://grails.1312388.n4.nabble.com/A-Relationship-Paging-Pattern-td1326643.html
But then I would have to add the relation back into UserRole so I would have:
static hasMany = [users : UserRole]
How can I do this? what would be the best way?
Please, let me know if you need more information and sorry if I wasn't clear enough
Thanks and regards
You cannot paginate an "ordinary" relationship.
You can change the order child objects appear in using mapping DSL:
static mapping = {
sort name:desc
}
To simplify a hand-crafted paginated relationship, you can use a named query:
class Role {
static namedQueries = {
userRoles {
eq('user', UserSessionService.instance.currentUser)
}
}
}
Or you can implement a transient User's property that will return a Criteria for User's Roles (which can be paginated).
Grails Pagination with hasmany relation Bidirectional property finally i come to the point were i found it working Huuuh.
These are the Domain classes
class Client {
List bills
String shopName
String nameOfClient
static hasMany = [bills: Bill]
static constraints = {
shopName(blank:true, nullable:true)
nameOfClient(blank:false, nullable:false)
}
}
class Bill {
String billDetails
String billNo
static belongsTo = [client: Client]
static constraints = {
billDetails(blank:true, nullable:true , type: 'text')
billNo(blank:true, nullable:true)
}
}
Now This is my controller Logic
def clientDetails(){
def maxJobs = 4
def offset = (params?.offset) ?: 0
def clientId = params.id
def bills = Client.get(clientId).bills
def client= Client.get(clientId)
def results = Bill.withCriteria {
eq('client', client)
firstResult(offset as Integer)
maxResults(maxJobs)
}
[id:client.id,bills: results, offset: offset, max: maxJobs, totalJobs: bills.size()]
}
And the gsp code
<g:each in="${bills}">
<tr>
<td>${it.billNo}</td>
<td>${it.billDetails}</td>
</tr>
</g:each>
<g:paginate class="pagination" controller="client" action="clientDetails" total="${totalJobs?:0}" offset="${offset}" max="${max}" params="[id:"${id}"]"
prev="« Previous" next="Next »" />