Remove Object from a list of objects rails - sql

I have a rails object array of list of users and another object array of list of team_users
I want to show the list of users that are not in team_users but not sure how to go about it .
In my code
User.where("users.user_account_type IS NULL or users.user_account_type = 'standard_user'").joins(:user_organizations).where("user_organizations.organization_id = ? AND users.approved = true AND users.locked_at IS NULL", 13)
This code returns to me a list of users
#team_members = TeamMember.all
This returns to me all users that are in team_members. This table has team_member_id as the foreign key for user.id in the User table.
User.where("users.user_account_type IS NULL or users.user_account_type = 'standard_user'").joins(:user_organizations).where("user_organizations.organization_id = ? AND users.approved = true AND users.locked_at IS NULL", 13).joins(:team_members).where("team_members.team_member_id != users.id")
I tried using this code but it doesnt work. it returns no records.
Any help is appreciated

Something like this should work:
in_teams = TeamMember.select(:team_member_id)
users_without_team = User.where.not(id: in_teams)
Also you could use hashes instead of strings for the readability:
Users.joins(:user_organization).where(approved: true, locked_at: nil, user_organizations: {organization_id: 13})

Im not sure what you want exactly but this returns only users which dont have the team_users account typ.
User.All.Where(x=>x.Users.user_account_type !="team_users")

Related

SQL injections in Rails 4 issue

I'm trying to learn about SQL injections and have tried to implement these, but when I put this code in my controller:
params[:username] = "johndoe') OR admin = 't' --"
#user_query = User.find(:first, :conditions => "username = '#{params[:username]}'")
I get the following error:
Couldn't find all Users with 'id': (first, {:conditions=>"username = 'johndoe') OR admin = 't' --'"}) (found 0 results, but was looking for 2)
I have created a User Model with the username "johndoe", but I am still getting no proper response. BTW I am using Rails 4.
You're using an ancient Rails syntax. Don't use
find(:first, :condition => <condition>) ...
Instead use
User.where(<condtion>).first
find accepts a list of IDs to lookup records for. You're giving it an ID of :first and an ID of condition: ..., which aren't going to match any records.
User.where(attr1: value, attr2: value2)
or for single items
User.find_by(attr1: value, attr2: value)
Bear in mind that while doing all this, it would be valuable to check what the actual sql statement is by adding "to_sql" to the end of the query method (From what I remember, find_by just does a LIMIT by 1)

Is this block of code efficient?

I am trying to assign a variable tagcolor only if it already exists in the database. This code queries the DB twice if the color is present, once to determine if it does indeed exist and another to actually assign it.
If it doesn't exist I just want to assign tagcolor to the user provided color.
if Tagmap.where("name = ? AND user_id = ?", tag, current_user.id).first.present?
tagcolor = Tagmap.where("name = ? AND user_id = ?", tag, current_user.id).first.color
else
tagcolor = params[:color].downcase
end
Can I reduce this block so I just query the DB once?
Provided you're on Rails 4, you can do:
tagcolor = Tagmap.find_by(name: tag, user: current_user).try(:color) || params[:color].downcase
Similar (but not that pretty) construction is possible in Rails 3:
tagcolor = Tagmap.find_by_name_and_user(tag, current_user).try(:color) || params[:color].downcase

Find all matching criteria where conditions not in array

