how to reject from an AR association where a specific condition exists - ruby-on-rails

I'd like to remove items from the following association (where a site_placement has a native_ad_placement.ad_type == "video") and have the following code but this doesn't seem to work
# not an array but an association
#sites.each do |site|
site.site_placements.reject { |sp| (sp.native_ad_placement.ad_type == "video") }
end
How could I achieve this? I'm using Rails 3.2.

You should use .reject! instead of .reject.
But really, you shouldn't use reject at all. If I am not wrong, you can totally achieve the same thing at querying level, and it is even much more effective. Something like below:
Site.includes(site_placements: [: native_ad_placement]).where.not(native_ad_placements: { ad_type: "video" })

Related

Rails get value from hash based on table name

I think the best way for me to explain this question is with example. Here is a simple method with a hash:
def getValues(table)
allColumns = {
'User' => ['first_name', 'last_name'],
'Vehicle' => ['make', 'model', 'id'],
}
end
I am trying to pass in the table and based on that table return a range of values. I would like to know what would be (performance-wise) the best way to accomplish this. Is it using a switch statement, if/else, some sort of loop? If you come up with an answer, please be as kind to include an example so that I may understand better.
I suggest you to rename the parameter first, maybe to table_name or something more descriptive.
Second it is kind of a convention in ruby to use method names separated by _, and avoid using camelCase as another languages.
Third, i would put the list on a constant variable or something, and just reference it inside the method.
Then you can look up the values of some hash based on a key just by using hash[key].
LIST = {
'User' => ['first_name', 'last_name'],
'Vehicle' => ['make', 'model', 'id'],
}
def get_values(table_name)
LIST[table_name]
end
Hash lookup by key is probably one of the most performant operations you could do with a collection, so there is no need to worry about it.

Find Record based on the associated attributes

I am trying to find a record based on two associated attributes. The Record should be selected, if its association contains those two records.
So far, I tried following - Which seemed to me a very bad practice and I want to avoid using it.
#size = Spree::OptionValue.find(params[:size])
#color = Spree::OptionValue.find(params[:color])
vari = Spree::Variant.all
vari.each do |va|
if va.option_values.include?(#size && #color)
#variant = va
end
end
So far, I also tried
#variant = Spree::Variant.all(:include => :option_values, :conditions => ['option_value.id = ?', params[:color])
This seems to be the way to go, but I can't seem to figure out the right way to get the result.
The return error I keep on getting is following:
ActiveRecord::StatementInvalid: PG::Error: ERROR: missing FROM-clause entry for table "option_values"
LINE 1: ..._option_values_variants"."option_value_id" WHERE (option_val...
EDIT:
I got it working due to the great help given in the accepted answer:
Spree::Variant.joins(:option_values).where("spree_option_values.id in (?)", [size, color])
First off, your code is probably broken. I doubt that .include?(#size && #color) does what you think it does; you're effectively only checking if option_values includes #color. This is equivalent to doing (true && #color). If you want to include both values, you need .include?(#size) && .include?(#color).
So your code should probably look like this:
vari = Spree::Variant.all
vari.each do |va|
if va.option_values.include?(#size) && va.option_values.include?(#color)
#variant = va
end
end
Next, you can make your code much more Ruby-esque:
#variant = Spree::Variant.all.select do |v|
v.option_values.include?(#size) && v.option_values.include?(#color)
end
But it's far better to actually evaluate the condition at the database level rather than load the entire table into your application. You seem to be looking for all records where the associated OptionValues includes the two you've selected into #size and #color.
The query you're looking for probably looks something like this:
Spree::Variant.joins(:option_values).where("option_values.id in (?)", [#size, #color])

Rail3 'Return False Unless XYZ' Query Not Working

In my rails3.1 application, I'm trying to apply the following logic in one of my order model.
def digital?
line_items.map { |line_item| return false unless line_item.variant_id = '102586070' }
end
I've created a separate variant called prepaid_voucher which has id = 102586070. Despite this, the result is false...
Order has many line_items
LineItem belongs to order and variant
Variant has many line_items
Is this the best way to perform such a task and how can I fix?
First of all I think you want a double == here line_item.variant_id = '102586070', then I rather go for something like that (If I understand what you want)
def digital?
line_items.select{|line_item| line_item.variant_id == '102586070'}.any?
end
But it's hard to understand what you really want, what is the expected behavior if the id is not found?

Specify fields to be returned with find_each?

We currently have this batched code using MongoMapper which is still taking longer than we would like:
User.find_each(conditions: {is_active: true}, batch_size: 500) do |user|
# simple stuff that only requires a couple fields from user
end
Is there some way to tell it to only return the fields we need from the User model like you can do with a non-batched find?
User.where(is_active:true).fields(:field1, :field2).all
Changing the batch size hasn't helped so we're looking for other ideas.
Thanks!
try
User.where(is_active:true).select("field1, field2").find_each { |user| p user }
MongoMapper's fields filter should work fine with find_each. But, when used at the end of a query chain, find_each returns an enumerator rather than calling the block, so you have to add an extra .each:
User.where(is_active:true).fields(:field1, :field2).find_each.each { |user| ...}
Source: plucky/lib/plucky/query.rb:54
Versus: mongomapper/lib/mongo_mapper/plugins/querying:13

Rails scope with HABTM relationship count

I have an Event class with a HABTM relationship with a User class. I'm trying to create a Event scope that includes only Events that have 2 Users associated with it.
I currently have a Event#status method that returns the following:
def status
self.users.length == 2 ? "matched" : "not matched"
end
So now basically I'm trying to find how to write a scope that includes all "matched" events. I tried scope :matched, self.users.length == 2, which didn't work at all, but is there a similar way that I'm missing?
EDIT: This class method does this correctly, but it'd still be nice if I could encapsulate it in a scope.
def self.pending
Event.all.map { |e| e if e.status == "matched" }
end
You've got a few problems here. Right now, your status method is returning literal strings, which is a bit surprising -- it would be more common to have this return a Boolean value. Also, the name status is not descriptive -- perhaps exactly_two_users? would be better. In addition, if you use users.count instead of users.length, then the DB will do the count more efficiently.
Your scope could simply be where(:users.count => 2), I believe.

Resources