I have three models
class Place < ActiveRecord::Base
acts_as_followable
has_many :events
end
class Event < ActiveRecord::Base
attr_accessible :startdate
acts_as_followable
belongs_to :place
belongs_to :user
end
class User < ActiveRecord::Base
acts_as_followable
acts_as_follower
has_many :events
end
I need to do two things:
get a homogeneous sorted list of events for followed places or users
get a homogeneous sorted list of events for followed places and users and events without duplicates
So for instance
User.find(1).following_places.includes(:events).collect{|p| p.events}.flatten.sort{|a,b| a.startdate <=> b.startdate}
should return a list of events for all of the places a user is following, sorted by date. The issue with this, if I am understanding correctly, is that the collect, flatten, and sort occur in ruby instead of SQL.
The second part should look something like the following, and ideally occur entirely in SQL as well:
user = User.find(1)
(user..following_places.includes(:events).collect{|p| p.events}.flatten +
user.following_users.includes(:events).collect{|p| p.events}.flatten +
user.following_events).sort{|a,b| a.startdate <=> b.startdate}
This answer is close, but not quite what I am looking for.
Thanks for your help!
Have you tried using order?
User.find(1).following_places.includes(:events).order('events.startdate ASC')
Related
I'm facing an Rails (and finally a pur SQL) issue.
I have 3 tables (models). Event / User / Invitation
class Event < ApplicationRecord
has_many :invitations
end
class User < ApplicationRecord
has_many :invitations
has_many :events, through: :invitations
end
class Invitation < ApplicationRecord
belongs_to :event
belongs_to :user
end
I want to list all events where a specific user does not have invitation.
Contraints (very important in my case):
I'm starting my request by Event.
Basically, I would say it's the opposite of a merge, like a merge.not(user.events).
The only solution I found is:
Event.where.not(id: user.events.pluck(:id))
But obviously, I don't like it. 2 queries that might be somehow merge into a single one.
Any idea?
use select instead of pluck, it will create sub-query instead pulling records from database. Rails ActiveRecord Subqueries
Event.where.not(id: user.events.select(:id))
I'm having some trouble trying to fetch some models via SQL in rails and I was wondering if anyone knows of a good solution for this particular problem. Basically, these are what my classes look like:
class SubscriberList < ActiveRecord::Base
has_many :subscriptions
end
class Subscription < ActiveRecord::Base
has_many :messages
belongs_to :subscription_list
end
class Announcement < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :subscription
belongs_to :announcement
end
Now, I want to access all the Announcements for a SubscriptionList excluding duplicates. Is this possible? Can it be done with a single SQL query or is that just wishful thinking?
For example here's what I want:
class SubscriptionList < ActiveRecord::Base
def announcements
Announcements.joins(:messages).where(message: { subscription: {subscription_list: self} })
end
end
I think your idea is correct in general. Try this variant
Announcements.
joins(messages: {subscription: :subscription_list}).
where(subscription_lists: {id: self.id})
# opposite
SubscriptionList.
joins(subscriptions: {messages: :announcement}).
where(announcements: {id: self.id})
Notes:
* these queries may return duplicates - so uniq can be added to them
* self can be omitted (I wrote it to show that this is id of instance and avoid missunderstanding)
I have the following table structure
manufacturers --> products ---> available_sizes_products <-- sizes
and the following models
class Manufacturer < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
has_many :sizes, :through => :available_sizes_products
has_many :available_sizes_products
end
class AvailableProductSize < ActiveRecord::Base
belongs_to :sizes
belongs_to :products
end
class Size < ActiveRecord::Base
has_many :products, :through => :available_sizes_products
has_many :available_sizes_products
end
I need to get a unique list of manufacturers, that have products in size "XL" or "L" for example.I'm getting lost in the chaining of joins etc.
class Manufacturer < ActiveRecord::Base
def self.with_sizes(sizes=[])
#sizes = Sizes.find(sizes)
...
end
end
Can someone help me with that ? Trying to do the Rails 4 way rather than drop down to SQL, since I need the query to run on several DBS
Thanks
First of all you have to use single form of noun in belongs_to expression.
And for the query try this one:
Manufacturer.includes(:products).where(products: (size: "XL"))
I use "includes" to avoid N+1 query. Otherwise it will send two queries: one for Manufacturers and one for products. Write back, if this one doesn't fit your need.
EDIT
BTW, if you want to use exactly joining, write joins instead of includes.
Everything is here:
http://guides.rubyonrails.org/active_record_querying.html#joining-tables
and here:
http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
After going through the docs for joins
this is what worked :
Manufacturer.joins(products: :sizes).where(sizes: {id:ids}).distinct
This Rails way returns the model correctly.
I'm adding quiz functionality to the twitter app from the Hartl tutorial and have these Models:
User is nearly the same as the tutorial:
class User < ActiveRecord::Base
has_many :followed_users, through: :relationships, source: :followed
has_many :takens, dependent: :destroy
has_many :questions, through: :takens
end
Taken is a table of Question ids to User ids:
class Taken < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
nothing interesting in Question:
class Question < ActiveRecord::Base
attr_accessible :category, :correct, :option1, :option2, :option3, :qn
end
I want to be able to show followed_users and followers in order of the number of tests they have taken. In the console this can be had through:
User.find_by_id(1).question_ids.count
Then I can do something like:
User.find_by_id(1).followers.first.question_ids.count
in the console to get the count for a single follower.
I feel like I'm almost there.
How do I sort the followers and followed_users through their 'takens' count? (I was also looking at cache_count, which at first seemed promising, but might not be what I need...)
Ruby on Rails does not provide an object oriented mechanism to perform this; you have to write the SQL yourself. In your case, I'd say that the following line SHOULD work:
User.find_by_sql("SELECT users.*, COUNT(questions.id)
AS c FROM users, questions WHERE questions.user_id = users.id
GROUP BY users.id ORDER BY c DESC")
I don't have the actual tables in front of me, so I can't be sure that this is actual valid SQL, but hopefully it should work.
EDIT: There were a few syntax errors with my SQL but they've been fixed. Note that I'm assuming that your tables are called users and questions. They may differ for you.
I have a very standard app backed by an SQL database with a User model, a Problem model, and a CompletedProblem model acting as a join table between the two.
I'm trying to create a method that returns all problems not solved by a particular user. I have run into a wall, however, and I would appreciate pointers on what my method should look like.
Below are the models as well as my latest (incorrect) pass at creating this method.
class User < ActiveRecord::Base
has_many :completed_problems
has_many :problems, :through => :completed_problems
def unsolved_problems
Problem.includes({:wall => :gym}, :completed_problems).
where('completed_problems.user_id != ? OR completed_problems.user_id IS NULL)', self.id)
end
end
class Problem < ActiveRecord::Base
has_many :completed_problems
has_many :users, :through => :completed_problems
end
class CompletedProblem < ActiveRecord::Base
belongs_to :user
belongs_to :problem
end
(For the curious: this method does work so long as there is only one user marking problems as solved. As soon as you add a second, each user starts to return only those problems that have been solved by other users, instead of those not solved by herself.)
Via a friend:
select * from problems where id not in (select problem_id from completed_problems where user_id = USER_ID))
Although I'd still be interested in hearing if there's a way in ActiveRecord to do this.
I think something like this will do it:
Problem.where(["id NOT IN (?)", self.problems.all.map(&:id)])