question about using the polymorphic association in rails - ruby-on-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.

Related

Ruby on rails - ActiveModel association with array

i'm building a RoR app
this is my original scenario:
2 models, Clienti and Interventi
class Clienti < ActiveRecord::Base
has_many :interventi, :dependent => :destroy, :foreign_key => "cliente_id"
......
end
class Interventi < ActiveRecord::Base
belongs_to :clienti, :foreign_key => "cliente_id"
.........
end
this is a simple one-to-many relation, each "clienti" has many "interventis" (iterventi is a kind of job in my app).
Today i need to convert this relation from one-to-many to many-to-many, each "interventi" need to have more then one "clienti", so i think i have to change the "cliente_id" column in DB from int to text and store an array of "Clienti's ids" (is it the good way? )
My question is: if it's the good way, how can i keep the association in model so i can still use something like "Clienti.Interventi.count" ?
Thanks to all!
You would need a join model to do this kind of many-to-many association. By convention, you could call it clienti_interventi
class Clienti
has_many :clienti_interventis
has_many :interventis, through: :clienti_interventis
end
class Interventi
has_many :clienti_interventis
has_many :clientis, through: :clienti_interventis
end
class ClientiInterventi
belongs_to :clienti
belongs_to :interventi
end
With this setup, you can keep doing whatever you were doing, as well as Clienti.first.interventis.count or Interventi.first.clientis.count

Using Rails, not sure if I should use belongs_to or not

Very new to Rails... I'm building out functionality that lets people compare photos, and I can't decide exactly how I should structure it. Ideally what I'd like is to have a "comparisons" table which keeps a record of the IDs of the photos compared as well as the user that compared them, but I'm not quite sure whether this warrants use of the "belongs_to" function or not. If so, how do I specify that each comparison belongs to TWO separate photos?
The following has_many, :through => Model structure will let you have additonal properties on the join table, e.g. 'comparing_user_id'.
class Photo < ActiveRecord::Base
has_many :appearances
has_many :users, :through => :appearances
end
class Appearance < ActiveRecord::Base
belongs_to :photo
belongs_to :user
end
class User < ActiveRecord::Base
has_many :appearances
has_many :photos, :through => :appearances
end

generic categories for my rails models

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.

Rails Modeling Question - Relationships and Primary Keys

I'm working on a rails site that I've inherited and am trying to troubleshooting some sub-optimal model behavior. I have users, songs, and songs_download, each of which is its own model.
Here's the relevant line from the users model:
has_and_belongs_to_many :downloaded_songs, :class_name => 'Song', :join_table => :song_downloads
From the songs model:
has_and_belongs_to_many :downloaded_users, :class_name => 'User', :join_table => :song_downloads
And from the song_downloads model:
belongs_to :user
belongs_to :song
Here's the code to create a new song_download record when a user downloads a song (in the songs controller):
SongDownload.create( :song_id => #song.id,
:user_id => current_user.id,
:download_date => Date.today )
The problem I'm having is that once a user downloads a song, if I try to invoke the downloaded users from the interactive console, by, say, typing the following:
Song.find(<some id>).downloaded_users
I get back the complete record of the user, but the id in the returned objected is the primary key of the SongDownload, not the primary key of the User. All of the other fields are accurate, but the ID is not.
I didn't come up with this modeling scheme and it seems to me that :has_and_belongs_to_many might be more appropriately used with no explicitly modeled SongDownload object, but I'd rather not overhaul the codebase if I can help it. Are there any ways to get back the right user id given the current modeling scheme?
Thanks very much for your time and consideration!
Justin
Has and belongs to relationships are being phased out in favour of has many :through relationships.
On the upside you won't need to change any of your underlying structure, just the relationship declarations in the Song and User models.
class Song < ActiveRecord::Base
has_many :song_downloads
has_many :users, :through => :song_downloads
...
end
class User < ActiveRecord::Base
has_many :song_downloads
has_many :songs, :through => :song_downloads
...
end
Now
Song.find(<some id>).users
Returns an array of User objects which are joined to the selected song through the song_downloads table.
The has_many :through is recommended when the join table has more columns than simply two foreign keys.
class User < ActiveRecord::Base
has_many :song_downloads
has_many :downloaded_songs,
:through => :song_downloads,
:source => :song
end
class Song < ActiveRecord::Base
has_many :song_downloads
has_many :downloaded_users,
:through => :song_downloads,
:source => :user
end
Now you can get a list of users that have downloaded a particular song like so:
Song.find(1).downloaded_users

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