What's the rails way to include a field in a join model when listing an association? - ruby-on-rails-3

So if I have the following relationship
class Item < ActiveRecord::Base
has_many :item_user_relationships
has_many :users, :through => :item_user_relationships
end
class User < ActiveRecord::Base
has_many :item_user_relationships
has_many :items, :through => :item_user_relationships
end
class ItemUserRelationship < ActiveRecord::Base
belongs_to :item
belongs_to :user
attr_accessible :role
end
What's the rails way to include the role attribute when listing all the Users of an Item?
#users = #item.users # I want to include the role as part of a user
Thanks!
UPDATE: I'm still having trouble with this. My goal is to get an array of User models that have their role included in the attributes.

I'm note sure if I understand you correctly, but maybe this is what you want?
#users = #item.users
#users.each do |user|
puts user.item_user_relationships.first.role
end

Related

N + 1 Queries even with Eager loading in Rails 3.2

I have a has_many through, through relationship that needs to be eagerly loaded. Is this possible in Rails 3.2? I've tried several ways to include the association yet calling categories on the facebook_user object always makes another query to Category. Here's a simplified version of my activerecord associations.
class FacebookUser < ActiveRecord::Base
belongs_to :user, touch: true
has_many :user_categories, through: :user
has_many :categories, through: :user_categories
end
class User < ActiveRecord::Base
has_many :user_categories
has_many :categories, through: :user_categories
has_one :facebook_user
end
class UserCategory < ActiveRecord::Base
belongs_to :user
belongs_to :category
end
#single query
FacebookUser.includes( user: :categories).joins(user: :categories).each do |f|
## N+1 query on f.categories
f.categories.first
end
#multi-part query
facebook_user_ids = FacebookUser.where(user_id: [1,2,3]).joins(user: :categories).pluck('facebook_users.id')
FacebookUser.where( id: facebook_user_ids ).includes( user: :categories)
With
FacebookUser.includes( user: :categories)
you have eager loaded the user and his categories instead of the categories on facebook_user. So in order to avoid n+1 query you call then
f.user.categories
So why u just don't eager facebook_user's categories?
FacebookUser.includes(:categories)

Added two "belongs_to" to a Comment model but unable to get one of the associations

I am currently building very simple Comment system on Rails. The primary models are User, Albumpost, and Comment. Users can post Albumposts. For each Albumpost, Users can add Comments to the Albumpost. As a result, a Comment belongs to a User and belongs to an Albumpost.
The problem I'm having is that even with the proper associations in my models (see below), I can't get
#comment.user.name
when I'm trying to render the comments in the albumpost 'show' page (/views/albumposts/show.html.erb). When I go to the page, I can't get #comment.user.name (doesn't understand the association) and get a
"undefined method `name' for nil:NilClass"
Oddly I can get
#comment.albumpost.content
I've double-checked my models and also added the proper foreign keys to the models. Am I doing something wrong in the controllers?
Here are my models:
class Comment < ActiveRecord::Base
attr_accessible :body, :albumpost_id, :user_id
belongs_to :albumpost
belongs_to :user
end
class Albumpost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
has_many :comments, dependent: :destroy
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :albumposts, dependent: :destroy
has_many :comments, dependent: :destroy
end
Here are the relevant parts of my Albumpost and Comments controllers:
class AlbumpostsController < ApplicationController
def show
#albumpost = Albumpost.find(params[:id])
#comments = #albumpost.comments
#comment = Comment.new
#comment.albumpost_id = #albumpost.id
#comment.user_id = current_user.id
end
end
class CommentsController < ApplicationController
def create
albumpost_id = params[:comment].delete(:albumpost_id)
#comment = Comment.new(params[:comment])
#comment.albumpost_id = albumpost_id
#comment.user_id = current_user.id
#comment.save
redirect_to albumpost_path(#comment.albumpost)
end
end
I think you should prefer setting objects to relations instead of setting their ids. For example, you should do this:
#comment.user = current_user
instead of
#comment.user_id = current_user.id
ActiveRecord will take care of setting corresponding *_id fields. I'm not sure how it handles the reverse. (it should autoload though, if I understand correctly)

has_many :through causes error: HasManyThroughSourceAssociationMacroError

I need to assign students (users) to classes (studentclasses)
I have a simple many-to-many relationship using 3 tables:
studentclasses (lesson details)
users (user... student info)
studentclass_users (Join table containing user_id and studentclass_id)
I'm using has_many :through and my models look like the following:
studentclass.rb
class Studentclass < ActiveRecord::Base
has_many :studentclass_users
has_many :users, :through => :studentclass_users
end
user.rb
class User < ActiveRecord::Base
...more here...
has_many :studentclass_users
has_many :studentclasses, :through => :studentclass_users
end
studentclass_users.rb
class StudentclassUsers < ActiveRecord::Base
belongs_to :studentclass
belongs_to :user
end
For testing purposes, I'm just using a hidden field in my studentclass new view partial to tack on a user id when creating the class and it is as follows:
_new.html.erb
<%= hidden_field_tag "studentclass[user_ids][]", 29%>
And in my studentclass controller:
studentclasses_controller.rb
def new
#studentclass = Studentclass.new
end
def create
#studentclass = Studentclass.new(params[:studentclass])
#studentclass.save!
end
My params comes back:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"MjBTf4rtcyo8inADrSxPZB3vLOKtlZRVFlQJJzfCqWs=", "studentclass"=>{"class_title"=>"hjhkj", "user_ids"=>["29"]}, "commit"=>"Save"}
which seems fine but I get the following error:
NameError (uninitialized constant ActiveRecord::HasManyThroughSourceAssociationMacroError):
I think this is something simple with naming maybe? Any help would be appreciated

