How to create a (high performance) activity feed from several models? - ruby-on-rails

In a Rails app I want to combine several models into a single activity feed.
For example, I have Post, Comment, Photo, Status models. Each one belongs to a User, an Institution, and a City. On a User/Institution/City show page I want to display a chronological list of the latest activity.
From reading around and from other questions on SO, there appear to be two schools of thought on this.
Create a polymorphic ActivityFeed model where e.g. a User has_many :posts as: feedable. Then render the ActivityFeed collection on the respective show pages.
Create and render a combined array e.g. #user_feed = #user_photos + #user_comment +..
But I haven't seen much discussing the pros and cons of each approach.
Has any one else attempted something similar? What issues should I be thinking about or planning for in choosing an approach? How well do each perform (especially as the database gets larger)?
My requirements are:
To display all items that belong to the parent model.
To have several different types of parent model (User, Institution, City, etc).
To render a different view partial for each item in the activity feed, depending on its class.
Grateful for any thoughts, personal experiences, or pointers to further information on this. Should I be looking for a third option? I'm particularly interested in the performance of creating a combined array from several queries.
Thanks

Let me add a few more issues to your requirements
ease of display all items belonging to parent model
ease of allowing for different types of parent model
ease of class-dependent template rendering
ease of refactoring shared activity functionality
ease of integrating potential activity control functionality (mark as read, subscribe, follow, share etc)
ease of calculating polymorphic feed, say in reverse chronological order of activities of various types.
ease of calculating aggregated activity count on a parent
For me 5 and 6 and 7 defo tips it in favour of the first option, my code would be:
class Activity
belongs_to :activity, polymorphic: true
belongs_to :user, counter_cache: true
belongs_to :institution, counter_cache: true
belongs_to :city, counter_cache: true
end
your scope for city newsfeed (demonstrating 1,2,6)
city.activities.order('updated_at DESC').limit(20)
note that this is a cheap search on one table only that can already give you enough for a quick list since association loading (would be .includes(:activities)) is not necessary to display something like.
Joe from NYU, New York has posted a comment
Mel from UCL, London has added a new photo
4 is trivial if activity is a separate class and 5 also smooth with standard activity controller. for shared rendering partials like the quicklist views/activities will be a natural place.
7 is easily done with the counter_cache.
as a bonus, by allowing has_many :activities on each type, you could distinguish types of activities, like create, update, read, etc.
hope this helps

Related

database design for composite elements

