Trouble with Rails has_many relationships - ruby-on-rails

I'm writing an app where a user can both create their own pages for people to post on, and follow posts on pages that users have created. Here is what my model relationships look like at the moment...
class User < ActiveRecord::Base
has_many :pages
has_many :posts
has_many :followings
has_many :pages, :through => :followings, :source => :user
class Page < ActiveRecord::Base
has_many :posts
belongs_to :user
has_many :followings
has_many :users, :through => :followings
class Following < ActiveRecord::Base
belongs_to :user
belongs_to :page
class Post < ActiveRecord::Base
belongs_to :page
belongs_to :user
The trouble happens when I try to work my way down through the relationships in order to create a homepage of pages (and corresponding posts) a given user is following (similar to the way Twitter's user homepage works when you login - a page that provides you a consolidated view of all the latest posts from the pages you are following)...
I get a "method not found" error when I try to call followings.pages. Ideally, I'd like to be able to call User.pages in a way that gets me the pages a user is following, rather than the pages they have created.
I'm a programming and Rails newb, so any help would be much appreciated! I tried to search through as much of this site as possible before posting this question (along with numerous Google searches), but nothing seemed as specific as my problem...

You have defined the pages association twice. Change your User class as follows:
class User < ActiveRecord::Base
has_many :pages
has_many :posts
has_many :followings
has_many :followed_pages, :class_name => "Page",
:through => :followings, :source => :user
end
Now let's test the association:
user.pages # returns the pages created by the user
user.followed_pages # returns the pages followed by the user

tried following.page instead of followings.pages ?

As to your ideal, a simplified user model should suffice (:source should be inferred):
class User < ActiveRecord::Base
has_many :pages
has_many :posts
has_many :followings
has_many :followed_pages, :class_name => "Page", :through => :followings
end class
Now, using the many-to-many association :followings, a_user.followed_pages should yield a collection of pages.

Related

Creating a follow/unfollow relationship from scratch between two models in Rails

Right now I'm trying to create a one-sided follow/unfollow relationship where a user can follow/unfollow a celebrity. Despite the gems available I'd like to learn how to create this from scratch.
The posts I've found online seem to only incorporate a self-referential style where a model instance can only follow one of its kind (a user can only follow other users). As a starting point point I've used this post for the initial setup. I'm just not sure how to re-configure the associations for models:
class User < ActiveRecord::Base
end
class Following < ActiveRecord::Base
end
class Celebrity < ActiveRecord::Base
end
You are looking for a "many to many" relationship. You can find more detailed information about this relation here. With your models as examples it would look like this:
class User < ActiveRecord::Base
has_many :followings, :dependent => :destroy
has_many :celebrities, :through => :following
end
class Following < ActiveRecord::Base
belongs_to :user
belongs_to :celebrity
end
class Celebrity < ActiveRecord::Base
has_many :followings, :dependent => :destroy
has_many :users, :through => :following
end

Source Reflection Errors with has_many :through

I'm attempting to create a system where my site's users can favorites pages. Those pages have two types, either clubs or sports. So, I have four models, associated as such:
User Model:
class User < ActiveRecord::Base
..
has_many :favorites
has_many :sports, :through => :favorites
has_many :clubs, :through => :favorites
..
end
Favorites Model:
class Favorite < ActiveRecord::Base
..
belongs_to :user
belongs_to :favoritable, :polymorphic => true
end
Club Model:
class Club < ActiveRecord::Base
..
has_many :favorites, :as => :favoritable
has_many :users, :through => :favorites
def to_param
slug
end
end
Sport Model:
class Sport < ActiveRecord::Base
..
def to_param
slug
end
..
has_many :favorites, :as => :favoritable
has_many :users, :through => :favorites
..
end
Essentially, the User has_many sports or clubs through favorites, and the association between favorites, sports, and clubs is polymorphic.
In practice, this is all working exactly the way I want it to, and the whole system I have designed works. However, I'm using Rails_Admin on my site, and I get an error in three places:
When loading the Dashboard (/admin) the first time. If I refresh the page, it works fine.
When loading the User model in Rails_Admin
When loading the Favorites model in Rails_Admin
Here is the error message on /admin/user (gist). All of the errors are similar, referencing ActiveRecord::Reflection::ThroughReflection#foreign_key delegated to source_reflection.foreign_key, but source_reflection is nil:.
Can anyone point me in the right direction so that I can fix this? I've searched all over, and asked other programmers/professionals, but no one could spot the error in my models. Thanks so much!
Alright, well, I finally worked this out, and figured that I'd post the fix just in case it helps someone else out in the future (no one likes finding someone else with the same problem and no posted answer).
As it turns out, with a polymorphic has_many :through, there is a little more configuration needed. My User model should have looked like this:
class User < ActiveRecord::Base
..
has_many :favorites
has_many :sports, :through => :favorites, :source => :favoritable, :source_type => "Sport"
has_many :clubs, :through => :favorites, :source => :favoritable, :source_type => "Club"
..
end
This answer to another question about polymorphic has_many :through associations is what helped me figure this out.
I encountered this error when the code included a has_many for an association that doesn't exist (mid-refactor). So it can also be caused by some general has_many misconfigure. The Ruby/Rails code never cares because the dynamic style of Ruby means the association is only called on demand. But Rails-Admin exhaustively inspects properties, leading to reflection problems.

Like/Dislike style Voting Database in Rails

I’m creating a voting feature for our website in the style of YouTube “Likes” and “Dislikes” and Digg using Ruby on Rails 3. I have having trouble coming up with the right scheme.
I have three models, Users, Topics, and Votes. Each User will make one vote “Like” or “Dislike” for one Topic. Like these sites, Users can Vote on a Topic, but they can also create new Topics. I’d like to be able to not only view all of a User’s Votes, but also both the Topics they have created and the Topics they have voted on. I am trying to build this on our own and decide how best to setup the database to handle this process.
My first idea was to use :has_many and belongs_to exclusively like so…
class User < ActiveRecord::Base
has_many :votes
has_many :topics
class Topic < ActiveRecord::Base
has_many :votes
belongs_to :users
class Vote < ActiveRecord::Base
belongs_to :topics
belongs_to :users
boolean choice #tracks whether the User chooses Like or Dislike
But it became evident that this might not be the best way to do this. I began to think the best method would be to use a :has_many :through association like...
class User < ActiveRecord::Base
has_many :votes, :through => :topics
But I’m not sure. Any ideas on how best to set something like this up?
I think your initial setup is good but it can be further improved upon to better support what you want to accomplish. Perhaps like this:
class User < ActiveRecord::Base
has_many :votes
has_many :topics
#Lists all topics the user has voted on
has_many :voted_topics, :through => :votes, :source => :topic
#Lists all votes for the users topics
has_many :topic_votes, :through => :topics, :source => :votes
end
class Topic < ActiveRecord::Base
has_many :votes
belongs_to :user
end
class Vote < ActiveRecord::Base
belongs_to :topic
belongs_to :user
end

Rails: Multiple "has_many through" for the two same models?

Can't wrap my head around this...
class User < ActiveRecord::Base
has_many :fantasies, :through => :fantasizings
has_many :fantasizings, :dependent => :destroy
end
class Fantasy < ActiveRecord::Base
has_many :users, :through => :fantasizings
has_many :fantasizings, :dependent => :destroy
end
class Fantasizing < ActiveRecord::Base
belongs_to :user
belongs_to :fantasy
end
... which works fine for my primary relationship, in that a User can have many Fantasies, and that a Fantasy can belong to many Users.
However, I need to add another relationship for liking (as in, a User "likes" a Fantasy rather than "has" it... think of Facebook and how you can "like" a wall-post, even though it doesn't "belong" to you... in fact, the Facebook example is almost exactly what I'm aiming for).
I gathered that I should make another association, but I'm kinda confused as to how I might use it, or if this is even the right approach. I started by adding the following:
class Fantasy < ActiveRecord::Base
...
has_many :users, :through => :approvals
has_many :approvals, :dependent => :destroy
end
class User < ActiveRecord::Base
...
has_many :fantasies, :through => :approvals
has_many :approvals, :dependent => :destroy
end
class Approval < ActiveRecord::Base
belongs_to :user
belongs_to :fantasy
end
... but how do I create the association through Approval rather than through Fantasizing?
If someone could set me straight on this, I'd be much obliged!
Keep your first set of code, then in your User Model add:
has_many :approved_fantasies, :through => :fantasizings, :source => :fantasy, :conditions => "fantasizings.is_approved = 1"
In your Fantasizing table, add an is_approved boolean field.

how to specify multiple relationships between models in rails using ActiveRecord associations

Say there're two models : User and Post, i want to keep track of who has read which post, and who writes which post, which user favorites which posts etc. Then i come up with the following solution:
class User < ActiveRecord::Base
has_many :writings
has_many :posts, :through => :writings
has_many :readings
has_many :posts, :through => :readings
#..
end
class Post < ActiveRecord::Base
has_many :writings
has_many :posts, :through => :writings
#...
end
and setting up the intermediate models - Writing, Reading. this works, but finally i find out that when i writing this
#user.posts #...
the returned array contains housekeeping information both for writings and readings. How can i solve this problem.
You want something like this:
class User < ActiveRecord::Base
has_many :writings
has_many :posts, :through => :writings
has_many :readings
has_many :read_posts, :through => :readings, :class_name => "Post"
#..
end
By giving the association name something other than just :posts you can refer to each one individually. Now...
#user.posts # => posts that a user has written via writings
#user.read_posts # => posts that a user has read via readings

Resources