I am modelling a Trainer/Member relationship on Ruby on Rails and I was wondering what is the best way to model this relationship.
Currently I only defined roles for a User class using Rolify for view and controller access.
Trainers and Members are users.
Should I do a recursive relation between the User model, or should I create a Trainer and a Member model specifically on Rails, and set up hierarchy between them, and create the relationship between the child models?
I would setup two different models for trainers and members as you proposed and use the rails association helpers. For example, if a member can have several trainers and trainers can have many members you would want to implement a many-to-many relationship. This is most easily done in rails via the "has_many :through" model helpers. You can then add an attribute to these classes that would specify the levels of authorization or controller access on your app if need be.
Related
Which is the best way to implement "recursive" relations in ruby on rails?
eg.
Manager has many Employees
Employee has many Interns
Manager has many Interns;
Manager, Employee and Intern may have multiple "Client" (has many)
but all that models have lots in common: attributres, methods, views.
But if I use a single model "User" with a role attribute and a N:N table for relations I'll lost all the Rails "helper" and methods.
I will be not able to do "manager.employees.clients"
Which is the best way to implement it?
Is there a gem or a clever way?
This is called self join. have you searched rails documents? Check this: https://guides.rubyonrails.org/association_basics.html#self-joins
I've a quick and quite basic question to ask.
I would like to create a new model which has a parameter that can be one of several model types.
Ex: the param 'targeted_object' can be either an instance of Model A or an instance of Model B.
For the moment I don't think I need a similar behavior for Model A and Model B, so my first guess is to create a Master model for Model A and Model B named TargetableObject: create inheritance.
But is it the best way to do this or I need to make something else regarding that I presume for now no related behavior for Master object children?
Thanks
If I understand correctly, Polymorphic associations could be what you need.
From the rails guides:
With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.
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.
I have a Record model (Active Record) that stores some custom logs.
Record is in polymorphic association with all the other model in my app, and I can effectively log what I want hooking my Record methods in the other controllers.
What I need:
To have the logs in a separate database.
So I have to:
Be able to manage two different databases in my apllication (one is Postgres/ActiveRecord and the other one is MongoDB/MongoMapper)
Generate a polymorphic association between my Record model, now with MongoMapper, and the rest of my Active Record models.
That way I can persist my logs to the MongoDB database.
Thanks.
Yes this can be done.
To create a polymorphic association you need both the class and an id. Idiomatically the fields will be named <assoc>_type and <assoc>_id‡. You will need to do some wiring up to make everything work.
Create a MongoMapper::Document Class with the keys <assoc>_type and <assoc>_id with the correct types (I believe MongoMapper allows Class as a key type) along with any other keys you may need.
Define the method <assoc> and <assoc>=
def assoc
assoc_type.find(assoc_id)
end
def assoc=(input)
assoc_type = input.class #STI makes this more complicated we must store the base class
asspc_id = input.id
end
Possibly add a method to your ActiveRecord models allowing them to access you MongoMapper logging class. If there are a lot, you may want to build a module and include it in all the classes that need that kind of functionality.
‡ replace with something meaningful for you application like 'reference' or 'subject'
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 .