can a PORO access the database? - mysql

as my first Rails app, I am building a homework management app which has these tables:
users (from Devise authentication)
schools
courses
assignments
Unlike most examples of course/grading apps I've found, this one is never concerned with all the grades for all students for a particular course, but has only a 1:many relationship between student and courses. So the examples don't really help me.
In order to calculate a user's current grade in any given course (which requires access to data in both course model and assignment model), I am following a suggestion from here on Stack Overflow and creating a PORO in the app/models directory called GradeCalculator.
But this is my first experience with building a PORO into a Rails app, and most of the documentation I'm finding online is for more sophisticated users. I'm assuming it doesn't need a controller (please correct me if I'm wrong), and I see that building it is as simple as:
app/models/gradecalculator.rb
Class GradeCalculator
def calculate_current_course_grade(course_id)
#graded_course_assignments = Assignment.where(user_id: current_user.id, course_id: course_id, graded: true)
#grab weights for each type of assignment in #graded_course_assignments from courses table
#do some calculations
#return the array
end
def calculate_user_GPA(current_user.id)
#more of the same
end
end
My questions are:
Can a PORO access the database (to get data from the courses and assignments tables). Or do I need to pass it all the relevant data from my other classes (like assignments) as params when calling it?
1a. If a simple class can access the database, does the syntax differ from that in the models? Would the above code be able to access Assignment.where?
1b. How would I call this PORO? For example, how would I call it from my views/assignments/index.html.erb?
Can it access Devise's current_user helper?
Tangentially, I just realized that I could store assignment weights in the assigments table. I was thinking chronologically (user inputs number of homework assignments, quizes, etc. at the time of inputting a new course, which determines the weight for each type of assignment), but I could programmatically have each new assignment populate its own weight field by referencing the number of like assignments from its parent course. This would mean, logically, I could do the grade calculation right in the Assignment model. But if extra credit or other changes were added to the course, all the assignments might then have to recalculate their weights. Which way is more correct?
Writing these questions makes me suspect that I am just to pass my PORO the relevant data from my view, let it do calculations on that data and return a grade. But I will post anyway, just in case I'm wrong.

The reason for breaking business logic out into POROs like this is usually to make your code easier to reason about and easier (and faster) to test. To that end, you do not want GradeCalculator to know or care how Assignment works. You should just pass GradeCalculator all of the data it needs (or a Relation, which quacks like an Enumerable). Having GradeCalculator call Assignment.where means that your tests will depend on ActiveRecord, and the database, which means they'll be slow. If GradeCalculator just expects an array, in your tests you'll just have to mock an array of objects that respond to whatever attribute methods GradeCalculator needs to know about, and you'll be able to run them without loading Rails at all. (It's common to have a separate spec_helper.rb and rails_helper.rb so that specs that don't need Rails can run without loading Rails, which makes them so much faster.)
Per your second question my advice is similar: Decouple your POROs as much as possible from Rails and from Devise.

Related

Right design to structurally ensure data consistency

In my current design, I have app_group, student and group_article:
To structurally ensure that a group_article is only associated with a student from that same group, the foreign keys "publisher" and "app_group" are taken from the join entity group_member (1) as opposed to having them issued from student and app_group individually. This way, someone with the right to insert new records into the database cannot introduce incoherent data such as adding an article that have been written by a student that isn't even in that group which would be poor design. Now, I want generalize this approach into multiple students or multiple groups. I now have group_message, group_message_in and group_message_out which is an inheritance chain (group_message is the base which is an abstract entity in Symfony, and both group_message_in and group_message_out extend it):
Initially, I was planning to embed the group foreign key on the base class (group_message) and have the sender/recipient (respectively on group_message_out and group_message_in) be taken from student directly:
However, this will leave the database vulnerable to incoherence as per the first example, eg: student from group A can be associated with a message that targets student from group B which is not desirable (only students from the same group can exchange group_message).
I'm well aware that I can amend this risk in code but I want a similar solution to (1) and to know if this is achievable with Doctrine since MySQL itself might have ways of solving a similar problem that aren't supported by Doctrine.
A relational solution to your problem would look something like this:
The integrity that you seek would be achieved by the PK-FK relationships and by assigning a student to a group using the groupName colums.
Your question then becomes something like "How can I use Doctrine to do the same thing?"
To the best of my knowledge Doctrine uses a set of PHP libraries to create what its proponents call a "persistence layer" that stores what it calls "Entities". With Doctrine, the term "Entity" is a synonym for "Class" in the OO paradigm.
In other words Doctrine stores classes in the data layer.
And now we can see the problem.
A relational schema is a structure of relations which is a completely different kind of artefact than a collection of classes.
The OO/Relational divide has been called an "impedance mismatch". Unfortunately this term obscures more than it reveals.
To quote from the Wikipedia article: "There have been some attempts at building object-oriented database management systems (OODBMS) that would avoid the impedance mismatch problem. They have been less successful in practice than relational databases however, partly due to the limitations of OO principles as a basis for a data model."
I suggest that you also review Ted Neward's article "The Vietnam of Computer Science."
This new answer shows the object-role model, the relational schema that it generates and the logic that is implied by the new constraint (shown by the red arrow)
The object- role model.
This is the logic that is asserted by the fact type Student(.id) is a member of Group(.name)
Now as the domain expert, you can read this verbalization and tell me whether it is True or False in your domain.
Please note that all I did as the modeler, was to change the constraint (shown by the red arrow) and the ORM tool called NORMA generated the new verbalization that you see here.
When the domain expert agrees that the model conforms to the requirements then it takes a few seconds to generate the SQL DDL that can then be used to create a new database schema in an RDBMS.

