generic categories for my rails models - ruby-on-rails

I am working in a rails app which main points are articles and products.
Someone has implemented categories for articles.
class ArticleCategory < MainSchemaBase
belongs_to :user
has_many :articles, :through => :article_category_articles, :conditions => 'articles.deleted_at IS NULL'
has_many :article_category_articles, :conditions => 'article_category_articles.deleted_at IS NULL'
And I have been asked to do basically the same thing for products.
Of course I want to DRY but products belongs to brand instead of user, and I have many products instead of many articles
The model is almost empty (some named scopes), controller and views also very dependent of the context (article)
Can this be DRY? Or should I just copy the implemntation ?

Make it polymorphic: The best way, i think, is to set up a polymorphic many-to-many relationship using has_many_polymorphs (https://github.com/Nielsomat/has_many_polymorphs) so that a single category could be applied to a product and an article.
class Category
#doesn't have any association fields
has_many_polymorphs :categorizables, :from => [:products, :articles], :through => :categorizations, :dependent => :destroy
end
class Categorization < ActiveRecord::Base
#has fields categorizable_id, categorizable_type, :category_id
belongs_to :categorizable, :polymorphic => true
belongs_to :category
end
class Product < ActiveRecord::Base
#doesn't need anything to set up the association
end
class Article < ActiveRecord::Base
#doesn't need anything to set up the association
end
"Categorizable" is a bit of a mouthful but you won't actually be using it. You'll be saying #product.categories or #category.articles etc.

Related

Rails Polymorphic Associations

Total newbie to Rails and programming in general, so please forgive me if the answer to my question seems glaringly obvious. I've been doing a lot of reading including the ROR guides but can't seem to find a scenario specific to the following situation:
I have three models scaffolded under one User model, and am trying to link them like so:
class User < ActiveRecord::Base
has_many :malls, :dependent => :destroy
end
class Mall < ActiveRecord::Base
belongs_to :user
has_many :stores, :dependent => :destroy
has_many :cakes, :as => :cake_poly, :dependent => :destroy
end
class Store < ActiveRecord::Base
belongs_to :mall
has_many :cakes, :as => :cake_poly, :dependent => :destroy
end
class Cakes < ActiveRecord::Base
belongs_to :cake_poly, :polymorphic => true
end
Will this work? If it does, is there a better way to implement this? If not, how else can I implement the associations?
The idea is that each User may have many malls, each Mall may have many stores, and both malls and stores may have many cakes.
A key question for your design is the intent - what do you want to achieve?
You should not use the polymorphic relationship if you simply like to aggregate cakes available in the mall's shops for the mall model. You can use the following relationship to achieve such a design:
class Mall < ActiveRecord::Base
has_many :stores
has_many :cakes, :through => :stores
end
The polymorphic approach is a perfect choice if the two sets (cakes in the mall, cakes in the mall's stores) don't correlate.

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.

Comment belongs_to one of several models

My scenario is that there are several different models which can have comments. Trying to figure out the relationships:
Post
has_many :comments
Update
has_many :comments
Comment
belongs_to EITHER :post OR :update (but not both)????
Whats the proper way to set up the comment relationships? I want to be able to call Post.comments and Update.comments
Smells like a polymorphic association:
With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.
So you'd want something like this:
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
end
class Post < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class Update < ActiveRecord::Base
has_many :comments, :as => :commentable
end
You'd have to set up a few things in the database for this to work as well. See the Polymorphic Associations section of the Active Record Associations Guide for details on the columns you'll need.

question about using the polymorphic association in rails

How guys
I'm new to rails, here's my code:
class Video < ActiveRecord::Base
belongs_to :videoable, :polymorphic => true
end
class Drummer < ActiveRecord::Base
has_many :videos,:as => :videoable
end
class Cymbal < ActiveRecord::Base
has_many :videos, :as => :videoable
end
From this point I can use the drummer.videos to get all the video that belong to drummer,
But I can't use video.drummer to get who is the video belongs to.
of course I can use video.where(:videoable_id => '1', :videoable_type => 'drummer') to get the to find the exact drummer record, but I think there must be a elegant to do that in rails, right?
and one more question, I want to improve this association, video and drummer, video and cymbal should be many-to-many, sometime there are more than 1 drummer or 1 cymbal in one video, so it makes sense do it this way. how can I do this?
If it's always a one-to-many relationship that you want (a video can at most have one drummer), you can add these lines to your Video model:
belongs_to :drummer, :class_name => "Drummer", :foreign_key => "videoable_id"
belongs_to :cymbal, :class_name => "Cymbal", :foreign_key => "videoable_id"
Rails will figure out what class the foreign key maps to and fetch the correct entry.
You might be looking for video.videoable and many-to-many join tables.
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods
http://railscasts.com/episodes/47-two-many-to-many
http://railscasts.com/episodes/154-polymorphic-association
If your Drummer and Cymbal models are similar, you might consider using STI instead of polymorphism. Define a new model with at type column to act as a parent, and add the has_many association, then add the child models:
class Subject < ActiveRecord::Base
has_many :subject_videos, :dependent => :destroy
has_many :videos, :through => :subject_videos
end
class Drummer < Subject
end
class Cymbal < Subject
end
Add a SubjectVideo model with foreign keys subject_id and video_id. Then make your Video model associate through it:
class Video < ActiveRecord::Base
has_many :subject_videos, :dependent => :destroy
has_many :subjects, :through => :subject_videos
end
Now you have a many-to-many association.
d = Drummer.create
d.videos # []
d.videos.create(:name=>"Stompin' at the Savoy")
v = Video.find_by_name("Stompin' at the Savoy")
v.subjects # [Drummer]
The primary drawback of this approach is that Drummer and Cymbal are now stored in the same table, which can be undesirable if they share few columns.
If still need a many-to-many relationship using polymorphism, also take a look at has_many_polymorphs.

Rails Polymorphism 'backwards'

Say I'm writing a blog app with models for posts, pages and photos. I've got a category model, that may be linked to any of these models. So, a category may contain various kinds of items. Every item only has ONE category.
I could implement this using a generic tagging pattern with a join table, but I want to make sure every subject can have only category.
What would be the best way to implement this in Rails?
Okay, I think I've got it:
class Post < ActiveRecord::Base
has_one :categorization, :as => :categorizable
has_one :category, :through => :categorization
end
class Category < ActiveRecord::Base
has_many :categorizations, :dependent => :destroy
end
class Categorization < ActiveRecord::Base
belongs_to :category
belongs_to :categorizable, :polymorphic => true
end
Now various models can have a category, but each instance can have only one category… I guess.

Resources