Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order Data from three different models in ruby on rails

I have three models ie image, datafiles and video. I want to fetch the latest content by a user from all the three models.

One very bad of doing this can be:

  images = User.find(8).images
  videos = User.find(8).videos
  data_files = User.find(8).data_files

All the content:

 all_content = images + videos + data_files
 all_content.sort_by(&:created_at).reverse.paginate(:page => params[:page],:per_page=> per_page)

How can do this in just one query to make the code better.

like image 697
Mohit Jain Avatar asked May 20 '26 13:05

Mohit Jain


1 Answers

Probably it's a good idea to have a Content model which connects a user to his contents. Something like this:

class User < ActiveRecord::Base
  has_many :contents
end

class Content < ActiveRecord::Base
  belongs_to :user
  # Remember the contentable_type and contentable_id columns
  belongs_to :contentable, :polymorphic => true
end

# Similar relations for Image/File models
class Video < ActiveRecord::Base
  has_one :content, :as => :contentable
  belongs_to :user, :through => :content
end

# Then to fetch the last contents from the user
Content.where(:user_id => 8).order('created_at DESC')
       .paginate(:page => params[:page], :per_page=> per_page)

It's just a proof of concept, you could even go with single table inheritance if you prefer, it depends on the attributes each of your content model has, probably it's the better thing given these object usually contains a title, a body, a link to the content, an url and similar stuff and few differences.

If you go with STI you need to define a base model (Content in this case) with the common attributes and several other model for each of your content model (e.g. Image or Video). These models inherit from the Content model. Remember to have a contents table in your DB with a type column (which will contain the string with the type of content, e.g. 'Video') and all the columns for the child models (yes, if you use this approach all the data will go in a single table).

UPDATE: The Single Table Inheritance approach has several pros, e.g. you get all the contents' data in one query, the previous solution is good for sorting but you still need to get the Video, and other specific data with other queries:

# The contents table has a type string column and
# all the specific models's columns
class Content < ActiveRecord::Base
end

# Video class inherit from Content (a Video is a Content!)
class Video < Content
end

In this case if you want all the user's content you can use user.contents and you'll get an array of the specific objects (Video, Image and so on) depending of their type. You can also get just the images or videos with something like this Video.all

Of course these are just ideas, the real implementation depends on your problem and requirements.

like image 107
Aldo 'xoen' Giambelluca Avatar answered May 22 '26 05:05

Aldo 'xoen' Giambelluca