I'm building a site that tracks donations and sales of items in a school auction.
Items can be sold individually or in lots, which are just groups of items bundled for sale as a single unit (like a gift certificate for a dinner Item bundled with a gift certificate for movie tickets Item).
Both of these things (Items and Lots) share fields like name, description, value. But Items have additional fields, like the donor, restrictions of use, type of item, etc.
I started by creating a table called Lot and an association table that lets Lots contain 1+ Items.
That works great for Lots. But that leaves me with a problem:
When Buyers win I need to record the win and the price. I'm doing that with a Win table that associates the Buyer with the Lot and the winning price.
But how do I deal with all the Items that aren't assigned to Lots? Should every item be in a Lot, just singly? That would make sense because it would work with the Win table scheme above, but I would need to automatically create a Lot for every Item that isn't already in another Lot. Which seems weird.
I'm sure this is a simple problem, but I can't figure it out!
Thanks!
Your approach of treating every item as a lot should be the winning one. It may sound weird, but it will make things way easier in the long run.
I have to deal on a daily base with a database where a similar problem was 'solved' the other way round, meaning keeping bundles of items and items apart and that proved to be a great pita (and for sure I'm not talking about a flat round bread here).
This database is both backbone for statistical evaluations and a bunch of (web) applications and on countless occasions I run into trouble when deciding which table to chose or how to level the differences between those two groups in querying and in coding.
So, even if your project will be rather small eventually, that is a good idea.
Yes, you need to provide a method to put every item in a lot, but this trouble is to be taken just once. On the other hand your queries wouldn't become significantly more complex because of that 'extra' table, so I'd definitely would chose this way.
It sounds like you have an Auction model that could have one or many Items. Then you could have two different types of Auctions, Auction::Single and Auction::Lot. Price would be a column on Auction. Auction has many Bids which is a join model between the Auction and the User (or Bidder). That join model would also store the bid price. When the Auction is over, you could create a separate Win record if you want, or just find the Winner through the highest Bid from Auction.
It would be helpful if you showed some code. But, what you want is a polymorphic association. So, something like:
class Item
has_one :win, as: :winnable
belongs_to :lot
end
class Lot
has_one :win, as: :winnable
has_many :items
end
class Win
belongs_to :buyer
belongs_to :winnable, polymorphic: true
end

Model/Association Design For New Rails Application

I'm about to start building an application in Rails (just started learning Rails, so figured this would be a good, basic exercise) and wanted to solicit some feedback on how to architect my models and associations. The application is designed to host a "game" in which users guess what songs they think will be played at a given concert each show the band plays. So far, I have the following models (with approximate attributes):
User: keep track of active users (user_name, user_password, user_email, etc.)
Submission: keep track of a given user's guess for a given show (date_of_show, guess_1, guess_2, guess_3, user_id)
Show: keep track of each show the band plays (date_of_show, songs_played)
Song: keep track of band's current catalog (song_name)
The relationship between User and Submission is pretty straightforward:
class User < ActiveRecord::Base
has_many :submissions
end
class Submission < ActiveRecord::Base
belongs_to :user
end
When it comes to the relationships between the other pieces though, things become a bit more unclear, so I have the following questions:
Each Submission corresponds to one Show. Does it make sense to say that each Submission belongs_to a Show and each Show has_many Submissions using date_of_show as the key?
Is it necessary to have a Song model at all? In the initial version of the application, it will simply be used as a list to validate guesses (i.e.; populate a select drop down).
If I should keep the Song model, how do I associate that with the other models? A User doesn't have a song, so that one's easy, but each Submission has three Songs and each Show can have a varying number of Songs.
On the point of each Show having a varying number of Songs, is the best way to approach this to store them in an array, ala this post (http://amberonrails.com/storing-arrays-in-a-database-field-w-rails-activerecord/) or is there a better way? Ultimately, I will need to implement some method that loops through each Submission, check guess_1, guess_2, and guess_3 against the songs_played array (or whatever other alternative I use) in the Show model, and produce a score.
For the first steps, design your application like the real life. When you have more experience, you can drop some models, simulate others for some optimization.
In real life, how to design a show ? It's a band playing songs. How to design a band ? It's a set of people (not used here) having songs. How to design a submission ? It's a user thinking a song is played at a time.
Then, you can have theses models :
User (name...)
Song (name, band_id) : belongs_to a band and have many show_songs
Band (name) : has_many songs and has_many shows
Show (band_id) : belongs_to band
ShowSong (show_id, song_id, datetime) : belongs_to show and song
Submission (user_id, song_id, show_song_id) : belongs_to song and show_song
It's not a unique solution, you can design what you want.
I design theses models from some Rails practices:
Don't use date_of_show as a key, use an _id (that's why I insert show_song)
It's necessary to have a model when model have specific methods or must be registered in database
don't use guess_1, guess_2, ... Use an have_many guesses

How best to model reservation/appointments database in Rails

I'm looking to write some sort of Rails app to help users book time slots at a restaurant. How can this be modeled in such a way so that it can be reservations can be displayed and booked through the browser? I have two models:
class Restaurant < ActiveRecord::Base
has_many :reservations
class Reservation < ActiveRecord::Base
belongs_to :restaurant
attr_accessible :name, :date, :time
At first I toyed with a using a hash within the Restaurant model to store availability, using dates as keys. But then I realized that Rails databases must serialize hashes, and I'd like to make sure there isn't a better way to go about this before I dive into that stuff.
I'm using Postgres (if that's relevant). Any help would be much appreciated!
Your basic model structure is fine. Note that attr_accessible is not current best practices, as of Rails 4. (It has been replaced by strong parameters)
Doesn't matter too much about what database you are using (even though PG is a solid choice) but the general engineering that is truly important.
I won't give you a copy paste answer but hopefully give you some direction.
So a Restaurant can have many Reservations throughout the day. I assume each restaurant can only hold so many people and thus have some type of "reservation limit" and Reservations cannot overlap.
Because of the constraints I imagine your 2 model method will work. You just need to figure out exactly how they must interact to work as you plan.
Restaurants should be able to keep track of open times/vacancies (or whatever important details). While Reservations will keep track of the number of people in the party, time, etc.
Your initial relationship looks to be well defined. But the other answer does correctly point out the new Rails 4 preferred method.

