Grails find in relationship - grails

I'm breaking my head into wall about this logic, I have 2 domains, User and RSS. When the user add a RSS, I have to compare if it's not duplicated URL in my db by given another URL in the same user.
class RSS {
Long id
String link
static belongsTo = [user:User]
}
class User {
Long id
Long uid //facebook
String name
static hasMany = [rss:RSS]
}
def addRSS(){
//logic url is valid or not
...
def user = User.findByUid(data.id) //get User uid and then by this uid, i can get the all RSS url
//and compare like if(db_url == given_url) ...
}
I tried many ways and I had no success.

You could also use one of the findOrSaveWhere or findOrCreateWhere methods
def url = 'some url from user' //data.url I would assume
def user = User.findByUid(data.id)
RSS.findOrSaveWhere(url: url, user: user)
If it's in the db it will fetch it for you if not it will create it for you. The documentation explains the difference between the *Save* and *Create*

Simple join would do I think:
def existing = RSS.withCriteria{
eq 'link', url
eq 'user.id', userId
}
or
def existing = RSS.withCriteria{
eq 'link', url
user{ eq 'uid', uidd }
}
if( existing ) return
else doSave()

Related

Grails: creating a many-to-many-to-many relationship?

So I'm currently building a Grails application, and I am trying to allow users to create posts, and those posts have comments as well.
The association I am trying to create is something like:
A User can have 0 to many Posts, and
Posts can have 0 to many Comments
I tried to set this up with my domain classes as the following:
class User implements Serializable{
static hasMany = [created_posts: Post]
String username
String password
}
class Post {
static hasMany = [comments: Comment]
String description
}
class Comment {
String comment_body
static belongsTo = [post: Post]
}
I tried playing with the mappedBy property as well, like the following:
class User implements Serializable{
static hasMany = [created_posts: Post]
static mappedBy = [created_posts: 'creator']
String username
String password
}
class Post {
static hasMany = [comments: Comment]
static belongsTo = [creator: User]
String description
}
class Comment {
String comment_body
static belongsTo = [post: Post]
}
But it would still not work. The code I am using to create this is the following:
Post new_post = new Post(description: "testing").save()
User user = User.get(springSecurityService.principal.id)
user.addToCreated_posts(new_post).save()
Unfortunately, Grails cannot seem to execute the last line, and sometimes it would not compile at all, giving a :bootRun error.
I am unsure of how to create the proper associations between the Users, Posts, and Comments. Any help is welcome and greatly appreciated!
EDIT: my current code: (compiles, but does not save to user's set)
class User implements Serializable{
static hasMany = [createdPosts: Post]
static mappedBy = [createdPosts: 'creator']
String username
String password
}
class Post {
static hasMany = [comments: Comment]
static belongsTo = [creator: User]
String description
static constraints = { creator nullable: true }
}
class Comment {
String comment_body
static belongsTo = [post: Post]
}
The code I am using in my controller:
User user = User.get(springSecurityService.principal.id)
Post new_post = new Post(description: "testing description", creator: user).save()
user.save()
System.out.println("post saved to user? " + user.getCreatedPosts())
Output is:
post saved to user? []
The issue is more than likely the fact that the save() function does not return the object that was saved.
Initially, I changed your code to:
Post new_post = new Post(description: "testing")
new_post.save()
User user = User.get(springSecurityService.principal.id)
user.addToCreated_posts(new_post).save()
Which did compile. But, there is one issue remaining - instead of running user.addToCreated_posts, you'll have to set the property creator of new_post, since you did not explicitly specify that it can be null when you created your Post domain class. Therefore, the call to save() will silently fail.
If you change the code to:
User user = User.get(springSecurityService.principal.id)
Post new_post = new Post(description: "testing", creator: user)
new_post.save()
Your code should work.
It is also probably a good idea to replace all of your calls to save() with save(failOnError: true), so that when a save fails, an exception is thrown. You can catch this exception, and extract error messages from the exception. Usually, the error messages are related to failed validations for the domain object.
This was tested on Grails 3.2.7, using H2 (the default, in-memory database packaged with Grails).
EDIT Here's an updated snippet based on the update that was made to the question.
You are running:
User user = User.get(springSecurityService.principal.id)
Post new_post = new Post(description: "testing description", creator: user).save()
user.save()
System.out.println("post saved to user? " + user.getCreatedPosts())
I would change this to:
User user = User.get(springSecurityService.principal.id)
Post new_post = new Post(description: "testing description", creator: user)
new_post.save(failOnError: true)
System.out.println("post saved to user? " + user.getCreatedPosts())
The reason I would do this is because you aren't saving the user - you are saving the post. When you get created posts for a user, Grails searches the database for posts where the creator_id column is set to the id of the user you called the method from.
Also, I would make sure that you did not remove the following line from User.groovy:
static hasMany = [createdPosts: Post]
static mappedBy = [createdPosts: "creator"]
You will absolutely need the following in Post.groovy:
static belongsTo = [creator: User]
This way, Grails knows how it is supposed to look up Posts for a user.
Once you make these changes, make sure you start with a fresh DB - for H2 in memory, this should be done automatically, so long as you are using the development environment - and restart your server.

Grails Criteria - list contents

These are my domain objects
User{
hasMany = {roles: UserRole}
}
UserRole{
User user
Role role
}
Role{
String authority
}
I need to find users based on their Role. For that I am trying to use the following criteria:
def role_admin = Role.findByAuthority('ROLE_ADMIN')
def criteria = new DetachedCriteria(User).build {
roles{
role{
idEq(role_admin.id)
}
}
}
result.users = criteria.list(params)
result.total = criteria.count()
The above will always return one result, even though I have verified by looking at the database directly that there should be more results. The params passed to list are correct, but I tried removing them just to be sure. I can't see what is wrong with the above, any suggestions ?
I also tried this
roles{
role{
eq("authority","ROLE_ADMIN")
}
}
But it is throwing exception:
Unknown column 'role_alias2_.authority' in 'where clause'
this works for me:
def criteriaUsers = UserRole.createCriteria()
def users = criteriaUsers.listDistinct{
eq("role", role_admin)
}.user
Side note: from the nomenclature of your classes it looks like you are using spring-security-core plugin. In my humble opinion the hasMany = [roles: UserRole] is redundant as the association User - Role is already being modeled in the UserRole class.

Filtering data based on username

The domain class 'Message' displayed below:
String name
String age
User user
From the following code, i retrieve all the messages that was posted. But what i really want is to display is all messages of a particular user. For example : user.firstName. How can i do it?
def messages = Message.listOrderByDate(order: 'asc', max:1000)
println messages.firstName + " BOOOOOOO "
[messages:messages.reverse()]
So instead of displaying all the data i want to filter the data based on users name. How can this be done ?
It could be queried in the following way:
def results = Message.withCriteria {
user {
eq("name", theUserNameYouWantToQuery)
}
order("date", "asc")
maxResults(1000)
}
This example could be extended to grouping etc. See http://grails.org/doc/latest/ref/Domain%20Classes/createCriteria.html
create as hasMany relationship from user to Message like this:
class User {
static hasMany = [messages: Message]
}
class Message{
String name
String age
static belongsTo [user: User]
}
and then use myUser.messages to fetch all Messages from this user.

Save On My Domain Class Object Is Not Working.

I have a User class which has a List field namely pt. This field is not initialized when User register his account. But when user goes this controller action :
def updatePt() {
//performs some action
def user = User.get(springSecurityService.principal.id) //find the user
user.pt = []
//on certain conditions i put values into user.pt like this
user.pt << "E"
//at last I save it
user.save()
}
But using user/show action via scaffolding I found that pt field is not saved on users object. Where I'm making a mistake?
You have to provide a static mapping in the Users domain class so that Grails knows the field must be persisted:
class User {
static hasMany = [pt: String]
}
It's possible because of validation error. Try with
if (!user.save()) {
log.error('User not saved')
user.errors.each {
log.error('User error: $it')
}
}
PS or you can use println instead of log.error

httpSession in Grails

I need to access the domain class User of the current session. The following code works:
class RatingController {
def rate = {
def rating = params.rating
def artist = Artist.get( params.id )
def user = User.get(1)
user.addToRatings(new Rating(artist:artist, rating:rating))
user.save()
render(template: "/artist/rate", model: [artist: artist, rating: rating])
}
}
But instead of explicitly get the user with ID equal 1 (User.get(1)) I need to access the user of the current session. I tried the following code, but it doesn't work:
class RatingController {
def rate = {
def rating = params.rating
def artist = Artist.get( params.id )
def user = user.session
user.addToRatings(new Rating(artist:artist, rating:rating))
user.save()
render(template: "/artist/rate", model: [artist: artist, rating: rating])
}
}
I'm still struggling to fully understand the httpSession concept, so a little help would be great.
Thank in advance.
UPDATE
In my UserController, my authentication looks like this:
def authenticate = {
def user = User.findByLoginAndPassword(params.login, params.password)
if(user){
session.user = user
flash.message = "Hello ${user.name}!"
redirect(controller:"event", action:"list")
}else{
flash.message = "Sorry, ${params.login}. Please try again."
redirect(action:"create")
}
}
the http session is nothing more than data that is maintained among a sequence of requests from a single source, like a browser.
To put something on the session, just do
session.setAttribute("key", value)
and to get data off the session just do
session.getAttribute("key")
Grails also adds some fanciness to session access as outlined here. Their example shows
def user = session["user"]
session["user"] = "John"
asset "John" == session.user
Note that if you are using a grails plugin for authentication and authorization, it will probably provide a way to get the user. For example Spring Security gives you the following
springSecurityService.getCurrentUser()
depending on the details of your plugin, that user might or might not be on the session.
In your code I noticed you wrote
def user = user.session
When I think you mean
def user = session.user
The other thing I do is make it session.userId ie session.userId = user.id and then
def user = User.get(session.userId)
Not sure if that's necessary.
You'll need to use .merge():
user.merge(flush: true)
This is because the instance is detached from the persistence context when you save it to HttpSession. Here is the doc from grails:
http://grails.org/doc/2.3.1/ref/Domain%20Classes/merge.html

Resources