Multiple Polymorphic Model in Rails - database

Hey So i have a basic schema that I am implementing. Here are the basic Models
User - Public Free User of App
Organization - Subscribes to app, has employees
Employee - Belongs to an organization
Here are my polymorphic parts
Post - Can be made by employees or users
Image - Multiple can be attached to either posts or comments
Comment - Can be added to images or posts by either employees or users
Users and Employees are distinct.
The polymorphic image is done. Where i am having trouble is the comment part. How do i set this up so that the comment can be associated with either images or posts and can be posted by either employees or users. Here is what i have so far.
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Post < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Image < ActiveRecord::Base
has_many :comments, :as => :commentable
end
This sets it up so that the comment can belong to the post or image, how do i set it up so that the employee/user can have many comments as they add them? Or should i just split this up into EmployeeComments and UserComments.
It seems like i will need another table that will host the polymorphic ownership association.

You should just need to add another polymorphic belongs_to association to the Comment model which will represent the author of the comment.
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
belongs_to :authorable, :polymorphic => true
end
class User < ActiveRecord::Base
has_many :comments, :as => :authorable
end
class Employee < ActiveRecord::Base
has_many :comments, :as => :authorable
end

Related

Rails Association logic on event and ticket

I am writing an event application using ruby on rails and i am stuck on how to do the association effectively: the association is base on the following table User, Event, Ticket. The problem i have right now is the ticket and events, they are two type of tickets: free & paid which also have quantity.
i will be glad if anyone can help me with this association thanks.
Regarding the type of the ticket types you should look into STI.
Prerequisites:
# Gemfile
gem 'active_record_union'
It basically goes something like this:
class Ticket
end
class FreeTicket < Ticket
# Free-ticket stuff goes here
end
class PaidTicket < Ticket
validates :price, presence: true # and other paid-related checks
end
I suggest something along these lines for associations:
class Event # Also STI
end
class FreeEvent < Event
has_many :free_tickets
has_many :users, through: :free_tickets
end
class PaidEvent < Event
has_many :paid_tickets
has_many :users, through: :paid_tickets
end
class Ticket
belongs_to :event
belongs_to :user
scope :open, -> { where(user_id: nil) }
scope :taken, -> { where.not(user_id: nil) }
end
class User
has_many :free_tickets
has_many :paid_tickets
has_many :free_events, through :free_tickets
has_many :paid_events, through :paid_tickets
def events
free_events.union(paid_events)
end
end
This way you can do something like:
Event.find(1).tickets.count # => 13
Event.find(1).tickets.open.count # => 10
Event.find(1).tickets.taken.count # => 3
Event.find(1).users.count # => 3
User.find(1).events.count # => 1
User.find(1).free_events.count # => 0
User.find(1).paid_events.count # => 1

Finding similar values in a hash/array in Ruby

