can't query by association field value - ruby-on-rails

I need to query only Realties where user id confirmed.
I am using "devise" gem for authentication, and my query looks like this:
#search = Realty.includes(:user).where("users.confirmed_at != ?", nil)
As result I get => [], but there are many Realties records where user.confirmed? => true. I double checked it from the console.
The association structure looks like this:
class Realty
belongs_to :user
.....
class User
has_many :realties
.....
Please help me or tell where I make an mistake ??
Thank you.

#search = Realty.includes(:user).where("users.confirmed_at IS NOT NULL")
You cannot use != in a SQL statement.
If you want to check if the value is not empty as well, then you can do
#search = Realty.includes(:user).where("users.confirmed_at <> ''")
it will return the results where users.confirmed_at is neither null nor empty.

Related

Is the correct: "Employee.where(age: <"60").order(:first name)"?

I am trying to use 'Employee.where(age: <"60").order(:first name)'. It is not working. Is there something wrong?
Assuming your :age field is an integer and you need to order by :first_name it goes like this:
Employee.where('age < ?', 60).order(:first_name)
Please take a look into documentation. You will find the descriptions to each ActiveRecord query method, including where and order.
I would do it like:
#Controller
#employees = Employee.sort_by_name('first_name ASC').young_employees
#model
scope :sort_by_name, ->(criteria) { order: criteria }
scope :young_employes, -> { where("age < ?", 60)}
In order to this to work, please check that your 'age' columns is integer type, and also that your first name columns is called 'first_name'

ActiveRecord: Scope for where attribute is present

I want to grab those Blogs where its title.present? == true. (Blogs have a string attribute of title).
class Blog < ActiveRecord::Base
scope :with_present_titles, -> {where("#{title.present?} == ?", true)} #doesn't work
end
#blogs = Blog.with_present_titles #doesn't work
Not sure what I'm doing wrong here.
To return all records with some values in title column, you would update your scope with the following query:
scope :with_present_titles, -> { where("title is not null and title != ''") }
This returns all records with some value in title column leaving any null and empty titles.
.present? being a method provided by rails, you cannot simply use these methods in your DB queries.
Depending on your rails version you can also use where.not (introduced in rails 4) E.g.
scope :with_present_titles, ->{where.not(title: [nil,'']) }
#Blog.with_present_titles.to_sql
#=> "SELECT [blogs].*
# FROM [blogs]
# WHERE (NOT (([blogs].[title] = '' OR [blogs].[title] IS NULL)))"
Simply write the following scope.
scope :with_present_titles, -> { where('title IS NOT ? AND TITLE != ?', nil, '') }

Rails 3: Trying to understand join query

I have a User class and a GroupUser class. I'm trying to do a search by name of the users. I tried following what I read on the joins, but I have something wrong. Also I need to change my name portion of the query to a like instead of an equals
Here is the query I had initially built.
#users = GroupUser.joins(:users).where(:group_id => params[:group_id]).where(:users => {:name => params[:q]})
Try this:
#users = User.where("name ilike ? and id in (select distinct user_id from groups_users where group_id = ?)", "%#{params[:q]}%", params[:group_id])

Difference Between find and Where with Relationships

I wouldn't think there is a difference when it comes to active record and finding data.
Here are my models
class User < ActiveRecord::Base
has_many :shows
end
class Show < ActiveRecord::Base
belongs_to :user
end
When I use the rails console I can do the following and it works.
u = User.find(1)
u.shows
It gives me all the shows for that user.
However when I do
u = User.where("username = ?", "percent20")
u.shows # this is doesn't work gives me a now instance error
I get the same user and relevant information, but not the relationship. The only problem I can see is maybe I am doing something wrong because there is some difference between where and find.
Any help is appreciated.
The problem is not the relationship.
u = User.find(1)
returns one User
#return a Set of users. In your case its only one user.
u = User.where("username = ?", "percent20")
The result type is ActiveRecord::Relation --> [User, User, User]
use e.g. first to get the first User
#returns the first user
u = User.where("username = ?", "percent20").first
u.class.name
=> "User"
User.find(1) is retrieving a specific record with its ID, whereas User.where("username = ?", "percent20") is retrieving the set of records that match the condition.
Try:
u = User.where("username = ?", "percent20").first
u.shows
The where is method that returns an array of objects. So, in your case try
u.each { |user| user.shows }

Rails ActiveRecord: Find All Users Except Current User

