0

I tried a search, but wasn't able to find anything. Mind you, I may have been searching the wrong thing.

So, my question is with regard to join tables in Rails.

I plan to have Users and Books and a join table Favourites that would link Users to Books.

So, my initial thought is that the Favourites table would have user_id and book_id.

However, I want to also provide suggestions. So, if user1 likes books 1,2,3,4 and user2 likes books 1,2,3,4,5; I want to be able to suggest book 5 to user1.

I am thinking that having a table with user_id and then an array containing their favourite books would be easiest for figuring out appropriate suggestions.

So, my question is two fold. First, do I need two tables? One join table and another for the table with array? Or can/should those two be the same? Second, is this the best way to set all this up? I am self-taught, so I very well could be missing something very basic..

The help is much appreciated!

3 Answers 3

3

So, I am not sure where and how do you want to show the suggestions, but lets say it like this:

I am assuming you made the User, Book and Favorite class like this:

Class User < ActiveRecord::Base
   has_many :favorites
   has_many :books, :through => :favorites
end

Class Book < ActiveRecord::Base
   has_many :favorites
   has_many :users, :through => :favorites
end

Class Favorite < ActiveRecord::Base
   belongs_to :user
   belongs_to :book
end

Lets say that every User has his profile page (show action), and every time some user goes to a profile page of another user, you want the suggestion to be shown.

You wouldn't have to make any table for suggestions, just a few methods to calculate the suggestions and show it to the user.

Let's say that that to suggest a book you would need to have at least three books that you favorite with the other user.

in your User class:

def suggest_books_from?(user)
     true if self.books & user.books > 3
end

That would make a intersect to see if you are compatible with the other user. If you are compatible, e.g. the method returns true, than you would have to calculate which books to suggest to him, so a call would be something like this:

if current_user.suggest_books_from?(user)
     user.books - current_user.books
end

and that method should return you the array that contains all the books that the user has favorited, but the current user hasn't favorited

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

2 Comments

Oh! I just saw this! I will take a look. Maybe this is easier for me to implement than a gem.
I think this is a really easy way to do it. If i didn't do something correctly just google the intersect and - method on arrays and you will easily find a solution. Cheers :)
2

To answer your first question: you're looking for a single, standard join table. Including another table (or another column) with a different representation of the same information will prove difficult for you to keep consistent and probably won't help you as much as you think.

Reason being the answer to question two: there are a lot of really great recommendation engines out here that will do all this work for you!

The biggest one is recommendify but it hasn't been active for about a year. I used it in a project and found it very satisfying: it's fast and the results, in my experience, seem to be accurate.

Recommendable is much more recently updated but also works more on upvotes and downvotes. Still, you can treat a "favorite" of a product as an upvote and probably use it like that if you wanted to.

If neither of those fit your needs, you can check out RubyToolbox's list of recommendation engines.

3 Comments

Thanks for such a quick reply! I will check those out. I just need something really simple for now. I knew I probably wasn't searching the right thing.. Thanks again, much appreciated!
Haha, before i started to write such a long answer i didn't think there was a gem for something like that. Talk about reinventing the wheel :)
You and me both @Zippie. I have my "recommendation engine" all drawn out on my notepad, haha.
0

A simple way to do this would be to just use the join model you've created (Favourite) to get that array of ids. In the long run it may not be performant, but given the early state of the app, I would keep it simple for now and deal with performance later.

So, in that case, if you have something like this:

class User < ActiveRecord::Base
  has_many :favorites
  has_many :books, :through => :favorites
end

class Book < ActiveRecord::Base
end

class Favourite < ActiveRecord::Base
  belongs_to :user
  belongs_to :book
end

Then you could get the book ids for a user like so:

user = User.first
user.book_ids

I can't speak to recommending books, but to see which books two users don't have in common:

frank = User.first
joe = User.last
frank.book_ids - joe.book_ids # IDs for books Frank has but Joe doesn't
joe.book_ids - frank.book_ids # IDs for books Joe has but Frank doesn't

1 Comment

Thanks Sean! Yes, I am definitely going for ease of execution over optimal performance initially. Just looking for proof of concept. I will have a chance after my classes to check this out. Thanks so much!

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.