Rails joins with select issue - ruby-on-rails

I am trying to follow the mantra of "select only what you need" when making database calls in my rails applications. Currently I am eager loading all users against their posts, however I notice that this selects every column from the user table for each users.
I have tried to use a join instead which offers a much easier way to select what specific attributes I need, however I am using paperclip and the user has_attached_file. I currently haven't found a way to include this in the join.
I was just wondering if anyone had any suggestions or tips on what the best way to load both users and posts is in terms of database performance?
Currently to retrieve users I am simply using this sort of syntax:
Post.all.includes(:user)

Have you tried Post.eager_load(:user)? Should fetch all the Post fields and all the User fields in a single query, and instantiate AR objects for each. Paperclip attachment would be stored in the user table under 4-5 fields starting with the same prefix. Those should be loaded through Post.eager_load(:user).
The only reason this wouldn't work is if the association between Post and User is polymorphic.

Related

Tracable anonymous recurring records

I have an application where users fill out surveys on a regular basis.
Surveys are sent via e-mail and need to be semi-tracable, meaning, that I need to follow what kind of question categories are sent to each user on each survey. Right now after answering the survey, answers are saved in a separate table and any association to a particular user is removed to guarantee anonymity.
What I would like to achieve is a way where it is not possible to map any anwser with a particular user BUT it is possible to get all answers that any one user has submitted. We want to do this for analysis purposes to track how user's answers change over time, but at the same time preserve complete anonymity on a database level.
Users fill out surveys using several devices so private key storing on their device is not an option.
Application is written in Rails with PostgreSQL, but the solution can also involve other languages if it is not possible in ruby.
One of the simple solutions would be feeding a fixed set of user data to a hash function to calculate an identifier for that user, save it into the separate table along with the answers.
This way you'll be able to gather all submissions per user but there will be no relation to the user record.
A drawback is that if you would still want it you can trace a user by calculating all the hashes for your "users" table and associating it with the "answers" table. Unless you give up control over either "users" or "answers" entity to another team/business unit etc.

How do I model my Rails application where users search for events and save the ones that interest them?

I am using three models:
- users
- events
- user_events (the join table)
I feel like I do not need to save every search result because it would be unnecessary. The search will query two APIs and display maybe the top 10 results and display them to the user. The user then might be interested in one or two of these events and add them to a list of things that interest them, a bookmark, if you may. Bookmarks that are happening on the same day should then be grouped together for the users organizational purposes.
Should I make another search model along with a search controller? I'm fairly new to Rails and need some advice on this topic.
I would advise you make a bookmark or search class to store a search when a user wants to save it. Then you can construct a has_many relationship between a user and a bookmark. So a user will have many bookmarks. See this for more documentation: http://guides.rubyonrails.org/association_basics.html#the-has-many-association

Modeling an inbox in Rails

I'm writing an app that allows users to feed their inbox, then process their input, making it either a note or a task.
Since I need notes and tasks to behave very differently, I plan on using different models for them.
The question is: how do I go about changing inbox items into notes or tasks?
My first idea was to write an action that would destroy an inbox item and call the create action on the notes (or tasks) controller, but that does not seem right.
Is there a better way to do this?
Update
I'm looking into polymorphic associations as a solution for this, as suggested by #Dipak.
This is my schema: (sorry I can't paste the code. I'm using a web based ssh tool)
I have decided to use the Idea model to define inbox items
And these are my models:
I want to be able to click this link (on my partial)
and have it do two things:
create a task
assign this task to idea.thought
How should I do this? Is this the proper way to use this kind of association?
As per your question it seems like your few initial fields are same for all notes and tasks, that you calling inbox. So better you can save those fields in different table and other fields in related table.
For such situation you should use polymorphic association. You can read about it here. So your new inbox table should be intermediate table used for polymorphic association.

What is the best way to store a user's Facebook friends list in my database?

