ActiveRecord how to correctly exclude records with conditions correctly? - ruby-on-rails-3

Why does below not work?
Try to exclude all the is_reply = 1 values from the query but can't figure out how to.
I tried several combinations but all fail.
All records with is_reply = 1 still get returned with this below query, I think need to sub the or part but how?
#messages = Message.all(:conditions => ['is_reply = ? AND recipient_id
= ? OR user_id = ?', 0, current_user.id, current_user.id] )

You probably want to use parenthesis() and group your conditions together
['is_reply = ? AND (recipient_id = ? OR user_id = ?)', 0, current_user.id, current_user.id]

Related

Rails 5 - How to use postgresql query?

In rails 5, I am using pg(postgresql) for a back-end database. Now I want to query through rails and get the data. How can I use IN and ORDER(:created_at, :desc) conditions in a query.
In controller,
PAGE_LIMIT = 5
posts = Post.where("user_id IN (?)", [1,2,3]).order(created_at: :desc)
posts = posts.paginate(params[:page], PAGE_LIMIT)
I am writing a custom method like,
def paginate(page, limit = 5)
page = page ? page.to_i : 1
limit = limit.to_i
offset = (page - 1) * limit
self.offset(offset).limit(limit)
end
I am new to postgresql. Please help me to solve this issue?
suppose you have User model and you want to get user which has id in [1,2,3]
User.where("id IN (?)", [1,2,3]).order(created_at: :desc)
for more dynamic
x = [1,2,3]
name = "testing123"
User.where("name = ? AND id IN (?)", name, x).order(created_at: :desc)
for more details you can see Active Record Query
to make it working with pagination for array changes to be done here
modified answer
PAGE_LIMIT = 5
posts_arr = Post.where("user_id IN (?)", [1,2,3]).order(created_at: :desc)
posts = Post.where(id: posts_arr.map(&:id)) #here to get active records of posts to make it working for custom pagination
posts = posts.paginate(params[:page], PAGE_LIMIT)

sqlalchemy: paginate does not return the expected number of elements

