J. Haselden J. Haselden - 1 year ago 62
Ruby Question

Ruby on Rails: Select model that user has not interacted with

I'm very new at Ruby on Rails, but I've spent all day on this trying all different solutions I found online and I've still got nothing.

I have three models: users, tracks, and feeds.

Users is pretty self explanatory,
Tracks are songs that users can upload,
and Feeds are feedbacks that Users leave on each others Tracks

I have:

class User < ActiveRecord::Base
has_many :tracks, dependent: :destroy
has_many :feeds

class Track < ActiveRecord::Base
belongs_to :user
has_many :feeds, dependent: :destroy

class Feed < ActiveRecord::Base
belongs_to :track
has_one :user

I need to select the tracks that a user hasn't already left feedback on. I tried:

Track.joins(:feeds).where("feeds.user_id != #{current_user.id}").where("tracks.user_id != #{current_user.id}")

but that didn't produce anything.

Anybody help?

Extra info if needed:

=> ["id", "email", "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "created_at", "updated_at", "genre", "name", "genre_id", "slug"]

=> ["id", "title", "link", "user_id", "created_at", "updated_at", "slug", "average_feed", "feed_avaliable", "feed_level", "pref_genre", "last_feed"]

=> ["id", "feedback", "user_id", "track_id", "created_at", "updated_at", "overall", "feed_for"]

class PageController < ApplicationController

def feed
@track = Track.joins(:feeds).where("feeds.user_id != #{current_user.id}").where("tracks.feed_avaliable > '0'").where("tracks.user_id != #{current_user.id}").reorder(feed_level: :asc, last_feed: :desc, created_at: :asc).first()
@feed = current_user.feeds.build if user_signed_in?

Answer Source

First, as Muhammad correctly pointed out, Feed should belongs_to User, not has_one.

class Feed < ActiveRecord::Base
  belongs_to :track
  belongs_to :user

This example uses the where.not feature introduced in Rails 4.

Track.where.not(id: current_user.feeds.select(:track_id))

Let's say your user has an id of 42. This should generate

SELECT tracks.* FROM tracks WHERE tracks.id NOT IN (
  SELECT feeds.track_id FROM feeds WHERE feeds.user_id = 42 

You generally want to avoid string-interpolation in SQL queries at all costs. There are a couple ways to do it safely, but in this case you can just use the ruby interface.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download