Rails includes nested relations

I need to query all posts from a specific user and include all comments and the user who belongs to the comment.
class User < ...
has_many :posts
has_many :comments
end
class Post < ...
belongs_to :user
has_many :comments
end
class Comment < ...
belongs_to :user
belongs_to :post
end
#posts = current_user.posts.include(:comments)
Is is possible to also get the comment user? I list a lot of posts and comments. I do not want to query each comment user.
Thx / Tobias
Try
#posts = current_user.posts.includes( :comments => :user)
Read more about it here
How about include at the relation definition statement?
:include
Specify second-order associations that should be eager loaded when this object is loaded.
class Post <
belongs_to :user
has_many :comments, :include => [:user], :limit => 5
end

Rails calling User record from Friends model

I've built a simple Friend model, which allows Users to have multiple friends. Here's what that looks like:
class Friend < ActiveRecord::Base
belongs_to :user
class User < ActiveRecord::Base
has_many :friends
Each friend record just has an id, user_id and friend_id. The user_id is the id of the user it belongs to and the friend_id is the id of user they are befriending.
Here's my problem
I'm not quite sure how to display a list of a particular user's friends. #user.friends will give me a list of all the friend records they have, but not the user accounts of those friends.
For instance, I am trying to build a show page for the friends controller:
class FriendsController < ApplicationController
def show
#user = current_user
end
SHOW.HTML.ERB
<% if #user.friends.count > 0 %>
<% #user.friends.each do |friend| %>
<div class="entry">
<%= friend.username %>
This does not work because friend in this case does not have username. I need to do something like this in my controller:
#friend = User.find_by_id(friend.friend_id)
But I'm not sure how I would call that in my view in the #user.friends loop. Any thoughts appreciated. Let me know if I need to be more clear.
UPDATE
I've updated my User model like so:
has_many :friends, :include => :user
has_many :friended_users, :through => :friends, :source => :user, :uniq => true
However, when I run #user.friended_users it's giving me the user_ids (which is the same as #user) rather than friend_ids.
How can I tweak that relationship so it's linking to the friend_id rather than user_id?
The more I think about it, I think I may not have set up the relationship properly in the first place. Maybe a User should has_many :users, through => 'friends', but that doesn't really make sense...
UPDATE
I've updated my models based on #twooface's input:
class User < ActiveRecord::Base
has_many :friendships
has_many :friends, :through => :friendships
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
class Friend < ActiveRecord::Base
has_many :friendships
has_many :users
I'm just not sure what my Friends table should look like. I assume it should have a primary key and a user_id? If I create a friendship and friend record, I can do friendship.user and friendship.friend and get the correct results, but user.friends gives me an empty hash...
I think your relations are built a bit wrong. Try something like this:
class User < ActiveRecord::Base
has_many :friends
has_many :friendships
has_many :friends, :through => :friendships
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
# This class has :user_id and :friend_id
Then everything will be simpler. Every user will have an array of friends that will be just users.
User.first.friends
Will return an array of Users that this User friends.
Hope this helps.