I am using flask-sqlalchemy together with a sqlite database. I try to get all votes below date1
sub_query = models.VoteList.query.filter(models.VoteList.vote_datetime < date1)
sub_query = sub_query.filter(models.VoteList.group_id == selected_group.id)
sub_query = sub_query.filter(models.VoteList.user_id == g.user.id)
sub_query = sub_query.subquery()
old_votes = models.Papers.query.join(sub_query, sub_query.c.arxiv_id == models.Papers.arxiv_id).paginate(1, 4, False)
where the database model for VoteList looks like this
class VoteList(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
arxiv_id = db.Column(db.String(1000), db.ForeignKey('papers.arxiv_id'))
vote_datetime = db.Column(db.DateTime)
group = db.relationship("Groups", backref=db.backref('vote_list', lazy='dynamic'))
user = db.relationship("User", backref=db.backref('votes', lazy='dynamic'), foreign_keys=[user_id])
def __repr__(self):
return '<VoteList %r>' % (self.id)
I made sure that the 'old_votes' selection above has 20 elements. If I use .all() instead of .paginate() I get the expected 20 result?
Since I used a max results value of 4 in the example above I would expect that old_votes.items has 4 elements. But it has only 2? If I increase the max results value the number of elements also increases, but it is always below the max result value? Paginate seems to mess up something here?
any ideas?
thanks
carl
EDIT
I noticed that it works fine if I apply the paginate() function on add_columns(). So if I add (for no good reason) a column with
old_votes = models.Papers.query.join(sub_query, sub_query.c.arxiv_id == models.Papers.arxiv_id)
old_votes = old_votes.add_columns(sub_query.c.vote_datetime).paginate(page, VOTES_PER_PAGE, False)
it works fine? But since I don't need that column it would still be interesting to know what goes wrong with my example above?
Looks to me that for the 4 rows returned (and filtered) by the query, there are 4 rows representing 4 different rows of the VoteList table, but they refer/link/belong to only 2 different Papers models. When model instances are created, duplicates are filtered out, and therefore you get less rows. When you add a column from a subquery, the results are tuples of (Papers, vote_datetime), and in this case no duplicates are removed.
I encountered the same issue and I applied van's answer but it did not work. However I agree with van's explanation so I added .distinct() to the query like this:
old_votes = models.Papers.query.distinct().join(sub_query, sub_query.c.arxiv_id == models.Papers.arxiv_id).paginate(1, 4, False)
It worked as I expected.

How do I modify this where clause to check if a column has a nil value in SQL?

I have the following query:
user.all_memberships.where("user_id = ? OR invited_id = ?", user2.id, user2.id)
This is what my membership model looks like:
#<Membership id: 4, family_tree_id: 3, user_id: 1, created_at: "2015-10-23 20:33:41", updated_at: "2015-10-23 20:33:41", relation: nil, invited_id: nil>
What I would like the query to also check is if relation != nil....but not sure how to represent that in the SQL passed in to the where clause in quotes.
In other words, I would like for it to check for the presence of user2.id in either the user_id or invited_id column. But...relation also has to be NOT nil.
How do I do that?
Edit 1
When I do the following query, as per Blindy's suggestion below:
user.all_memberships.where("relation is not null and user_id = ? OR invited_id = ?", user2.id, user2.id)
It generates this query, that seems to work but based on the SQL it generates I am nervous about it. Notice the second AND and the second part of that statement. It feels like it may return false positives occasionally.
(0.9ms) SELECT COUNT(*) FROM "memberships" WHERE (memberships.user_id = 1 OR memberships.invited_id = 1) AND (relation is not null and user_id = 2 OR invited_id = 2)
How do I customize the AR where query to be more true to what I want to do and not have any hidden gotchas?
This isn't completely clear, but I think you mean something like:
relation is not null and (user_id = ? OR invited_id = ?)

ActiveRecord condition with count less than for association

I have a User that has_many messages.
I need a create a query that will
'Get me all users who's (message.opened == false) count < 3'
Right now, I am using User.all, iterating through all users, and counting manually. I understand that this isn't very efficient and it can be all done in one query, but I am new to SQL/ActiveRecord so need some help here.
Thanks
Assuming Rails 3 syntax. You can do something like:
User.joins(:messages).where(:messages => {:opened => false}).group(:user_id).having("COUNT(messages.id) < 3)
This should work:
User.includes(:messages).group("users.id").where("messages.opened = 0").having("count(messages.id) < 3")
This will create two queries, one for the grouped query, and one for eager loading the resulting users and messages with a join.
Here is solution to your problem
User.includes(:messages).group("users.id").where("messages.opened = 0").having("count(messages.id) < 3")
but what else you can do is to create a scope for this
scope :not_opened_less_three_count, includes(:messages).group("users.id").where("messages.opened = 0").having("count(messages.id) < 3")
And then you can use it anywhere you needed as follow
User.not_opened_less_three_count
Try this
User.includes(:messages).group('users.id').having('SUM(IFNULL(messages.opened = 0, 1)) < 3')
It works at least on MySQL, AND assuming your boolean true are 1 in database.
EDIT I had reversed the condition
PS IFNULL is there to handle if messages.opened can be NULL

Rails 3.0 One-One Association Using associated model in WHERE clause

When I do:
conditions = {:first_name => 'Chris'}
Patient.joins(:user).find(:all, :conditions => conditions)
It Produces (and fails because the first_name is not in the patients table)
SELECT "patients".* FROM "patients" INNER JOIN "users" ON "users"."id" = "patients"."user_id" WHERE "patients"."first_name" = 'Chris'
I need to be able to query the User model's fields also and get back Patient objects. Is this possible?
Try this:
conditions = ['users.first_name = ?', 'Chris']
Patient.joins(:user).find(:all, :conditions => conditions)
Try changing you conditions hash to:
conditions = {'users.first_name' => 'Chris'}
I've used this style in Rails 2.3, and it worked great for me. Cheers!