Rails: Pulling results for a polymorphic association - ruby-on-rails

I have a the following polymorphic association set up:
class Favorite < ActiveRecord::Base
belongs_to :favoritable, :polymorphic => true
belongs_to :user
end
class Photo < ActiveRecord::Base
has_many :favorites, :as => :favoritable
belongs_to :user
end
What I ultimately want to do is pull all the photos a specific user has favorited.
How would I make that happen?

You could use the Active Record Query Interface for this:
Photo.joins(:favorites).where("favorites.user_id = ?", user_id)
This will return an Array of Photo objects (along with joined fields from Favorite) that a specific user has favorited. You'll have to pass in the user_id to this call.

Related

Most efficient way to pull a specific record from an ActiveRecord collection

In my database, Account has many Contacts.
class Account < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :account
end
Contacts has a field called primary_contact, which denotes the record as the primary. In a situation where I need to pull all contacts for an account, and list the primary contact separately, is there an efficient way to pull this primary record out with ActiveRecord, or should I just identify the correct record in the collection that it returns by looking at the values of that field manually?
Ideally I would like to be able to do something like account.primary_contact or even contacts.primary to identify this, but it's not necessary.
you can add a has_one association
class Account < ActiveRecord::Base
has_many :contacts
has_one :primary_contact, class_name: 'Contact', conditions: { primary_contact: true }
end
UPDATE: rails 4 syntax would be
has_one :primary_contact, -> { where(primary_contact: true) }, class_name: 'Contact'
class Contact < ActiveRecord::Base
belongs_to :account
scope :primary, where( primary_contact: true )
end
Then if you have an account:
account.contacts.primary
should give you the primary contacts.

Polymorphic associations and/or has_many_through

I need to create relationships between a user, product and a photo-model. A user can add photos to a product. Therefore, a user has_many photos and a product has_many photos, but each photo belongs_to both a product and a user. How can I achieve this in Rails? As far as I understand a polymorphic association would only allow a photo to belong to a product or a user. Do I have to instead using separate has_many_through relationships for the user-photo and product-photo relationships?
You can have multiple belongs_to attributes within the same model. Essentially the Model that is marked as belongs_to will hold a foreign key to the Model that has been marked with has_many.
class MyModel < ActiveRecord::Base
belongs_to :other_model1
belongs_to :other_model2
end
If you want to use polymorphic associates as you mentioned below you could do that along these lines
class Photos < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Users < ActiveRecord::Base
has_many :photos, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :photos, :as => :imageable
end
In this case you can create the relationship simply by adding the has_many :phots, :as => :imageable attribute without having to revisit the Photos class.

Rails - Query with has_many association

I am currently trying to create a custom method on a model, where the conditions used are those of a has_many association. The method I have so far is:
class Dealer < ActiveRecord::Base
has_many :purchases
def inventory
inventory = Vehicle.where(:purchases => self.purchases)
return inventory
end
end
This is not working, due to the fact that Vehicle has_many :purchases (thus there is no column "purchases" on the vehicle model). How can I use the vehicle.purchases array as a condition in this kind of query?
To complicate matters, the has_many is also polymorphic, so I can not simply use a .join(:purchases) element on the query, as there is no VehiclePurchase model.
EDIT: For clarity, the relevant parts of my purchase model and vehicle models are below:
class Purchase < ActiveRecord::Base
attr_accessible :dealer_id, :purchase_type_id
belongs_to :purchase_item_type, :polymorphic => true
end
class Vehicle < ActiveRecord::Base
has_many :purchases, :as => :purchase_item_type
end
class Dealer < ActiveRecord::Base
def inventory
Vehicle.where(:id => purchases.where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type_id))
end
end
Or:
def inventory
purchases.includes(:purchase_item_type).where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type)
end
I was able to do this using the :source and :source_type options on the Vehicle model, which allows polymorphic parents to be associated.

Rails: How do I check a polymorphic association?

I have the follow model setup:
class Favorite < ActiveRecord::Base
belongs_to :favoritable, :polymorphic => true
belongs_to :user
end
class Photo < ActiveRecord::Base
belongs_to :user
has_many :favorites, :as => :favoritable
end
class User < ActiveRecord::Base
has_many :photos
end
And that Favorite model has favoritable_id and favoritable_type` fields.
What I ultimately want to do is check and see if a User has already marked a photo as a favorite.
I'm able to create the database record without issue...it's the checking to see if that user already has favorited the photo (or other data type) that I'm having issues with.
I could obviously do some sort of raw SQL query to get it, but seems like there's gotta be a more "standard" way of doing it.
I'm running Rails 3.0.3.
you can add two other associations in the User model and a method that checks if the photo is favorite :
has_many :favorites
has_many :favorites_photos, :through => :favorites, :source => :favoritable, :source_type => 'Photo'
def photo_favorite?(photo)
favorites_photos.exists?(photo.id)
end
or more simply just by adding this method to the Photo model :
def favorite_for?(user)
favorites.exists?(:user_id => user.id)
end
I did not tested it, but I think it should work.

Adding a Rating to each User per category on Ruby on Rails

Right now I'm building a social media app, where i want an user to have a rating per category, how would the association go? The way it needs to be setup it's Each user will have a different rating in each category.
I'm think that
belongs_to :user
belongs_to :category
in the UserCategoryRating model.
and
has_many :user_category_ratings, through => :category
on the User model, Is this the correct approach?
The UserCategoryRating table has the User_id column, Category_id column, and the rating column, that updates each time an user gets votes (The rating it's just the AVG between votes and the score based on 1-5)
UPDATE: If I'm understanding you correctly, here is a diagram of the simple design you'd like:
And this would be the basic skeleton of your classes:
class User < ActiveRecord::Base
has_many :ratings
# has_many :categories, :through => :ratings
end
class Category < ActiveRecord::Base
has_many :ratings
# has_many :users, :through => :ratings
end
class Rating < ActiveRecord::Base
belongs_to :user
belongs_to :category
validates_uniqueness_of :user_id, :scope => [:category_id]
end
Will allow for these query:
#category_ratings_by_user = Rating.where("ratings.user_id = ? AND ratings.category_id = ?", user_id, category_id)
#specific_rating = user.ratings.where("ratings.category_id = ?", category_id)
# make nice model methods, you know the deal
# ... if you added the has_many :through,
#john = User.find_by_name("john")
# Two ways to collect all categories that john's ratings belong to:
#johns_categories_1 = #john.ratings.collect { |rating| rating.category }
#johns_categories_2 = #john.categories
#categories_john_likes = #john.categories.where("categories.rating >= ?", 7)
I'm just unsure as to why you want this has_many, :through (this doesn't seem like a many to many -- a rating only belongs to one user, correct?).
I will use the following data model:
class User
has_many :user_categories
has_many :categories, :through => :user_categories
end
class UserCategory
belongs_to :user
belongs_to :category
# this model stores the average score also.
end
class Category
has_many :user_categories
has_many :users, :through => :user_categories
end
Now when you want to update the score of a user for a category
uc = u.user_categories.find_by_category_id(id)
uc.score = score
uc.save

Resources