I am trying to compute how many 'tips' a 'user' has in common with another user.
Here is my method doing so:
class User < ActiveRecord::Base
has_many :tips, :inverse_of => :user
...
public
def tip_affinity_with(user)
tipAffinity = 0
user.tips.each do |tip|
if self.tips.include?(tip)
tipAffinity = tipAffinity + 1
end
end
return tipAffinity
end
end
I know that some users have tips that they have both rated, but in my table, the tipAffinity is 0 for all of the users.
What could be the problem? Any help is greatly appreciated!
EDIT: Here is the join model, Affinity:
class Affinity < ActiveRecord::Base
attr_accessible :user_A_id, :user_B_id, :tips_value, :tips_valid, :profile_value, :profile_valid, :value
belongs_to :users
belongs_to :inverse_user, :class_name => "Users"
validates :tips_value, presence: true
validates :profile_value, presence: true
validates :user_A_id, presence: true
validates :user_B_id, presence: true
before_update :set_value
before_create :set_value
private
def set_value
self.value = 0.7*self.tips_value + 0.3*self.profile_value
#self.value = PredictionConfigs.find(1)*self.tips_value + (1 - PredictionConfigs.find(1))*self.profile_value #Use prediction configs
end
end
I am indeed trying to find the intersection of two hashes. The two hashes are the tips of two users, one is self, the other is user.
Thanks again!
Although this is brutally inefficient, you might try:
(user.tips & self.tips).length
You really want to avoid loading models if you're not using the data contained within them. This should be possible to compute using only what's present in the database. Something like:
(user.tip_ids & self.tip_ids).length
If your models are set up correctly, this can be done in the database with:
def tip_affinity_with(user)
user.tips.where(id: tip_ids).count
end
It seems to me based on the comments (and your example code) that your models may not be set up correctly. Do you have a join model between users and tips? Something like:
class User < ActiveRecord::Base
has_many :suggestions
has_many :tips, through: :suggestions
end
class Suggestion < ActiveRecord::Base
belongs_to :user
belongs_to :tip
end
class Tip < ActiveRecord::Base
has_many :suggestions
has_many :users, through: :suggestions
end
It'd help to see your Tip model. My guess is that Tip belongs_to :user and that's why you aren't getting any overlap between users, but I could be wrong.
Here's some more reading from the Rails guides on has_many :through associations.

Can't Save IDs from other tables into current table in database upon creation of an object Rails, Postgresql

