Database schema - polymorphic association vs separate tables - ruby-on-rails

Users have many tasks. (tasks.user_id = user_id)
tasks have many tags (implemented through Acts as taggable on
Users have many lists -> which have many tasks (A list is just a wrapper for multiple tags, for example {List id => 1, name => "shopping vacation summer"} will retrieve all tasks tagged with all of those tags)
If, for example, a user goes to the url tags/shopping%20vacation, my code would do a lookup for:
Task.all.tagged_with(["shopping", "vacation"])
There is no Lookup table or foreign key for task.list_id
I want users to be able to share tasks, lists, and tags with other users.
A user sharing a task shares just that task with another user.
A user sharing a list opens up all the tasks in that list to another user.
A user sharing a tag opens all of that users tasks tagged with that tag to another user.
To me, there are a few options, and I'd like some input on the pluses and minuses of each that I may not have thought about.
One is a distinct table for each shareable item:
shared_tasks: task_id, shared_to_id(or user_id)
shared_lists: list_id, shared_to_id
shared_tags: tag_id, shared_to_id
OR: a polymorphic association with
shareables: shared_id(item_to_share), shared_to_id, shared_type
What are the pluses and minuses of each?
Is there another solution that I haven't thought of?

Personally I would change the schema design. Taking Tasks as an example i would now treat it as a many-to-many relationship with User instead of many-to-1 as it is currently. So this would mean removing column tasks.UserId and adding a new table called UserTasks which links Tasks with Users defined as (UserId, TaskId, IsOwner). IsOwner is set to 1 for the user who the task belongs to and 0 if it is shared but belongs to someone else. This will make queries easier for example you could do do a single select to get both owned and shared tasks rather than 2 separate queries and also avoid union's.

Related

Sort by timestamp on has_many after scope

I have a User object, a Package object (User has_many packages) and then a LocationTracker (User has_many location_trackers), which acts as a join table between User and Package, but just tracks details such as the most recent package delivery.
I'd like to sort my Users based on the most recent package they sent. The LocationTracker has an attribute last_received_from_user
I can easily sort the users from a certain location by ordering by the last_received_from_user attribute, however I'd also like to have a global index page that shows all of the Users, sorted by the last package they delivered.
I'm having trouble grouping the users. I'm attempting to use a DISTINCT ON(last_received_from_user), but then it complains that the attribute isn't in the group, and when I add it to the group, it groups by that timestamp, which is obviously pretty unique, so I get duplicate users showing up.
My current code is as follows:
User.includes(:location_trackers)
.group("location_trackers.user_id, users.id")
.order("location_trackers.last_received_from_user #{order} NULLS LAST")
Any help is greatly appreciated!
EDIT:
I've got the last_received_from_user which allows me to sort users from a SINGLE location well. However, I need to be able to scope based on what could be a number of different options. For example, only show users in a certain area (Which could be compromised of a few locations), or order by ALL users for ALL locations. The attribute works great for a single user-location relationship, but fails when it comes to attempting to perform the search on more than 1 location.
I'd like to sort my Users based on the most recent package they sent
Wouldn't it be easier (and way more efficient) having an attribute like latest_delivery_location and using a callback on the User model like:
class User < ApplicationRecord
after_update :update_latest_delivery_location
private
def update_latest_delivery_location
update_attributes(
latest_delivery_location: location_trackers.last.last_received_from_user
)
end
end
Or updating such attribute after an order has been placed / dispatched. I'd go for this approach because is easier to maintain and, if you want it more performing you could always add an index on users.latest_delivery_location for sorting operations.

Octopus gem dynamically select shard for an associated model based on shard_id

We have a users table. Users have many listings.
We'd like to shard the association model Listing such that all users stay on database "master" shard. Users will get a shard_id column and listings will be split into different databases "shard1", "shard2".
We can augment our code to access the listings on the correct shard using the using method:
Listing.where(user: current_user).using(current_user.shard_id)
However that is a big code change. Ideally we want to just keep using our existing association statements like this:
current_user.listings
And have it automatically use current_user.shard_id beneath the hood.
Any suggestions for doing this?
According to the documentation, current_user.listings should work out of the box.
Octopus also handles associations. When you try to get a object that is associated to another object, you could use normal ActiveRecord syntax to get the objects
https://github.com/thiagopradi/octopus/wiki/How-Octopus-Works

Polymorphic join table and nested forms

I don't know what's the best way to solve this problem and I'll appreciate your help.
This is what I want to achieve:
There is an Act model. And it has many Organizations.
An Organization can have many Groups and also, a Group can have many Subgroups.
The Groups are loaded dynamically depending on the selected Organization, and the Subgroups are also loaded depending on the selected Group.
An Organization could have a Group or not, and also a Group could have a Subgroupor not
Here you are a mock-up of what I have explained above:
In the new Act form there is a section to add Organizations, something like this:
When you write an Organization it loads the options for the Group selector, and the same happens with a selected Group and the Subgroup selector:
When you click the add button, a new Organization section appears
A field can be empty. (This is a valid form)
Also, If you want to edit the Act, the form should show the Organizations added before:
I have this DB:
ActOrganizations is a polymorphic table, and also a join table
My main problems are about the form: how to build it to retrieve and persist the data easily and how to retrieve the stored Organizations to show them in the edit form. (I'm using simple-form)
I tried many approaches, but they were not very elegant. I'd like to know the closest way to the "rails-way" to do this.
Thank you very much for your time

Rails country/state listings

I am in the process of creating an application with Rails, what I am trying to do is have each user, upon registration, select 1 country, and 1 state within the country they are associated with. I know I can create classes like Country, and State and use belongs_to, has_many associations. But how would I be able to list all countries/states in a form and how would I map together a specific country/state name to that one user?
Thanks in advance!
Sounds like a job for Carmen.
No need to reinvent the wheel; it supplies the lists of countries and subregions so you don't have to manage them. The documentation also includes sample code for displaying the country-appropriate subregions (states) via JavaScript.
grouped select, example specifies exactly what you need:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-grouped_collection_select

rails 3 associations with join table query using active record

I have three models which are User, Domain and Association. My user model is populated from devise. My Domain model consists of "People's interests such as - running, biking etc". My association table links a user_id to a domain_id and stores it as a record. When I add a domain it automatically populates the user sign up form with domain's (in which a user can pick e.g. I like running).
My Query is.. What active record query could I use to pull user's with the similar interests e.g. running, with the currently logged on user. So if a user called Tom was logged in and had select domain interests of running and biking (linked to), how could I pull back a database object with other users that had the similar domain's (interests)
So basically if Tom, Paul and Steph were users, but Tom and Paul selected the same domain's and Steph selected different ones, what would be the Query code to do this? Hope this is enough information.
I think you could do something like this:
User.joins(:domains).where("domains.id IN (?)", current_user.domains.pluck(:domain_id))
current_user.domains.pluck(:domain_id) collects all the domain ids that the current_user has selected. Pluck is only in rails 3.2, if you're using an earlier version, you'll have to use collect instead.
Then the first part of the query selects the users who also have that domain as one of their interests.
You should look at the rails guide as Bongs suggests
http://guides.rubyonrails.org/association_basics.html

Resources