Overview
I'm creating a Ruby on Rails website which uses Facebook to login.
For each user I have a database entry which stores their Facebook User ID along with other basic information.
I'm also using the Koala gem in order to retrieve a user's friendlist from Facebook, but I'm unsure as to how I should store this data...
Option 1
I could store the user's friends as a serialized hash in the User table, then if I wanted to display a list of all the current user's friends, I could grab this hash and do something along the lines of SELECT FROM Users WHERE facebook_user_id IN hash
Each time the user logs in I could update this field to store the latest friends list.
Option 2
I could create a Friend table and store friendship information in here, where a User has many Friends. So there would be a row for each friendship, (User1 and User2 columns). Then to display a list of the current user's friends I could do something like SELECT User2 FROM Friends WHERE User1 = current_user
This seems like the better option to me, but...
It has the disadvantage that there would be many rows... If there were 100,000 users, each with 100 friends, that's now 10,000,000 rows in the Friends table.
It also means each time the user logs in, I'd need to loop over their Facebook friends list returned using Koala and create a Friend record if someone on their friendlist is in my User table and there isn't a corresponding entry in the Friends table. This seems like it'd be slow if a user has 1000 Facebook friends?
I'd appreciate any guidance on how it would be best to achieve this.
Apologies for the badly worded question, I'll try and reword/organise it shortly.
Thanks for any help in advance.
If you need to store a lot of data, then you need to store a lot of data. If you are like most, you probably won't run into that problem sooner than you have the cash to solve it. In other words, you are probably assuming you'll have more traffic and data than you'll get, at least in the short-term. So I doubt this is an issue, even though it is a good sign that you are thinking about it now rather than later.
As I mentioned in my comment below, the easiest solution is to have a tie table with a row for each side of the friend relationship (a has_many :friends, through: :facebook_friend_relationships, class_name: 'FacebookFriend' on FacebookFriend, per the design mentioned below). But your question seemed to be about how to reduce the number of records, so that is what the remainder of the answer will address.
If you have to store in the DB and you know for sure that you will absolutely have every FB user on the planet hitting your site because it is so awesome, but they won't all hit at once, then if you are limited in storage, you may want to use a LRU algorithm (remove the least recently used records) possibly with timed expiration also. You could just have a cron job that does a query on the DB then deletes old/unused records to do this. Wouldn't be perfect, but it would be a simple solution.
You could also archive older data rather than throw it away. So, frequently used data could stay in the table of active users, and then you might offload older data to another table or even another database (and you might see the apartment and second_base gems for that). However, once you get to the size, you're probably looking at a number of other architectural solutions that have much less to do with ActiveRecord models/associations or schema design. Though it pays to plan ahead, I wouldn't worry about that excessively until you are sure that the application will get enough users to invest the time in that.
Even though ActiveRecord has some caching, you could just avoid the DB and cache friends in memory yourself in the beginning for speed, especially if you don't yet have many users, which you probably don't yet. If you think you'll run out of memory because of the high number of users, LRU might be a good option here also, and lru_redux looks interesting. Again, you might want to time the cache also so expires and re-gets friends when the cache expires. Even just storing the results in the user session may be adequate, i.e. in the controller action method, just do #friends ||= Something.find_friends(fb_user_id), and the latter is what most might do as a first shot at it while you're getting started.
If you use ActiveRecord, in your query in the controller (or on the association in the model) consider using include: to avoid n+1 queries. That will speed up things.
For the schema design, maybe:
User - users table with email and authN info. Look at the Devise gem.
FacebookUser - info about the Facebook user.
FacebookFriendRelationship - a tie model with (id and) two columns, one for one FacebookUser id and one for the other.
By separating the authN info (User) from the FB data (FacebookUser and FacebookFriendRelationship), you make it easier to have other social media accounts, etc. each with information specific to those accounts in other tables.
The complexity comes in FacebookUser's relationship with friends if the goal is to minimize rows in the relationship table. To half the number of rows, you'd have a single row for a relationship where the id of FacebookUser could be in either foreign key column. Either the user has a friend or is a friend, so you could have two has_many :through associations on FacebookFriend that each use a different foreign key in FacebookFriendRelationship. Or you could do HABTM without the model and use foreign_key and association_foreign_key options in each association. Either way, you could add a method to add both associations together (because they are arrays). Instead, you could use custom SQL in a single has_many if you didn't care about having to use ActiveRecord to remove associations the normal way. However, per your comments, I think you want to avoid this complexity, and I agree with you, unless you really must limit the number of relationship rows. However, it isn't the number of tie table rows that will eat the data, it is going to be all of the user info you keep in the FacebookFriends table.

Rails: Multiple databases, same schema

I'm in the middle of a fictional scenario project where I have allowed multiple users for a company to log in, create records, and so on, who all connect to the one database. They can all records absence records, attendance records, and so on.
What I want to do however, is use this same schema but expands this to allow several companies to have their own databases using the same schema. So each company will have their own data, but all companies use the same data model. In other words all company's can create absence records, but they each only have access to their own absence records that they created themselves.
How can I achieve this?
All I need is two or three files for this, I'm not going commercial with it in case you guys think I'm cutting corners at someone else's expense!
Something as simple as an if-else that decides which file to use would be very useful to me, so if such a line of code exists please let me know.
I think you are doing it wrong (unless you have a really good reason to have a database for each company), because it seems like you are repeating your data model over and over while introducing unnecessary complexity to your code.
Try to have all the companies in one DB/tables with having separated by the company_id.
Ex: data structure would be as follows
companies table
id
name
users table
id
user_name
company_id
However if you really want to connect to multiple databases, check this SO question.

Resources