I'm having problems getting multiple ids to save properly into my database.
I have a listing that has two parameters: a listing id and a price.
I've tried changing the controller to accept the current_user, and no luck there.
I've tried changing the model, and I've also tried manually creating a listing while giving it a user_id and book_id (checking that it is, indeed, giving the correct book and user ids). In the manual listing, I've also tried to make variable names without the # symbols, and though there are no errors, I'm still unable to store the values in the database
My listing model:
class Listing < ActiveRecord::Base
belongs_to :user
belongs_to :book
has_one :order
belongs_to :user, class_name: 'Listing'
attr_accessible :listing_id, :price
end
My user model:
class User < ActiveRecord::Base
has_many :books
has_many :listings
belongs_to :creator, class_name: 'User'
end
My book model:
class Book < ActiveRecord::Base
has_one :status
has_one :listing
belongs_to :user
attr_accessible :condition, :isbn, :location, :title, :weight, :comment, :description, :price
validates :isbn, :isbn_format => true
end
The create function in my listings controller
def create
#listing = Listing.new(params[:listing])
#listing.user_id = current_user_id
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render json: #listing, status: :created, location: #listing }
else
format.html { render action: "new" }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
How I've tried to manually create the user_id and book_id columns:
<b><%= "Returned: "+doc.css("Ack").text %> </b> #returns if listing was a failure or success
<b><%= "Listing ID: "+doc.css("ItemID").text %></b> #returns the listing itemID
<% #book = Book.find_by_id(params[:book_id_num]) %><br /> #passed from a previous page
<% #user = User.find_by_id(current_user.id) %>
<%= #book.id %> #successfully displays the correct book id on the web page
<%= #user.id %> #successfully displays the id of the current_user
<% Listing.create(:listing_id => doc.css("ItemID").text, :price => price, :book_id => #book.id, :user_id => #user.id)%>
But doing it this way will only create a listing with a listing_id and a price.
I've been stuck for a while, and am unsure of how to proceed. I'm also fairly unfamiliar with how a database might function. Can anyone help me out?
I figured out the answer to my problem.
Using the rails console, it told me that it was unable to edit certain attributes in the creation of a listing.
I'm not sure if it's the rails way to do things, but if I allow the user_id and book_id to be accessible attributes, I am able to store the listing with the correct ids in the database. So my listing model looks as follows:
class Listing < ActiveRecord::Base
belongs_to :user
belongs_to :book
has_one :order
belongs_to :user, class_name: 'Listing'
attr_accessible :listing_id, :price, :user_id, :book_id
end
I can edit these values in the table appropriately when I create a listing.
Thanks to mu is too short for giving me the tip to check the creation of a listing in the rails console. I was not aware that it could be used in such a useful way.

rails and Mongoid, create Qualification system (Embed qualification into two Models)

i working on a little app to show some pictures.
Each picture can be "voted" or "qualified" in a scale of 1 to 5.
The qualification can be done for a logged user only one time.
I need to know the qualification of each image, and what image a user set the vote (and know the value of that vote), so i create this models:
class Voto
include Mongoid::Document
embedded_in :picture
embedded_in :user
field :value, :type => Integer
end
class Picture
include Mongoid::Document
embeds_many :votos
embeds_many :comments
belongs_to :user
...
...
end
class User
include Mongoid::Document
...
...
has_many :pictures
embeds_many :votos
end
But i don't know if this is correct. ¿Can i store the same model (in this case Voto) in two differents documents (Picture and User)?
Any idea how to achieve this?
You can do this by using the polymorphic flag
(see http://mongoid.org/en/mongoid/docs/relations.html#common Polymorphism)
class Voto
include Mongoid::Document
embedded_in :voteable, , polymorphic: true
field :value, :type => Integer
end
class Picture
include Mongoid::Document
embeds_many :votos, as: :voteable
embeds_many :comments
belongs_to :user
...
...
end
class User
include Mongoid::Document
...
...
has_many :pictures
embeds_many :votos, as: :voteable
end

Mongoid relational Polymorphic Association

Does anyone know how to do a polymorphic association in Mongoid that is of the relational favor but not the embedding one.
For instance this is my Assignment model:
class Assignment
include Mongoid::Document
include Mongoid::Timestamps
field :user
field :due_at, :type => Time
referenced_in :assignable, :inverse_of => :assignment
end
that can have a polymorphic relationship with multiple models:
class Project
include Mongoid::Document
include Mongoid::Timestamps
field :name, :type => String
references_many :assignments
end
This throws an error saying unknown constant Assignable. When I change the reference to embed, this all works as documented in Mongoid's documentation, but I need it to be reference.
Thanks!
Answering to an ancient post, but someone may find it useful.
Now there's also a polymorphic belongs_to:
class Action
include Mongoid::Document
include Mongoid::Timestamps::Created
field :action, type: Symbol
belongs_to :subject, :polymorphic => true
end
class User
include Mongoid::Document
include Mongoid::Timestamps
field :username, type: String
has_many :actions, :as => :subject
end
class Company
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
has_many :actions, :as => :subject
end
From Mongoid Google Group it looks like this is not supported. Here's the newest relevant post I found.
Anyway, this is not to hard to implement manually. Here's my polymorphic link called Subject.
Implementing inverse part of relation might be somewhat more complicated, especially because you will need same code across multiple classes.
class Notification
include Mongoid::Document
include Mongoid::Timestamps
field :type, :type => String
field :subject_type, :type => String
field :subject_id, :type => BSON::ObjectId
referenced_in :sender, :class_name => "User", :inverse_of => :sent_notifications
referenced_in :recipient, :class_name => "User", :inverse_of => :received_notifications
def subject
#subject ||= if subject_type && subject_id
subject_type.constantize.find(subject_id)
end
end
def subject=(subject)
self.subject_type = subject.class.name
self.subject_id = subject.id
end
end
Rails 4+
Here's how you would implement Polymorphic Associations in Mongoid for a Comment model that can belong to both a Post and Event model.
The Comment Model:
class Comment
include Mongoid::Document
belongs_to :commentable, polymorphic: true
# ...
end
Post / Event Models:
class Post
include Mongoid::Document
has_many :comments, as: :commentable
# ...
end
Using Concerns:
In Rails 4+, you can use the Concern pattern and create a new module called commentable in app/models/concerns:
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
end
and just include this module in your models:
class Post
include Mongoid::Document
include Commentable
# ...
end

Resources