how to do a grails findAllBy with one to many relationship - grails

I have a one to many relationship between User and Task and want to get all of the tasks for that user, but my query isn't returning any results. Here's what I have:
def getByStatus(String findBy) {
// either get by Open/Closed or by All.
def sortPref = [sort: "deadline", order: "asc"]
def u = User.get(session.user.id) // session.user is a user domain object
if (findBy != "All")
tasks = Task.findAllByUserAndStatus(u, findBy, sortPref)
else
tasks = Task.findAllByUser(u, sortPref)
}
I also tried searching by .findByUserIdAndStatus, but got an error saying that there was no UserId property on task. If I remove the user part, then I get all of the tasks.

Assuming there is no issue with lazy loading (assuming # of tasks per user is not considerably high), you can directly get required tasks based on user (from 1:M relationship) as:
def getByStatus(String findBy) {
// either get by Open/Closed or by All.
def u = User.get(session.user.id) // session.user is a user domain object
def tasks = findBy == 'All' ? u.tasks.sort{it.deadline} :
u.tasks.findAll{it.status == findBy}.sort{it.deadline}
}
If interested, you can have the sort set in the mapping of the domain class.

Related

Add multiple filters in Spree Commerce Rails

We need to implement custom filters for categories in spree ecommerce in latest version as seen here https://github.com/spree/spree .
We need to do it in a dynamic way because we have about 100 filters or more to make. The ideal solution would be to show all available filters in admin area and admin can activate/deactivate them for each category.
Current Scenario:
We know how to make a new filter and apply it. But it takes about four methods per filter as shown in the product_filter.rb file linked below.
Some links we have found useful:
https://gist.github.com/maxivak/cc73b88699c9c6b45a95
https://github.com/radar/spree-core/blob/master/lib/spree/product_filters.rb
Here is some code that allows you to filter by multiple properties. It is not ideal (no proper validation etc) but I guess it is better than doing multiple "in" subqueries.
def add_search_scopes(base_scope)
joins = nil
conditions = nil
product_property_alias = nil
i = 1
search.each do |name, scope_attribute|
scope_name = name.to_sym
# If method is defined in product_filters
if base_scope.respond_to?(:search_scopes) && base_scope.search_scopes.include?(scope_name.to_sym)
base_scope = base_scope.send(scope_name, *scope_attribute)
else
next if scope_attribute.first.empty?
# Find property by name
property_name = name.gsub('_any', '').gsub('selective_', '')
property = Spree::Property.find_by_name(property_name)
next unless property
# Table joins
joins = product if joins.nil?
product_property_alias = product_property.alias("filter_product_property_#{i}")
joins = joins.join(product_property_alias).on(product[:id].eq(product_property_alias[:product_id]))
i += 1
# Conditions
condition = product_property_alias[:property_id].eq(property.id)
.and(product_property_alias[:value].eq(scope_attribute))
conditions = conditions.nil? ? condition : conditions.and(condition)
end
end if search.is_a?(Hash)
joins ? base_scope.joins(joins.join_sources).where(conditions) : base_scope
end
def prepare(params)
super
#properties[:product] = Spree::Product.arel_table
#properties[:product_property] = Spree::ProductProperty.arel_table
end

Grails - find all by presence of child obj in parent collection

I have 2 domain classes: Project and User.
Project hasMany on User via a SortedSet called allowedUsers. User does not belong to Project.
I want to find all Projects that a particular user is allowed to see. So trying syntax like:
Project.findAll{ it.allowedUsers.contains( userA ) }
Project.findAll{ userA in it.allowedUsers }
These dont work. And the find notation doesn't appear to support something like a ThatContains operator.
How can I achieve my aim?
Criteria should work, take a look at the "querying associations" section in http://grails.org/doc/latest/guide/GORM.html#criteria. Can you try the following:
def c = Project.createCriteria()
def results = c.list {
allowedUsers{
eq('id', userA.id)
}
}
You can also try where queries
def query = Project.where{
allowedUsers{id == userA.id}
}
def results = query.list()
or HQL
def query = """
select p from Project as p
inner join p.allowedUsers as user
where user.id = :user
"""
def results = Project.executeQuery(query, [user: userA.id])

removing objects from an array during a loop

I am trying to filter the results of an user search in my app to only show users who are NOT friends. My friends table has 3 columns; f1 (userid of person who sent request), f2 (userid of friend who received request), and confirmed (boolean of true or false). As you can see, #usersfiltered is the result of the search. Then the definition of the current user's friend is established. Then I am trying to remove the friends from the search results. This does not seem to be working but should be pretty straight forward. I've tried delete (not good) and destroy.
def index
#THIS IS THE SEARCH RESULT
#usersfiltered = User.where("first_name LIKE?", "%#{params[:first_name]}%" )
#THIS IS DEFINING ROWS ON THE FRIEND TABLE THAT BELONG TO CURRENT USER
#confirmedfriends = Friend.where(:confirmed => true)
friendsapproved = #confirmedfriends.where(:f2 => current_user.id)
friendsrequestedapproved = #confirmedfriends.where(:f1 => current_user.id)
#GOING THROUGH SEARCH RESULTS
#usersfiltered.each do |usersfiltered|
if friendsapproved.present?
friendsapproved.each do |fa|
if usersfiltered.id == fa.f1
#NEED TO REMOVE THIS FROM RESULTS HERE SOMEHOW
usersfiltered.remove
end
end
end
#SAME LOGIC
if friendsrequestedapproved.present?
friendsrequestedapproved.each do |fra|
if usersfiltered.id == fra.f2
usersfiltered.remove
end
end
end
end
end
I would flip it around the other way. Take the logic that is loop-invariant out of the loop, which gives a good first-order simplification:
approved_ids = []
approved_ids = friendsapproved.map { |fa| fa.f1 } if friendsapproved.present?
approved_ids += friendsrequestedapproved.map { |fra| fra.f2 } if friendsrequestedapproved.present?
approved_ids.uniq! # (May not be needed)
#usersfiltered.delete_if { |user| approved_ids.include? user.id }
This could probably be simplified further if friendsapproved and friendsrequestedapproved have been created separately strictly for the purpose of the deletions. You could generate a single friendsapproval list consisting of both and avoid unioning id sets above.
While I agree that there may be better ways to implement what you're doing, I think the specific problem you're facing is that in Rails 4, the where method returns an ActiveRecord::Relation not an Array. While you can use each on a Relation, you cannot in general perform array operations.
However, you can convert a Relation to an Array with the to_a method as in:
#usersfiltered = User.where("first_name LIKE?", "%#{params[:first_name]}%" ).to_a
This would then allow you to do the following within your loop:
usersfiltered.delete(fa)

Spock test cases doesn't make a relationship of domain classes in Grails?

I have a Spock test case, in which the setup block looks like this :
setup: "set the required objects"
def company = new Company(shortName:"infyyy",fullName:"infoysys",
region:"tamilnadu" ,email:"a#ac.com" ,telphone:34343433,fax:34343433).save(failOnError:true)
def project = new Project(name:"testing")
def userInstance = new User(username:username,password:password,
company:company,project:project,pt:["dummy"]).save(failOnError:true)
def tasksInstance = new Tasks(title:"testingwork",startDate:(new Date()-4),endDate:(new Date().clearTime()-6),description:"blah blah",project:project,completed:true,user:userInstance).save(failOnError:true)
And more over, the Tasks domain class looks like this :
class Tasks {
static belongsTo = [ user : User, project: Project ]
//other code
}
And User class is like this :
class User {
static hasMany = [ holidays : Holiday, tasks : Tasks, pt:String, project: Project ]
//other code
}
But when I run my test and my test fails(not with an error message, but it fails in the then block of my Spock test) and I find a error in it. My setup doesn't create any relationship between User and Tasks, which makes my test to fail.
The controller code, which I'm trying to test is :
def todaysTasks() {
def user = User.get(springSecurityService.principal.id)
def choice = params.managersProject
params.max = Math.min(params.max ? params.int('max') : 10,100)
def search = Tasks.createCriteria().list(max: params.max as Integer, offset: params.offset as Integer, order: params.order as String, sort : params.sort) {
and {
project {
like('name',"${choice}")
}
eq('endDate', new Date().clearTime())
}
}
println "todays task selected project is " + search
[tasksInstanceList : search, tasksInstanceTotal: search.getTotalCount() ]
}
The println in the above test prints 0. Why does this happen even though I'm making the endDate in my test less than today's date?
Thanks in advance.
As far as I know, GORM does not auto-populate relationships, by following a belongsTo relationship.
I always do the following.
def u=new User(...)
u.addToTasks(
title:"testingwork",
startDate:(new Date()-4),
endDate:...
)
u.save()
Note that I have not created a task object. I have passed the Map of values directly to addToX... this emphasizes that the added object belongs to User and should be instantiated and saved by GORM.
You cannot (and you shouldn't) test criteria queries in your unit tests. Criteria queires are not supported in grails (and spock) unit tests. Read this question for possible solutions.

Match one Sec role among many roles of SecUser grails

I have admin user with following five roles[ROLE_ADMIN,ROLESWITCHUSER,ROLE_DOCTOR,ROLE_USER]
and some normal users with only one role i.e ROLE_USER ,now my question is how can i get only normal users from my secuser table i tried with somne iterations
def roleId=SecRole.findByAuthority("ROLE_USER")
userInstance = SecUserSecRole.findAllBySecRole(roleId).secUser
here i got userInstance with all users along with adminuser now i tried to elminate adminuser from my userInstance and saved it in selectUserMap but am getting result for sometime and sometimes its giving all users. I think the sort() function not sorting the userinstansce roles please help me
for(int i=0;i<userInstance.size();i++)
{
println( "am in loop "+i+userInstance[i].username+"roles"+userInstance[i].getAuthorities())
def x=(userInstance[i].getAuthorities().sort())
for(a in x )
{ //println(a.getAuthority())
if((a.getAuthority() == use))
abc=true
else
abc=false
if((a.getAuthority() == adm))
{
println("break")
break;
}
abc=(abc && (a.getAuthority() == use))
if(abc)
{
println("am in true if ")
selectUserMap.add(j,userInstance[i])
j=j+1
}
else
{
println("am in else")
}
}
}
println("==============all users "+selectUserMap)
One thing that would help is to use hierarchical roles - see section "14 Hierarchical Roles" at http://grails-plugins.github.com/grails-spring-security-core/docs/manual/ - and then you wouldn't grant ROLE_USER to anyone but "real" users. If you define your hierarchy like this:
grails.plugins.springsecurity.roleHierarchy = '''
ROLE_ADMIN > ROLE_USER
ROLE_DOCTOR > ROLE_USER
ROLE_ADMIN > ROLE_DOCTOR
'''
then you don't need to explicitly grant ROLE_USER in the database to either a doctor or an admin, but the role will be inferred as granted. Then your original query will work:
def userRole = SecRole.findByAuthority("ROLE_USER")
def usersWithUserRole = SecUserSecRole.findAllBySecRole(userRole).secUser
If you can't or don't want to do this, then you should use a proper database query. It's extremely and unnecessarily expensive to load every user and every user's roles from the database and filter them out in your application. Use this HQL query:
def userRole = SecRole.findByAuthority("ROLE_USER")
def users = SecUserSecRole.executeQuery(
'select u from SecUser u where ' +
'(select count(ur.user) from SecUserSecRole ur where ur.user=u)=1 and ' +
'(:r in (select ur.role from SecUserSecRole ur where ur.user=u))',
[r: userRole])
Oh, you've choosen really complicated way, can understand your algorhitm :( Maybe this is enough:
List selectUserList = userInstance.findAll {
List roles = it.authorities*.authority
return roles.contains('ROLE_USER') && !roles.contains('ROLE_ADMIN')
}
I guess you can build selectUserMap from this selectUserList list (can't understand where you get j)
PS maybe it's better to rename userInstance to userInstances, because it's a list actually, not one instance?

Resources