Reputation: 2807
I'm trying to list all the user's products with a probable association where a flag 'notification' is set to zero.
user.probable_associations.where(:notified => 0).collect{|a| Product.where(:id => a.product_id).collect{|p| p.name}}.to_sentence
It seems like using a where and collect method twice within the statement isn't very good. Is there a better way to go about this?
Also, the result is something like
"[\"Product A\"] and [\"Product B\"]"
which is pretty ugly...and I still need to remove the extra punctuation "[\" \"] instead of something clean like
"Product A and Product B"
EDIT based on Rich's Answer, still have issues because notified is a field in associations NOT product:
has_many :probable_associations, -> { where "associations.category = 3"}, class_name: 'Association', before_add: :set_probable_category
has_many :probable_products, class_name: 'Product', through: :probable_associations, source: :product do
def not_notified
select(:name).where(notified: 0)
end
end
Upvotes: 0
Views: 58
Reputation: 12402
Assuming that probable_associations
is just an ActiveRecord has_many
association, and that you want to end up with a list of titles for Product
records, you can use this:
ids = user.probable_associations
.where(notified: 0)
.pluck(:product_id)
result = Product.where(id: ids).pluck(:name).to_sentence
It's similar to @spikermann's answer, but pluck(:column_name)
is faster than using a block and only extracts the required column from the DB.
Also, the reason your code produces that string is that, by the time you call to_sentence
, you have an Array
of sub-arrays. Each sub-array contains a single element: a product name.
That's because the second collect
is sent to an ActiveRecord::Relation
containing just one record.
You could have solved that problem with flatten
, but the whole operation could just be refactored.
Upvotes: 0
Reputation: 106802
Without knowing what probable_associations
does would I rewrite the code to something like this:
product_ids = user.probable_associations.where(:notified => 0).map(&:product_id)
Product.where(:id => product_ids).map(&:name).to_sentence
Upvotes: 0
Reputation: 76774
I'd use an ActiveRecord Association extension:
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :products do
def not_notified
select(:name).where(notified: 0)
end
end
end
#-> @user.products.not_notified
That's my contribution, but you could then use @spickermann
& @tompave
's controbutions and use .flatten.to_sentence
Upvotes: 1