Validate many-to-many circle - ruby-on-rails

I have this object association here:
Entry *--1 Category *--1 Project *--* User 1--* Entry
Explanation: An entry belongs to a category which has many entries, a category belongs to a project which has many categories - many users can have many projects. This user also has many entries and one entry belongs to one user.
When an entry is saved with a category and user association, I want to make sure, that the category belongs to a project a user is assigned to.
I thought about implementing a custom validator that fetches the project of the worklog and checks if it's in the list of the user's projects.
Is there a more Rails-like way to it or am I on the right track?

Related

rails when/how to use nested resources

I have a rails app. Users can create products that will be listed on products index page (including some data about the user who posted it) and everybody can see the list on app/products.html.
What is the best way to implement this? Should I do it with nested resources (user has many products) in which case I can use product.user.name for displaying the user name or should I create an independent class so when user creates a product, some user attributes (name, etc.) will get saved in the product table.
Your mixing together quite a few different concepts here.
Nested routes
In REST you have a concept of nested resources which is expressed though URIs such as:
posts/:post_id/comments # comment that belong to a resource.
Which tells us that there is a "has many" relation between post and comments.
The best practice here is that:
Don't nest if you don't need to.
Never nest more than 1 level deep. posts/:post_id/comments/:comment_id/replies for example should be comments/:comment_id/replies.
Associations and domain modeling
Domain modeling on the other hand is how your models fit together. In ActiveRecord each model class is backed by a database table.
Each model should correspond to a single type of object in your problem domain. So in your case you would have a User class and Products class.
They would be linked by a products.user_id column. So no - you should not store users attributes in the products table.

Core Data: Handling multiple profiles that can customize a prepopulated, static sql db?