I am trying to return a variable with values of an array of users. There are a few conditions that must be met. The user must have public_find set to true, it must not be the current_user (session variable of the user currently logged in), and it must not already be part of a friendship. The first and second conditions work perfectly. However, I am having an issue with the third part where the current_users.friendships needs to be an array of the ID values of the users where the association already exists. Any thoughts?
#users = User.find(:all, :conditions => ['
public_find=true AND
id <> ? AND
id NOT IN (?)',
current_user.id, current_user.friendships])
Edit:
I've figured out that I was missing pluck from the list. This works good now. However, if someone does not yet have a friend then current_user.friendships.pluck(:friend_id) will return NULL. I know that it is bad practice and unexpected results returned when using NOT IN and NULL. However, how do you create a condition where you can set the value to something realistic like [0] or [1] if the array returned is empty?
#users = User.find(:all, :conditions => ['
public_find=true AND
id <> ? AND
id NOT IN (?)',
current_user.id, current_user.friendships.pluck(:friend_id) || [0]])
EDIT AGAIN:
I got it working. However, now I want to know if this is best practice to have a statement like this. It basically is doing a check to see if the current_user.friendships.pluck(:friend_id) is empty or not. If it is then return [0]. Otherwise return an array of the user ids (foreign keyed as friend_id).
#users = User.find(:all, :conditions => ['
public_find=true AND
id <> ? AND
id NOT IN (?)',
current_user.id,
(current_user.friendships.pluck(:friend_id).empty? ? [0] : current_user.friendships.pluck(:friend_id))])
You can write this a little nicer ..
Show all users where public_find is true and also exclude the currently logged in user or any of their friends
ids = current_user.friendships.map(&:friend_id).concat([current_user.id])
#users = User.where(:public_find => true).where('id not in ?', ids)
I would use an arel table for this (which guarantees the code will work on any database):
t, f = User.arel_table, current_user.friendships
query = t[:public_find].eq(true).and(t[:id].not_eq(current_user.id))
query = query.and(t[:id].not_in(f.pluck(:friend_id))) unless f.empty?
#users = User.where(query)
Generated SQL for current_user = 3 and a single friendship with a user with id = 1:
SELECT "users".* FROM "users"
WHERE ("users"."public_find" = 't' AND "users"."id" != 3 AND "users"."id" NOT IN (1))
If current_user.friendships is nil, the unless f.empty? clause will prevent that condition from being applied at all, so it will not appear in the SQL:
SELECT "users".* FROM "users"
WHERE ("users"."public_find" = 't' AND "users"."id" != 3)
Also, note that because this code uses where instead of find, the final result is an ActiveRecord::Relation rather than an array of results. This means that you can further chain conditions onto it, e.g. to order the results by updated_at, change the last line to:
#users = User.where(query).order(:created_at)

Querying distinct with MongoMapper

How do I query distinct with MongoMapper? My query is:
subscribedToThread = Comment.where(:subscribe_thread => 1).all
But this will return many objects with the same user_id. I need to return just a distinct user_id. Is this possible?
I think you will need to drop down to the ruby driver in order to do this as I don't think you can do this with MongoMapper itself:
subscribedToThread = Comment.collection.distinct("user_id", {:subscribe_thread => 1})
Calling the collection method on a model returns the collection as would be provided by the Ruby driver directly so you can issue a distinct query using the syntax below:
collection.distinct(key, query = nil)
You can read more about it here
Yes, you can do so:
subscribedToThread = Comment.where(:subscribe_thread => 1).fields(:user_id).all.compact!.unique!
This will nil every field but user_id which you then uniq!,ie you remove all doubles and then compact! all nil
http://mongomapper.com/documentation/plugins/querying.html#fields
Try this
subscribedToThread = Comment.where(:subscribe_thread => 1).fields(:user_id).collect(&:user_id).uniq
It will show you list of uniq user_id

NHibernate IQueryOver where clause with a collection

I'm attemping to do a simple check for an empty collection in an NHIbernate Query. Here's my code:
var query = QueryNotDeleted().Where(x=>x.Markets.Count() > 0);
QueryNotDeleted returns an IQueryOver. The above line throws an error (Unrecognised method call in epression x.Markets.Count()) because it doesn't recognize the Count() in the query.
I tried
var query = QueryNotDeleted().Where(x=>x.Markets != null);
But unfortunately, Markets is never NULL, so I have to test for a count instead of it being null to get the records I want.
How can I get this "count" syntax correct so that it excludes records where the Markets property is empty?
I was able to get it to work using:
query.RootCriteria.CreateAlias("Markets", "m", JoinType.LeftOuterJoin);
and then
query.RootCriteria.Add(Restrictions.IsNotNull("m.Id"));
If I understand your question correctly you want to get a list of records that don't have corresponding children?
If I wanted to get a list of Orders that have no OrderItems using QueryOver then I would do something like:-
var orders = session.QueryOver<Order>()
.Left.JoinQueryOver(w => w.Items)
.Where(w => w.Order.Id == null);
If this is not the right answer then please can you submit the SQL you are trying to run and the parent/children mappings/.