5

I am attempting to track mutual likes where a user likes a user that likes them. To check if the like is mutual, I call an method after the like is created. If that liker has been a likee than it is considered mutual.

The problem however, is that I run into some odd errors that I believe are related to how the foreign keys have been set up. I have set up a has many association in Rails but any time I attempt to access it, I get a PG::InFailedSqlTransaction: ERROR: current transaction is aborted, commands ignored until end of transaction block : RELEASE SAVEPOINT active_record_1 error.

User:

class User < ApplicationRecord
  has_many :likes
end

Like:

class Like < ApplicationRecord
  belongs_to :likee, class_name: 'User', foreign_key: 'likee_id'
  belongs_to :liker, class_name: 'User', foreign_key: 'liker_id'
  belongs_to :connection, optional: true

  after_save :mutual_like?

  private

  def mutual_like?

    if liker.likes.where(likee: liker)
      # fails
    end
  end
end

I've tried changing the hook to be around save, etc. but that doesn't work either.

Also, I cannot even call Like.first else I get the same error.

I've tried printing out liker.likes.where(likee: liker) and i get PG::UndefinedColumn: ERROR: column likes.user_id does not exist which I think is the problem.

I can however, access the liker like this: self.likee inside of the hook but I cannot call self.likee.likes without it returning #<Like::ActiveRecord_Associations_CollectionProxy:0x3fd91ca5ca78>

Schema:

  create_table "likes", force: :cascade do |t|
    t.integer  "liker_id",      null: false
    t.integer  "likee_id",      null: false
    t.integer  "connection_id"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.index ["likee_id"], name: "index_likes_on_likee_id", using: :btree
    t.index ["liker_id"], name: "index_likes_on_liker_id", using: :btree
  end





create_table "users", force: :cascade do |t|
    t.string   "email"
    t.string   "username"
    t.string   "password_digest"
    t.boolean  "admin",                default: false
    t.index ["email"], name: "index_users_on_email", using: :btree
    t.index ["username"], name: "index_users_on_username", using: :btree
  end

Tests:

RSpec.describe Like, type: :model do
  let(:liker) { Fabricate(:user) }
  let(:likee) { Fabricate(:user) }
  let(:like) { Fabricate(:like, liker: liker, likee: likee) }
  let(:pending_like) { Fabricate.build(:like, liker: liker, likee: likee)}

  context 'relations' do
    it { should belong_to :likee }
    it { should belong_to :liker }

    describe 'liking another user' do

      it '#liker references first user' do
        expect(like.likee).to eq likee
      end

      it '#likee references second user' do
        expect(like.liker).to eq liker
      end

    end
  end
  ...

RSpec.describe User, type: :model do
  context 'relations' do
    it { should have_many :likes }
  end
 ...

Is this caused because I'm attempting to lookup a record that is being saved?

5
  • Can you post the relevant parts of your schema for these two tables. Commented Oct 8, 2016 at 5:08
  • I posted the relevant info on the users and likes tables Commented Oct 8, 2016 at 5:12
  • Does liker.user.likes work? Commented Oct 8, 2016 at 5:17
  • no NoMethodError: undefined method user'`. Weird thing is I have tests that validate the relationship that are passing Commented Oct 8, 2016 at 5:19
  • If I do self.likee.likes I get #<Like::ActiveRecord_Associations_CollectionProxy:0x3feaa56865bc> which cannot be converted to a plain model instance/array Commented Oct 8, 2016 at 5:20

1 Answer 1

2

liker.likes.where(likee: liker) returns only a relation. You have to execute your query like this liker.likes.where(likee: liker).exists?

has_many :likes within your User model expects a column user_id within your table likes. With the code given I would think you have to change it to

class User < ApplicationRecord
  has_many :other_likes, foreign_key: :liker_id 
  has_many :likes, foreign_key: :likee_id 
end

belongs_to :connection is a bad name in my point of view. ActiveRecord::Base has a class method with the same name. Maybe you will run into issues with such an association name some day.

Sign up to request clarification or add additional context in comments.

2 Comments

I think this is right - I'm now getting a relation. Just so I understand, the problem was that the user side of my relationship did not reference the right column? Thanks and good point about connection being used internally, I didn't know that.
Yes, your user side didn't reference the right column. The issue with liker.likes.where(likee: liker) was secondary. Your if statement would be true in every case when you don't append .exists?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.