Search code examples
arraysruby-on-rails-4conditional-statementsrecommendation-enginepredictor-ruby-gem

How to exclude an array of id's from a find-method?


I'm calling an array of recommended products (based on the predictor-gem) and want to exclude the products of the current_user from that set. I think that I'm using the proper condition for it (" != ?") but just not in the correct way. @products_rec should give that final array.

Here's the specific code in my product_controller.rb:

    recommender = ProductRecommender.new

    products = current_user.products

    @product_rec = (recommender.similarities_for("product-#{@product.id}")).map {|el| el.gsub(/(.*\-)[^\d]*/, "")}
    @products_rec = Product.find(@product_rec, :conditions => ["id != ?", products.id])

and here's my model, product.rb:

class Product < ActiveRecord::Base

  include Reviewing
  include PublicActivity::Model
tracked

extend FriendlyId
friendly_id :name, use: [:slugged, :finders]

belongs_to :category

belongs_to :benefit

has_many :subscriptions
has_many :users, through: :subscriptions

has_many :benefits
has_many :projects, through: :benefits

belongs_to :user

validates :name, presence: true, length: { maximum: 200 }
validates :gtin, presence: false
validates :content, presence: false, length: { maximum: 2000 }
validates :video, presence: false
validates :tag, presence: false
validates :project, presence: false
validates :category, presence: false
validates :user, presence: false

has_attached_file :image, :styles => { :medium => "680x300>", :thumb => "170x75>" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/

end

I want to exclude the products from the current_user, based on the users through subscriptions (see model).

How can I get this to work, any ideas?

Final code: Based on the answer of @Humza, I've added the following working code to my product_controller.rb:

    recommender = ProductRecommender.new

    products = current_user.products.select("id")

    @product_rec = (recommender.similarities_for("product-#{@product.id}")).map {|el| el.gsub(/(.*\-)[^\d]*/, "")}
    @products_rec_array = Product.find(@product_rec)
    @products_rec = Product.where(id: @products_rec_array).where.not(id: products)

Solution

  • To find products with id not in array, you must do this:

    array = current_user.products.pluck(:id)
    Product.where('id NOT IN (?)', array) # '?' is surrounded by paranthesis
    

    But since a product belongs to a user, you can simply do

    Product.where('user_id != ?', current_user.id)
    

    You can also use the not method like so:

    Product.where.not(id: array)
    Product.where.not(user_id: current_user.id)
    

    Edit:

    If you want the base products to be from some other list, this can help:

    base_product_ids = some_list.map(&:id) # assuming this is an Array
    Product.where(id: base_product_ids).where.not(user_id: current_user.id)
    

    If some_list was an ActiveRecord::Relation, you could have simply done:

    some_list.where.not(user_id: current_user.id)