I feel this should be very simple but my brain is short-circuiting on it. If I have an object representing the current user, and want to query for all users except the current user, how can I do this, taking into account that the current user can sometimes be nil?
This is what I am doing right now:
def index
#users = User.all
#users.delete current_user
end
What I don't like is that I am doing post-processing on the query result. Besides feeling a little wrong, I don't think this will work nicely if I convert the query over to be run with will_paginate. Any suggestions for how to do this with a query? Thanks.
It is possible to do the following in Rails 4 and up:
User.where.not(id: id)
You can wrap it in a nice scope.
scope :all_except, ->(user) { where.not(id: user) }
#users = User.all_except(current_user)
Or use a class method if you prefer:
def self.all_except(user)
where.not(id: user)
end
Both methods will return an AR relation object. This means you can chain method calls:
#users = User.all_except(current_user).paginate
You can exclude any number of users because where() also accepts an array.
#users = User.all_except([1,2,3])
For example:
#users = User.all_except(User.unverified)
And even through other associations:
class Post < ActiveRecord::Base
has_many :comments
has_many :commenters, -> { uniq }, through: :comments
end
#commenters = #post.commenters.all_except(#post.author)
See where.not() in the API Docs.
#users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))
You can also create named_scope, e.g. in your model:
named_scope :without_user, lambda{|user| user ? {:conditions => ["id != ?", user.id]} : {} }
and in controller:
def index
#users = User.without_user(current_user).paginate
end
This scope will return all users when called with nil and all users except given in param in other case. The advantage of this solution is that you are free to chain this call with other named scopes or will_paginate paginate method.
Here is a shorter version:
User.all :conditions => (current_user ? ["id != ?", current_user.id] : [])
One note on GhandaL's answer - at least in Rails 3, it's worth modifying to
scope :without_user, lambda{|user| user ? {:conditions => ["users.id != ?", user.id]} : {} }
(the primary change here is from 'id != ...' to 'users.id !=...'; also scope instead of named_scope for Rails 3)
The original version works fine when simply scoping the Users table. When applying the scope to an association (e.g. team.members.without_user(current_user).... ), this change was required to clarify which table we're using for the id comparison. I saw a SQL error (using SQLite) without it.
Apologies for the separate answer...i don't yet have the reputation to comment directly on GhandaL's answer.
Very easy solution I used
#users = User.all.where("id != ?", current_user.id)
User.all.where("id NOT IN(?)", current_user.id) will through exception
undefined method where for #<Array:0x0000000aef08f8>
User.where("id NOT IN (?)", current_user.id)
Another easy way you could do it:
#users = User.all.where("id NOT IN(?)", current_user.id)
an array would be more helpful
arrayID[0]=1
arrayID[1]=3
User.where.not(id: arrayID)
User.where(:id.ne=> current_user.id)
ActiveRecord::QueryMethods#excluding (Rails 7+)
Starting from Rails 7, there is a new method ActiveRecord::QueryMethods#excluding.
A quote right from the official Rails docs:
excluding(*records)
Excludes the specified record (or collection of records) from the resulting relation. For example:
Post.excluding(post)
# SELECT "posts".* FROM "posts" WHERE "posts"."id" != 1
Post.excluding(post_one, post_two)
# SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
This can also be called on associations. As with the above example, either a single record of collection thereof may be specified:
post = Post.find(1)
comment = Comment.find(2)
post.comments.excluding(comment)
# SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 AND "comments"."id" != 2
This is short-hand for .where.not(id: post.id) and .where.not(id: [post_one.id, post_two.id]).
An ArgumentError will be raised if either no records are specified, or if any of the records in the collection (if a collection is passed in) are not instances of the same model that the relation is scoping.
Also aliased as: without
Sources:
Official docs - ActiveRecord::QueryMethods#excluding
PR - Add #excluding to ActiveRecord::Relation to exclude a record (or collection of records) from the resulting relation.
What's Cooking in Rails 7?
What you are doing is deleting the current_user from the #users Array. This won't work since there isn't a delete method for arrays. What you probably want to do is this
def index
#users = User.all
#users - [current_user]
end
This will return a copy of the #users array, but with the current_user object removed (it it was contained in the array in the first place.
Note: This may not work if array subtraction is based on exact matches of objects and not the content. But it worked with strings when I tried it. Remember to enclose current_user in [] to force it into an Array.

Resources