Django/SQL - Creating a table view that joins a table with an override table

So I have the following model structure in my Django App:-
class SuperModel(models.Model):
f1 = models.CharField()
f2 = models.CharField()
class Model(SuperModel):
f3 = models.CharField()
class OverrideModel(models.Model):
fpk = models.OneToOneField(Model, primary_key=True)
f1 = models.CharField()
f2 = models.CharField()
Basically, in my application, the fields f1 and f2 in the Model table contain user information that I have entered. The user has the ability to override this information and any changes he/she makes in the data is stored in the OverrideModel table (because I do not want to lose the information that I had entered first). Think of it as me creating user profiles earlier while now I want the user to be able to edit his/her own profile without losing the information that I had entered about them.
Now, since the rest of my application (views/templates etal) work with the field names in the Model class, what I want is to create a view of the data that fetches the field f1 from the override table if it exists, otherwise it should pickup f1 from the table it used to earlier without resorting to a raw queryset.
I will describe everything I have considered so far so that some of the other constraints I am working with become clear:-
Model.objects.annotate(f1=Case(When(overridemodel__f1__isnull=True, then=F('f1')), default=F('overridemodel__f1'))).
This throws the error that the annotate alias conflicts with a field already in the table.
Model.objects.defer('f1').extra(select={'f1': 'CASE WHEN ... END'}, tables=..., where=...).
This approach cannot be applied because I could not figure out a way to apply an outer join using extra. The override model may not have a row corresponding to each model row. Specifying the override table in the tables clause performs a cross product operation which combined with where can be used to perform an inner join, not an outer join (although I'd be happy to be proved wrong).
EDIT: I have realized that select_related might be able to solve the above problem but if I filter the queryset generated by Model.objects.select_related('overridemodel').defer('f1').extra(select={'f1': 'CASE WHEN ... END'}, tables=..., where=...) on the field f1, say qs.filter(f1='Random stuff') the where clause for the filter query uses the Model.f1 field rather than the f1 field generated in extra. So this approach is also futile.
Using Model.objects.raw() to get a raw queryset.
This is a non-starter because the Django ORM becomes useless after using raw and I need to be able to filter / sort the model objects as part of the application.
Defining methods/properties on the Model class.
Again, I will not be able to use the same field names here which involves hunting through code for all usages and making changes.
Creating a view in the database that gives me what I want and creating an unmanaged model that reads the data from that view.
This is probably the best solution for my problem but having never used an unmanaged model before, I'm not sure how to go about it or what pitfalls I might encounter. One problem that I can think of off the top of my head is that my view always has to be kept in sync with the models but that seems a small price to pay compared to hunting through the codebase and making changes and then testing to see if anything broke.
So, there you have it. As always, any help / pointers will be greatly appreciated. I have tried to provide as minimal an example as possible; so if any more information is required I'll be happy to provide it.
Also, I am using Django 1.8 with MySQL.
I realized that there is no easy canonical way to solve my problem. Even with using option 5 (creating a view that is ORM manipulated using an unmanaged Model), I would lose the related query names on the original model that are being used in my filtering / sorting.
So, for anyone else with a similar problem I would recommend the approach I finally went with which is not keeping an OverrideModel but an OverriddenModel which keeps the values that are overridden whenever the user makes changes and updating the original Model with the override values so that the model always contains the values on which filtering / querying is going to occur

Separate get request and database hit for each post to get like status

So I am trying to make a social network on Django. Like any other social network users get the option to like a post, and each of these likes are stored in a model that is different from the model used for posts that show up in the news feed. Now I have tried two choices to get the like status on the go.
1.Least database hits:
Make one sql query and get the like entry for every post id if they exist.Now I use a custom django template tag to see if the like entry for the current post exist in the Queryset by searching an array that contains like statuses of all posts.
This way I use the database to get all values and search for a particular value from the list using python.
2.Separate Database Query for each query:
Here i use the same custom template tag but rather that searching through a Queryset I use the mysql database for most of the heavy lifting.
I use model.objects.get() for each entry.
Which is a more efficient algorithm. Also I was planning on getting another database server, can this change the choice if network latency is only around 0.1 ms.
Is there anyway that I can get these like statuses on the go as boolean values along with all the posts in a single db query.
An example query for the first method can be like
Let post_list be the post QuerySet
models.likes.objects.filter(user=current_user,post__in = post_list)
This is not a direct answer to your question, but I hope it is useful nonetheless.
and each of these likes are stored in a model that is different from the model used for news feed
I think you have a design issue here. It is better if you create a model that describes a post, and then add a field users_that_liked_it as a many-to-many relationship to your user model. Then, you can do something like post.users_that_liked_it and get a query set of all users that liked your page.
In my eyes you should also avoid putting logic in templates as much as possible. They are simply not made for it. Logic belongs into the model class, or, if it is dependent on the page visited, in the view. (As a rule of thumb).
Lastly, if performance is your main worry, you probably shouldn't be using Django anyway. It is just not that fast. What Django gives you is the ability to write clean, concise code. This is much more important for a new project than performance. Ask yourself: How many (personal) projects fail because their performance is bad? And how many fail because the creator gets caught in messy code?
Here is my advice: Favor clarity over performance. Especially in a young project.

Flask-SQLAlchemy– Can you make a query within a model?

I'm building a flask webapp which uses Flask-SQLAlchemy, and I'm also considering using Flask-Login to take care of sessions and to protect certain views.
Flask-Login requires certain methods which I see as useful for various parts of the app (specifically, is_authenticated() and is_active(). However, in all of the examples I've seen these methods just return something fixed. What if I want to make a query on the database. For example, if I want to check if that user actually has an entry in the table (I'm using LDAP to log in, so want users to be able to log in even if they haven't got an entry in the table, although I need to see if they are there).
But I don't know if it's possible to make a query on the table itself from within the class which defines it? Or should I place these functions elsewhere (even though the methods are needed by flask-login within the user class)?
You can. Usually the Session.object_session is a good way to get a session and perform a query:
class MyModel(Base):
__tablename__ = u'model_table'
id = Column(Integer, primary_key=True)
# ...
def my_method(self):
session = Session.object_session(self)
qry = session.query(...).filter(...)
# ...
Flask-Login requires that you provide a user object in the user loader callback. This user does not need to be backed by a database entry, it can be any object as long as it implements the required methods such as is_authenticated() and is_active().
From your description it seems to me that the representation of a user that you need is not one that maps one to one to the user table in your database, since you have valid users that are not in your database.
One approach that you can take is to have two user classes, both implementing the required methods. Let's call these DBUser and LDAPUser. As long as you figure out a strategy to have unique IDs across instances of the two classes Flask-Login will not care.
The DBUser class can be a proper database model based on Flask-SQLAlchemy, with straightforward implementations of the is_xxx() methods. The LDAPUser class, on the other side, can implement these methods issuing any necessary database queries into DBUser.query.

MySQL database model for signups with and without addresses

I've been thinking about this all evening (GMT) but I can't seem to figure out a good solution for this one. Here's the case...
I have to create a signup system which distinguishes 4 kinds of "users":
Individual sign ups (require address info)
Group sign ups (don't require address info)
Group contact (require address info)
Application users (don't require address info)
I really cannot come up with a decent way of modeling this into something that makes sense. I'd greatly appreciate it if you could share your ideas.
Thanks in advance!
Sounds like good case for single table inheritance
Requiring certain data is more a function of your application logic than your database. You can definitely define database columns that don't allow NULL values, but they can be set to "" (empty string) without any errors.
As far as how to structure your database, have two separate tables:
User
UserAddress
When you have a new signup that requires contact info, your application will create records in both tables. When a new signup doesn't require address info, your application will only create a record in the User table.
There are a couple considerations here: first, I like to look at User/Group as a case of a Composite pattern. It clearly meets the requirement: you often have to treat the aggregate and individual versions of the entity interchangeably (as you note). Implementing a composite in a database is not that hard. If you are using an ORM, it is pretty simple (inheritance).
On the other part of the question, you always have the ability to create data structures that are mostly empty. Generally, that's a bad idea. So you can say 'well, in the beginning, we don't have any information about the User so we will just leave all the other fields blank.' A better approach is to try and model the phases as if they were part of an FSM. One of the clearest ways to do this in this particular case is to distinguish between Users, Accounts and some other more domain-specific entity, e.g. Subscriber or Customer. Then, I can come and browse using User, sign up and make an Account, then later when you want address and other personal information, become a subscriber. This would also imply inheritance, and you have the added benefit of being able to have a true representation of the population at any time that doesn't require stupid shenanigans like 'SELECT COUNT(*) WHERE _ not null,' etc.
Here's a suggestion from my end after weighing pro's and con's on this model. As I think the ideal setup is to have all users be a user entity that belong to a group without differentiating groups from individuals (except of course flag a group contact person and creating a link with a groups table) we came up with the alternative to copy the group contact user details to the group members when they group is created.
This way all entities that actually are a person will get their own table.
Could this be a good idea? Awaiting your comments :)
I've decided to go with a construction where group members are separated from the user pool anyway. The group members eventually have no relation with a user since they don't require access to mutating their personal data, that's what a group contact person is for. Eventually I could add a possibility for groups to have multiple contact persons, even distinguishing persons that are or are not allowed to edit any member data.
That's my answer on this one.