Is STI appropriate if model can be multiple subclasses at the same time?

When is the correct time to use STI in a Rails app? After a lot of reading (including this excellent Railscast) I'm still unsure what is the best approach for my needs.
This (contrived) example illustrates my dilemma.
Lets say a User class could categorized in several sub-classes, including Doctors and Patients. These are more than simple roles, with key data and logic differences.
A Doctor has certain database fields (e.g., qualification, speciality), certain view logic (e.g. if User.doctor? then display list of patients), and certain logic and roles (e.g. can manage patient records).
A Patient has different database fields (e.g., blood type), view logic (e.g. if User.patient? then display list of treatments), and logic (e.g. can edit appointments).
Both Doctors and Patients have :username, :email, :password fields in common, as well as a considerable amount of logic throughout the remainder of the app (e.g., User has_many :comments, :messages, etc ).
From my reading, the fact that Patients and Doctors have different logic requirements suggests STI may be appropriate. But with different database fields, polymorphic may be a better approach.
BUT....
A User may be both a Doctor and a Patient simultaneously.
Is there a "best approach" to this problem?
STI uses a single column to determine the object's type.
At first glance this would indicate you'd need to have User, Doctor, Patient, and DoctorPatient classes, which to me, seems a little loopy. It could potentially get even loopier if other types are added.
Moving Doctor, Patient, etc. functionality into another class (and table) seems like it'd make more sense, without knowing anything more, but other folks may have more useful input.

Blog architecture design

I'm teaching myself rails, and want to build a blog similar to tumblr. It will have a couple different post types, such as written text, photo posts, audio posts, and video posts.
My initial thought was to have different models for each type of post, since there will be different rules for each type of post. However, I'm still learning and don't know what I don't know, so maybe there is a better way to go about things (maybe only one model for posts, and a table for post types?).
Any feedback would be appreciated.
Probably a good relational database and object oriented design would be to have one main post model, which will probably share mostly same attributes and behaviors with all the types of posts. This could even act as your "text" type posts.
This could also simplify relationships with the posts also (eg. "users has many posts" vs "users has many text posts and/or video posts and/or etc").
Then have a sort of "attachments" join table, which determines the type of attachment (so you can have multiple attachments per post):
CREATE TABLE attachments (post_id, media_type, media_id)
Then have a table and model for each type for specific behaviors and handlers for the media types.
CREATE TABLE audios (id, transcription, storage);
CREATE TABLE videos (id, location, format, storage);
This will probably require some sort of polymorphic relationship, though, which could be a debatable DB design... you'll need views and triggers to query easily and maintain integrity... but Rails handles it quite well.
The post model would have
has_many :attachments
and attachments would have
belongs_to :post
belongs_to :media, :polymorphic => true
and each of the media model would have
has_one :attachment, :as => :media
then you can access your media via
post.attachments[0].media
You can skip the attachments table and merge the attributes with the posts table if you only need one type of media per post
Sorry i keep editing, i keep thinking of more things to to say :)
Here's a couple of options that could work.
First, you could just make one Model with columns for text_content, video_link, photo_link, etc.
Then in your view, you could render the post's view to the user (probably using a partial) with a different look depending on which attributes have values.
A second option would be to make a smaller Post table that just had key information and use a series of 'has_one' relationships to the other items.
The only advantage I see to the second option is that your DB table would be smaller since you don't have to represent the null cells over and over. Unless your worried about some huge scaling issues, I'd go with the 1st option though.

Resources