Say I have an app that allows you to create a simple profile within core data that'll have different user attributes like name, sex, age, etc. This entity Profile is created and saved. Upon diving into the profile, a table view is presented of cars with data that's been generated from an imported sql database which was created using a utility app that prepopulated data using a core data model. Each Car has various attributes as well, such as make, model, year, color, etc.
Say I want to be able to click on each car in this tableview and select the field. While doing so, I want a variable isSelected to be set to 1 in order to keep track of which cars in this database have been selected by the user.
So far this would be simple to do using a single Profile with a to-many relationship: Profile <-->> Car.
Problem
The issue I'm having is doing the above with multiple profiles.
Model is setup like Profile <<-->> Car -
With multiple profiles, I can't figure out how to keep the imported sql database static (because this is the base data that every new profile will start out with) and then have another database or entity or something else i'm not thinking of with the isSelected = 1 or 0 attribute for each Car.
At first I thought I could just create a copy of each Car by doing this:
Profile *_currentProfile;
for (loop through all cars in the db) {
Car *copiedCar = [NSEntityDescription insertNewObjectForEntityForName:#"Car" inManagedObjectContext:self.appDelegate.managedObjectContext];
copiedCar.make = originalCar.make;
copiedCar.model = originalCar.model;
...
[_currentProfile addCarObject:copiedCar];
}
I thought this would allow me to create a copy of each Car and put it into the current Profile and modify the isSelected attribute without affecting the original database. This could then allow more profiles to be made without them interfering with each other. The problem occurred when other profiles began doing fetch requests for the Cars. The fetch request from subsequent profiles which generate 2x, 3x, .., the number of available Cars depending on the number of profiles created, because each created profile would essentially generate another full list of Cars
Question
So my model is a bit more complex than this Car example above, but the idea is the same.. how should I structure the Core Data model to allow for multiple profiles to customize an existing core data sql database without the multiple customizations interfering with each Profile? There will be no log out / in function in this. The profiles will be on the main screen and you just select the one you wish to enter. Should I:
have separate sql databases for each profile created?
would a core data structure like this work: Profile <<-->> Car <-->> Custom
With the isSelected attribute in the Custom entity?
something else I'm not thinking of...
I tried doing the first two, but I'm just not doing something right and got myself so confused.
If your cars have a relationship to profiles, then using those relationships changes the original data - so you can't just replace it (though you could run an update on the data).
If you want to keep the source data pristine such that you could delete all of the cars and replace them with other data then you would need to give each a unique identifier and then update the profiles with a list of identifiers. But, any update to the cars would still require them to retain the same identifiers.
So, all cars should have a unique identifier, and you should use many-many relationships. And you should get rid of any isSelected flags (because the relationships embody that information). The unique identifiers allow you to update the cars in the future without it mattering that they have relationships to profiles.
If your real problem is that each profile wants to change the car instances that it's connected to, then you should create a new entity which has a relationship to the car and profile entities (and which could replace the direct relationship between car and profile). That entity holds attributes that add to or override the car attributes. This new entity can be associated with only one car and one profile, and both should be required. Cars and profiles both have many instances of this new entity.

Linking fields in from between different models

This question is related to: How to link form after creating rails join table
I Had a products model, with a categories field, however needed each category in individual rows rather than the comma separated rows they were in. So I created a Category and ProductCategory model, and added all appropriate associations.
How do I link up the categories field from the old products model to the new Category table so that when a user enter a new product and adds the category, it will save to the category table.
There is a great Railscast on setting up accepts_nested_attributes_for it should be just what you are looking for. I would do you a better service by just telling you to watch it, rather than replicate code.
http://railscasts.com/episodes/196-nested-model-form-part-1

How to handle multiple user types in Rails?

I'm finding a good way to modeling User different types in the system. For registration, he/she can select to be a student, a mentor, or both. Being a student or a mentor has different set of properties. Student and mentor will have different profile template layout as well.
How would you design your controllers and models for this kind of problem?
I would create a User which can hold a Mentor class and/or a Student class. This way your different properties are seperated from each other while the same properties still remain in the User class.
In the Controller you can render a template (or partial), depending on the instance the User holds. One for students, one for mentors and one for both.
You could also use Inheritance (User as parent with Mentor, Student and Both as childs). The key word you want to look into here is Single Table Inheritance.
Imho the problem is the both option. That's why I would prefer the 1st solution.

How does the Rails' single table inheritance works?

I have a user table, and a teacher that I newly created. The teacher is sub class of user, so, I use scaffold generator to generate the teacher table, than, I modify the model to do teacher is subclass of user. After all that, I did a db:migrate. Then, I go to
http://localhost:3000/teachers/new
It shows an error:
undefined method `teacherSalary' for #<Teacher:0x103331900>
So, my question is what did I do wrong? I want to create a page for doing user register, the user can ONLY be a teacher / student. But I can't add a teacher record ... ... Moreover, I go to
http://localhost:3000/users/new
I want to have a combo box that allow user register their user to be a "teacher" or a "student". But everything seems not work like I expected. What I need to do? Thank you very very much for your help.
Within your database you should have a single table called users. This table should have a string column which by default is called type. If you use another name for this column then you will have to set the inheritance column name manually using self.inheritance_column = "column_name"
Within your application you have three models, User, Student and Teacher. User inherits from ActiveRecord::Base as usual, Student and Teacher both inherit from User.
You should then be able to instantiate new Teacher and Student objects. Internally this works by writing the model name to the type field on the user tables and then when you use Student.find it adds a clause to the SQL to only return rows where the type = 'Student'
You can add shared behaviour to the User class, e.g. validations etc then add additional behaviour to the inherited classes.
A fuller description of how STI works can be found in Martin Fowlers Book(Patterns of Enterprise Application Architecture).
I found this definition really handy:
STI means one table contains the data of more than one model, usually differentiated by the "type" column. ("users" table contains data for the models "Teacher", ""Pupil", "Employee", "Assistant", etc.)
Keeps similar models in the same table instead of creating new ones.
A Polymorphic Association means that one model can be associated with more than one other model(Comment can belong to post, image, file, user_type...)
To prevent foreign key conflicts, the association is reperesented with the *_id and *_type columns instead of only *_id.
For what you have here , I am not sure if STI is the best way go . STI should generally be used when there is a OO like inheritance and the Models have the same Attribute but different behaviour . In your case Teacher and Student can sure have a few shared attributed , but they are also bound to have different ones as well .
You might want to experiment with a polymorphic association as well .

Resources