Grails/Groovy: Cannot cast object to java.util.Set (twitter clone project) - grails

I am trying to make a follow user like in twitter. I'm getting an exception when I try to save the user of the currently logged in session user.
Error 500: Internal Server Error
URI - /blog-dwit/user/follow/3
Class - org.codehaus.groovy.runtime.typehandling.GroovyCastException
Message - Cannot cast object 'blog.dwit.User : 3' with class 'blog.dwit.User' to class 'java.util.Set'
User domain:
class User {
String email_id;
String password;
Profile profile
static hasMany = [ posts:Post, following: User ]
}
Controller action
def follow(){
def followUser = User.get(params.id)
def user = User.get(session.user)
user.following = followUser
user.save()
}

When adding instances to collections you have to use the addTo* method for the corresponding collection. The documentation explains this in further detail.
Your action should look like this:
def follow(){
def followUser = User.get(params.id)
def user = User.get(session.user)
user.addToFollowing(followUser)
user.save()
}

Related

Grails find in relationship

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()

Writing an Integration Test in Grails that will test DB persistence

My Integration-Test for my grails application is returning a null object when I try to get a domain object using grails dynamic get method.
This is a simplified example of my problem. Lets say I have a controller TrackerLogController that uses a service TrackerLogService to save an updated Log domain for another Tracker domain.
Domain Tracker:
class Tracker {
int id
String name
static hasMany = [logs: Log]
}
Domain Log:
class Log {
int id
String comment
static belongsTo = [tracker: Tracker]
}
Controller TrackerLogController save:
def TrackerLogService
def saveTrackerLog() {
def trackerId = params.trackerId
def trackerInstance = Tracker.get(trackerId)
Log log = TrackerLogService.saveTrackerLogs(trackerInstance, params.comment)
if( log.hasErrors() ){
//render error page
}
//render good page
}
Service TrackerLogService save:
Log saveTrackerLogs( Tracker tracker, String comment) {
Log log = new Log(tracker: tracker, comment: comment)
log.save()
return log
}
So now I want to write an Integration-Test for this service but I'm not sure if I should be writing one just for the simple logic in the controller (if error, error page else good page) I would think I would write a Unit test for that, and an Integration-Test to check the persistence in the Database.
This is what I have for my Integration-Test:
class TrackerLogServiceTests {
def trackerLogService
#Before
void setUp(){
def tracker = new Tracker(id: 123, name: "First")
tracker.save()
//Now even if I call Tracker.get(123) it will return a null value...
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(123) //I have tried findById as well
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
So for this example my trackerInstance would be a null object. I know the Grails magic doesn't seem to work for Unit tests without Mocking, I thought for Intigration-Tests for persistence in the DB you would be able to use that grails magic.
You can't specify the id value unless you declare that it's "assigned". As it is now it's using an auto-increment, so your 123 value isn't used. It's actually ignored by the map constructor for security reasons, so you'd need to do this:
def tracker = new Tracker(name: "First")
tracker.id = 123
but then it would get overwritten by the auto-increment lookup. Use this approach instead:
class TrackerLogServiceTests {
def trackerLogService
private trackerId
#Before
void setUp(){
def tracker = new Tracker(name: "First")
tracker.save()
trackerId = tracker.id
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(trackerId)
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
Also, unrelated - don't declare the id field unless it's a nonstandard type, e.g. a String. Grails adds that for you, along with the version field. All you need is
class Tracker {
String name
static hasMany = [logs: Log]
}
and
class Log {
String comment
static belongsTo = [tracker: Tracker]
}

springSecurityService.principal.id giving firstname instead of userid

I am using springSecurityCore plugin in my application and after user login in the appStartupController, I do like
def index = {
if (springSecurityService.isLoggedIn()) {
session.loginId=springSecurityService.principal.id
def userRole=UserRole.findAllByUserAndRole(User.get(session.loginId), Role.findByAuthority('ROLE_USERSDASH'))
if(userRole){
redirect(controller:'dashboard',action:'getRiskUserDashboard')
}
}
}
when I read session.loginId in the header.gsp I see the firstname from the User table is printed.
I need to have the userId field in the User table mapped to the session.loginId.
How to do that?
You can get the current User by calling the following:
def user = springSecurityService.getCurrentUser()
And then just pass that user into the UserRole find method.

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