Godzilla74 Godzilla74 - 4 months ago 21
Ruby Question

Twitter like following in Rails

I'm following along with this tutorial to create Twitter like following in my app, however, my following isn't reciprocal, in fact, the other side doesn't follow a user at all. My two main models are

User
and
Stock
. A user should be able to 'follow' a stock, but a stock does not ever follow a user.


models/user.rb


class User < ActiveRecord::Base

has_many :stock_relationships
has_many :stocks, through: :stock_relationships, source: :user

devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook, :twitter, :linkedin, :google_oauth2]

# stock following/unfollowing
def follow_stock(stock)
stock_relationships.create(stock_id: stock.id)
end

def unfollow_stock(stock)
stock_relationships.find_by(stock_id: stock.id).destroy
end

def following_stock?(stock)
stock_relationships.include?(stock.id)
end

end


Since my
Stock
model doesn't really belong to anyone I don't have anything in that model yet:


models/stock.rb


class Stock < ActiveRecord::Base

end


To keep track of the
users
that are
following
stocks, I've created another model called
StockRelationships
:


models/stock_relationship.rb


class StockRelationship < ActiveRecord::Base
belongs_to :user
end


I'm starting off in console by assigning a user:

user = User.find(1)


I'm having trouble because this doesn't seem to be working when using the
following_stock?
method.

I can create a
stock_relationship
:

pry(main)> user.follow_stock(stock)
(0.2ms) BEGIN
SQL (2.2ms) INSERT INTO "stock_relationships" ("stock_id", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["stock_id", 2], ["user_id", 1], ["created_at", "2016-07-12 01:01:00.552580"], ["updated_at", "2016-07-12 01:01:00.552580"]]
(2.5ms) COMMIT
=> #<StockRelationship:0x007ff0b960ba60
id: 3,
user_id: 1,
stock_id: 2,
created_at: Tue, 12 Jul 2016 01:01:00 UTC +00:00,
updated_at: Tue, 12 Jul 2016 01:01:00 UTC +00:00>


and I can
unfollow
a stock:

[10] pry(main)> user.unfollow_stock(stock)
StockRelationship Load (0.4ms) SELECT "stock_relationships".* FROM "stock_relationships" WHERE "stock_relationships"."user_id" = $1 AND "stock_relationships"."stock_id" = $2 LIMIT 1 [["user_id", 1], ["stock_id", 2]]
(0.1ms) BEGIN
SQL (0.3ms) DELETE FROM "stock_relationships" WHERE "stock_relationships"."id" = $1 [["id", 3]]
(1.5ms) COMMIT
=> #<StockRelationship:0x007ff0b9d36a60
id: 3,
user_id: 1,
stock_id: 2,
created_at: Tue, 12 Jul 2016 01:01:00 UTC +00:00,
updated_at: Tue, 12 Jul 2016 01:01:00 UTC +00:00>


However, I'm running into problems when I'm checking to see if a user is actually
following
a stock:

[13] pry(main)> user.following_stock?(stock)
=> false


Which should be returning
true
since the user is in fact following the stock:

[15] pry(main)> StockRelationship.all
StockRelationship Load (0.4ms) SELECT "stock_relationships".* FROM "stock_relationships"
=> [#<StockRelationship:0x007ff0bfa00408
id: 2,
user_id: 1,
stock_id: 1,
created_at: Tue, 12 Jul 2016 00:32:55 UTC +00:00,
updated_at: Tue, 12 Jul 2016 00:32:55 UTC +00:00>,
#<StockRelationship:0x007ff0bfa002c8
id: 4,
user_id: 1,
stock_id: 2,
created_at: Tue, 12 Jul 2016 01:04:06 UTC +00:00,
updated_at: Tue, 12 Jul 2016 01:04:06 UTC +00:00>]


Am I implementing
include?
incorrectly? Have I messed up something in my models?

Thanks in advance!

Answer

Your error is a datatype comparison problem. Try this:

   def following_stock?(stock)
     # either use this
     stock_relationships.where(stock_id: stock.id).present?
     # OR
     stock_relationships.pluck(:stock_id).include?(stock.id)
   end