Database record containing multiple entries in one column - ruby-on-rails

I am working on a web app written in rails. It is currently running on heroku with a postgres database.
I am supposed to add a feature where users may enter up to three codes for each one of the user's students. The codes themselves are irrelevant, they are simply strings that will be entered into the database.
This brings me to my dilemma. I am unsure of how to best store the codes in terms of their relationship to the student table. My original thought was to use the rails method serialize to store up to three codes in an array, but I have read that more often than not, storing data in an array in a database is not what you want to do.
Should I create a new table "codes" and set up a has_many relationship with the "students" table? Or is there a more preferable away to set up this relationship?

Given your situation, this sounds like the most reasonable approach to have a Code model and then setup has_many association with Student model.
student has_many codes and
code belongs_to student.

Related

One-to-one relationship with variable case string keys in Rails

Working with legacy database here, can't change the tables.
Have two tables. Lets say User and Admin. They both have user_id which is a string, and the case varies between the tables. I can pull out records by doing donwcase but its a manual query with no fancy ActiveRecord assosiation goods
How can I connect the two models?
I know that you can supply lambda to has_one and belongs_to, except it is used to narrow down the search, not to replace the AR generated one.
I am considering creating views on those tables and lowering the user_id in them. That could work if I dont figure out how to get this going

Postgres: Many-to-many vs. multiple columns vs. array column

I need help designing complex user permissions within a Postgres database. In my Rails app, each user will be able to access a unique set of features. In other words, there are no pre-defined "roles" that determine which features a user can access.
In almost every controller/view, the app will check whether or not the current user has access to different features. Ideally, the app will provide ~100 different features and will support 500k+ users.
At the moment, I am considering three different options (but welcome alternatives!) and would like to know which option offers the best performance. Thank you in advance for any help/suggestions.
Option 1: Many-to-many relationship
By constructing a many-to-many relationship between the User table and a Feature table, the app could check whether a user has access to a given feature by querying the join table.
E.g., if there is a record in the join table that connects user1 and feature1, then user1 has access to feature1.
Option 2: Multiple columns
The app could represent each feature as a boolean column on the User table. This would avoid querying multiple tables to check permissions.
E.g., if user1.has_feature1 is true, then user1 has access to feature1.
Option 3: Array column
The app could store features as strings in a (GIN-indexed?) array column on the User table. Then, to check whether a user has access to a feature, it would search the array column for the given feature.
E.g., if user1.features.include? 'feature1' is true, then user1 has access to feature1.
Many-to-many relationships are the only viable option here. There is a reason why they call it a relational database.
Why?
Joins are actually not that expensive.
Multiple columns - The number of columns in your tables will be ludicris and it will be true developer hell. As each feature adds a migration the amount of churn in your codebase will be silly.
Array column - Using an array column may seem like an attractive alternative until you realize that its actually just a marginal improvement over stuffing things into a comma seperated string. you have no referential integrety and none of the code organization benefits that come from have having models that represent the entities in your application.
Oh and every time a feature is yanked you have to update every one of those 500k+ users. VS just using CASCADE.
class Feature
has_many :user_features
has_many :users, through: :user_features
end
class UserFeature
belongs_to :user
belongs_to :feature
end
class User
has_many :user_features
has_many :features, through: :user_features
def has_feature?(name)
features.exist?(name: name)
end
end

achieve habtm on single model in rails

I have a problem with habtm on a single model in rails.
Example:
Let us say i have a User model with two roles "Student" and "teacher". User model is common for two roles. Now
Each student can be associated to many teachers
Each teacher can be associated to many students
In rails notation, their should be habtm between teacher and student
How this can be achieved with single table.
Thanks,
Aashish
It can't be done with a single table. In a many-to-many relationship, no matter what, you always need a table where you store the associations.
In your case, given the association seems to be parent/child, then you just need two tables instead of one.
How to implement it, it depends on your database structure and data organization. You should create an users_users table (as part of the habtm) and configure the references accordingly. If the user table, as it seems to be, is also used for STI, then the configuration may change a little bit.

rails 3, multiple database connections and setting up models

When working with multiple database connections and setting up models to work with those different instances, how do you setup the has_many, has_one, belongs_to, etc?
For example:
I have one database that is Read + Write, the other DB instance is used in my Rails app as Read only. The DB table that is Read only I am pulling back a list of Media items (Videos, Images and Audios). In my Read + Write DB I have a media_ratings table.
I have a model called AvMedia (The Read only DB) and a MediaRating Model (Read + Write DB). How do I setup The AvMedia model like so: has_one rating and setup the MediaRating model like so: has_many AvMedia?
Sorry if this is confusing... I tried to explain it the best I could.
In the AvMedia model you must include has_one :rating and just make sure that in the corresponding table you have a rating_id foreign key. You also need belongs_to :avmedia in your rating model.
A lot of magic goes on behind the scenes to automatically link your tables together when you define a relationship.
It sounds like you don't need the has_many for AvMedia - from what you said it appears that it's a 1-1 relationship (one AvMedia has one rating, one rating corresponds with one AvMedia). If this is incorrect, let me know.

Rails ActiveRecord Relationships

How do the relationships magically function when only the models are altered?
If I want a "has__and___belongs___to__many" relationship, what should I name the table (so Rails can use it) that contains the two foreign keys?
Short answer: You can't just tell the models that they're related; there have to be columns in the database for it too.
When you set up related models, Rails assumes you've followed a convention which allows it to find the things you wrote. Here's what happens:
You set up the tables.
Following conventions in Rails, you name the table in a particular, predictable way (a plural noun, e.g. people). In this table, when you have a relationship to another table, you have to create that column and name it in another predictable way (e.g. bank_account_id, if you're relating to the bank_accounts table).
You write a model class inheriting from ActiveRecord::Base
class Person < ActiveRecord::Base
When you instantiate one of these models, the ActiveRecord::Base constructor looks at the name of the class, converts it to lowercase and pluralizes it. Here, by reading Person, it yields people, the name of the table we created earlier. Now ActiveRecord knows where to get all the information about a person, and it can read the SQL output to figure out what the columns are.
You add relationships to the model: has_many, belongs_to or has_one.
When you type something like, has_many :bank_accounts, it assumes a few things:
The name of the model that you relate to is BankAccount (from camel-casing :bank_accounts).
The name of the column in the people table which refers to a bank account is bank_account_id (from singularizing :bank_accounts).
Since the relationship is has_many, ActiveRecord knows to give you methods like john.bank_accounts, using plural names for things.
Putting all of that together, ActiveRecord knows how to make SQL queries that will give you a person's bank accounts. It knows where to find everything, because you followed a naming convention that it understands when you created the table and its colums.
One of the neat things about Ruby is that you can run methods on a whole class, and those methods can add other methods to a class. That's exactly what has_many and friends are doing.
This works because you are following "Convention over Configuration".
If you state that a customer model has many orders then rails expects there to be a customer_id field on the orders table.
If you have followed these conventions then rails will use them and will be able to build the necessary SQL to find all the orders for a given customer.
If you look at the development.log file when you are developing your application you will be able to see the necessary SQL being built to select all orders for a given customer.
Rails does not create tables without you asking it to. The creation of tables is achieved by generating a migration which will create/alter tables for you. The fact that you create a customer model and then state within it that it has_many :orders will not create you an orders table. You will need to do that for yourself within a migration to create an orders table. Within that migration you will need to either add a customer_id column or use the belongs_to: customer statement to get the customer_id field added to the orders table.
The rails guide for this is pretty useful

Resources