So I have a query that looks like this:
merge_groups_with_mems_and_fps = PersonMergeGroup.joins(:members)
.where('merge_group_members.member_id IN (?)', member_ids)
.includes(:members, :field_preferences)
And the class of the association:
class FieldPreference < ActiveRecord::Base
belongs_to :merge_group
end
Now, when I say something like
merge_groups_with_mems_and_fps.first.field_preferences[0].merge_group
The result is a new query.
What's a good way to make sure when I call on a field_preference, and want its merge_group, I only look in merge_groups_with_mems_and_fps and don't make a new query? Thank you very much!
I think you need to hint to Rails about this association:
class FieldPreference < ActiveRecord::Base
belongs_to :merge_group, inverse_of: :field_preference
end
Check out the docs. Also, related SO question.
You're trying to call the merge_group association without including it in your original query. Unless you add it to the include section, you'll generate a new query every time you reference merge_group on any element in the field_preferences collection. You probably want something that looks like this:
merge_groups_with_mems_and_fps = PersonMergeGroup.joins(:members)
.where(merge_group_members: member_ids)
.includes(:members, field_preferences: { :merge_group })
PS: ActiveRecord will generate IN queries for you, so you can specify those conditions as hash parameters for your where query.
Related
Rails 5, ActiveRecord on PostgreSQL database. Have class with a previous_id column, like so:
class Event < ApplicationRecord
belongs_to :previous, class_name: 'Event'
end
I would like to get all Events that have no other Events referencing them as a "previous" Event. How can I make a query to do this?
I can obviously do something like:
Event.where.not(id: Event.pluck(:previous_id))
But my sense is that there is a more performant way to achieve this.
Building off of #Craig Ringer's comment with some ruby code that will produce his recommended SQL, you can do something like this
Event.joins("left join events referencing on referencing.previous_id = events.id")
.where("referencing.id is null")
I've not been able to figure this one out -- perhaps I've missed something in the docs. I want to get all of the articles that are associated with published issues. (That is, article.issue.is_published = true.)
I have two models:
# Article model
class Article < ActiveRecord::Base
belongs_to :issue
...
end
# Issue model
class Issue < ActiveRecord::Base
has_many :articles
...
end
From what I understand, I can run something like this:
Article.includes(:issues)
.where('issue.is_published = true')
.references(:issues)
But I get nothing but funky business on the other end. All of the examples I've found have one-to-many relationships going the other way - I assumed that I've gotten something wrong with the naming convention, but no combination of "issue" and "issues" seems to work any better.
What am I missing here?
You'll want to do a joins instead of includes here. This translates to a SQL inner join. Article.joins(:issue).where(issues: {is_published: true})
The question below had a good answer to grab associated values of an activerecord collection in one hit using Comment.includes(:user). What about when you have multiple associations that you want to grab in one go?
Rails have activerecord grab all needed associations in one go?
Is the best way to just chain these together like below Customer.includes(:user).includes(:sales).includes(:prices) or is there a cleaner way.
Furthermore, when I am doing this on a loop on an index table. Can I add a method on the customer.rb model so that I can call #customers.table_includes etc and have
def table_includes
self.includes(:user).includes(:sales).includes(:prices)
end
For the record I tested the above and it didn't work because its a method on a collection (yet to figure out how to do this).
In answering this, I'm assuming that user, sales, and prices are all associations off of Customer.
Instead of chaining, you can do something like this:
Customer.includes(:user, :sales, :prices)
In terms of creating an abstraction for this, you do have a couple options.
First, you could create a scope:
class Customer < ActiveRecord::Base
scope :table_includes, -> { includes(:user, :sales, :prices) }
end
Or if you want for it to be a method, you should consider making it a class-level method instead of an instance-level one:
def self.table_includes
self.includes(:user, :sales, :prices)
end
I would consider the purpose of creating this abstraction though. A very generic name like table_includes will likely not be very friendly over the long term.
Is there a way to use a filter criterion in where, which is not a DB column. If I have a Movie model with the following method:
def blockbuster?
imdb_rating > 8
end
is there a way to do something like Movie.where(:blockbuster? => true). I know that in this particular example it's possible to just use the imdb_rating attribute (Movie.where('imdb_rating > ?', 8)), but there are cases, when a method does a more complex logic. Currently, if I want to do this, I must call Movie.all.select(&:blockbuster?), but I want to do this at the DB level. Thank you.
P.S. I am sure that similar questions are asked many times, but I can't seem to think of the right keywords to find them here or on Google. Please, post a link if this is answered elsewhere.
Have you tried making it into a scope? There is some information on scopes in the Rails documentation.
Basically, with your method, you'd do something like:
class Movie < ActiveRecord::Base
scope :blockbuster, -> { where('imdb_rating > ?', 8) }
end
Movie.blockbuster # returns all relevant objects as an ActiveRecord relation
Class methods are also available as scopes:
class Movie < ActiveRecord::Base
def self.blockbuster?
where('imdb_rating ?', 8)
end
end
Movie.blockbuster? # also returns all relevant objects as an ActiveRecord relation
iOS developer learning Rails here. Trying to query active record for records based on a has_many relation's property. Apologies if this is simple but I just can't figure it out. I've read about and have been trying to use scope, .where, .joins, but there are so many contradicting posts and blogs online I'm unsure which to use and what's correct...
On to the problem:
I have two ActiveRecord models:
class User < ActiveRecord::Base
has_many :items
end
and
class Item < ActiveRecord::Base
belongs_to :user
end
An item has a property title, I am trying to find all of the Users that have an item with a title that is similar to some search parameter in string format.
I have managed to do such using a search for items and then .map like this:
users_owning_item_in_search_parameter = Item.where{ (title =~ my{#search_param + "%"}) }.map! { |i| i.user }
(that syntax comes from the squeel gem.)
But that command returns an Array when I want an ActiveRecord::Relation, because I need to do some further filtering that requires this instance type.
Any help much appreciated.
I think you're looking for something like this:
User.joins(:items).where('items.title LIKE ?', "#{#search_param}%")
You'll have to modify it a bit if you want to take advantage of squeel.