I want to model different post types
ImagePost VideoPost TextPost. They all have different contents
I was going to go with post has_many polymorphic but rails doesn't support it
A previous stackoverflow post pointed me towards has_many_polymorphs gem but is deprecated
I need to be able to post different posts types and retrieve them in an instance show them on a feed
e.g.
#posts.each do ..
if type == video ...
elseif type == image ....
I'm new to rails so thanks for the assistance.
Use single table inheritance of Post model
class class Post < ActiveRecord::Base
.....
end
Than inherit this Post model into these model.
class VideoPost < Post
end
class ImagePost < Post
end
At migration you need to create a type column for different type of post. For details look at this blog post
Consider doing the following
class Post < ActiveRecord::Base
# Create the an association table and add additional info on the association table, description, etc etc.
has_many :images, through: image_posts
has_many :image_posts
end
class Image < ActiveRecord::Base
# Image specific
end
Doing this, #post.image_posts.count > 0 indicates there are multiple image_posts.
Or you could also achieve the goal by polymorphic relation:
class VideoPost < ActiveRecord::Base
belongs_to :postable, polymorphic: true
end
class ImagePost < ActiveRecord::Base
belongs_to :postable, polymorphic: true
end
class Feed < ActiveRecord::Base
has_many :posts, as: :postable
end
In this case #feed.posts.each will check the postable_type, which is the model type instead.
STI is the way to go. I guess columns of all three type should be same or similar at least. So Single tale inheritance would be the best choice.
Related
So I am making an app that reviews books, articles and the like.
I have created the backbone of the app by creating models, views, controllers etc for Piece(the book or article), Section(self explanatory), Subsection, and Subsubsection.
I want to add a new model into the mix, a "Links" model (which will just be a link to another source or website). My issue is that I don't know how to make ALL of my previously stated models have "Links". I want each of The above models to have access and CRUD capabilities to their "Links", but so far all i have read about is has_many or has_and_belongs_to_many.
As far as I understand, those kinds of relations only relate ONE model to ONE other model, even if Piece might have many Sections, it only relates these two models.
I guess the Links model would have to have an obligatory piece_id, but then optional id's such as: section_id, subsection_id depending on where the link was. So if in Chapter 3 of my first book i want to add a link, it would have an obligatory piece_id=1 and then a section_id=3, but then no subsection_id or subsubsection_id.
So how do I go about creating a model such that it belongs to several other models? Or is this even possible?
https://github.com/kingdavidek/StuddyBuddy
Ok, it sounds like essentially you want a polymorphic association
class Link
belongs_to :linkable, polymorphic: true
end
class Piece
has_many :links, as: :linkable
end
Link would need linkable_id integer column and linkable_type string column. You can then use it in the same way as an ordinary has_many to belongs_to association
if i wanted to create a new Link in a Subsection, it would belong to
Subsection, but also to Section and Piece because of the nested
relationship
This bit rails can't help with, you'd need to write your own method to find all the links in the chain of items.
This is a pretty good use case for polymorphic associations. For simplicity lets start out with a one to many relationship:
class Link < ActiveRecord::Base
belongs_to :linkable, polymorphic: true
end
class Piece < ActiveRecord::Base
has_many :links, as: :linkable
end
class Section < ActiveRecord::Base
has_many :links, as: :linkable
end
Here the links table will have linkable_id (int) and linkable_type (string) columns. One important thing to take note of here is that linkable_id is not a true foreign key from the RBDMS point of view. Rather ActiveRecord resolves which table the relation points to when it loads the relation.
If we want to cut the duplication we can create a module which contains the desired behavior. Using ActiveSupport::Concern cuts a lot of the boilerplate code involved in creating such a module.
class Link < ActiveRecord::Base
belongs_to :linkable, polymorphic: true
end
# app/models/concerns/linkable.rb
module Linkable
extend ActiveSupport::Concern
included do
has_many :links, as: :linkable
end
end
class Piece < ActiveRecord::Base
include Linkable
end
class Section < ActiveRecord::Base
include Linkable
end
So how would we make a polymorpic many to many relation?
class Link < ActiveRecord::Base
has_many :linkings
end
# this is the join model which contains the associations between
# Links and the "linkable" models
class Linking < ActiveRecord::Base
belongs_to :link
belongs_to :linkable, polymorphic: true
end
# app/models/concerns/linkable.rb
module Linkable
extend ActiveSupport::Concern
included do
has_many :links, through: :linkings, as: :linkable
end
end
class Piece < ActiveRecord::Base
include Linkable
end
class Section < ActiveRecord::Base
include Linkable
end
On a side note - a better way to build a hierarchy between sections would be to use a single Section model and give it a self joining relationship.
class Section < ActiveRecord::Base
belongs_to :parent, class_name: 'Section'
has_many :children, class_name: 'Section',
foreign_key: 'parent_id'
end
i'm trying to figure out the proper way to do this, but if i have 2 models, how do I get the data from the 1st Model in the 2nd MVC. Example:
Model 1: User
Model 2: Post
I have a "user_id" field in the Post Model. If I am in the Post Controller/View, how do I fetch the user's first and last name from Model 1?
Thanks so much in advance!
Set a user association in the Post model:
class Post < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
Then it is as easy as:
post.user.first_name
Look up associations - With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models.-- http://guides.rubyonrails.org/association_basics.html
class User < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
end
I have two models Board and Pictures and I want a user to be able to comment on either the Board as a whole or the individual Pictures.
My polymorphic Comment model:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
and then I have a simple has_many in each of the other models:
class Board < ActiveRecord::Base
has_many :comments, as: :commentable, dependent: :destroy
has_many :pictures
class Pictures < ActiveRecord::Base
has_many :comments, as: :commentable, dependent: :destroy
belongs_to :board
What I really want to be able to do is add a new scope called something like all_comments which combines the comments from the Board model with the related comments from the Pictures model. I can do this with a method, but I end up with an array and not a scoped relation.
My method:
def all_comments
comments = self.comments
return comments + self.pictures.map {|x| x.comments}.flatten
end
How can I return a scoped relationship that can chain the results?
first of all Pictures should be singular.
secondly, you can just call a finder on Comment to get all the comments you want
Comment.where("type = 'board' AND id IN(?) OR type = 'picture' AND id IN(?)", self.id, self.pictures.map(&:id))
or something like that.
phoet's answer intrigued me (I +1'd), so here's my refactor / expansion on what he suggested:
You'd look in the Comment model to pull out the relevant comments. To do this, you need to firstly know the board & the pictures associated with it. Phoet uses the self.pictures object for this:
#app/models/comment.rb
Class Board < ActiveRecord::Base
def all_comments
ids = self.id + self.pictures.map(&:id)
Comment.find(ids)
end
end
This will find the ids in the comment model, returning the data as a collection. If you wanted a true representation of the comments (hierarchical), you'd have to use some sort of ancestry / inheritance structure I think
From my readings for a one to many relation we need a has_many on the parent side and a belongs_to on the child side. I was wondering does rails create errors or something if I am just interested in one part of the relation and just for example declare the belongs_to side in my model ?
There will be no errors,
has_many and belongs_to just auto generate association methods on the class they are called on.
For example:
class User < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
end
# works
User.first.posts
# error, method undefined
Post.first.user
Please excuse the confusing phrasing in the title. In my RoR project let's say I have it set up like this
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
end
and
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
I then have a categories_products table that connects them. This works fine but my problem is that a product will only ever have one category at a time and I'd of course like to do product.category instead of having to deal with an array. How can I accomplish that?
A one-to-many representation is demonstrated in the rails guides like this:
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :category
end