So this one has me a bit confused, and it may be unjustified but I would like some input regardless.
I have a rails 3.1.3 application with users who can view media files. I want to keep a history of their activities with regards to their media viewing. The goal is to be able to record a history such that I can track it from the user or from the media e.g. get data for user.history() and media.history() to show both all of the media accessed by a user and all of the users who accessed a particular piece of media, along with other data regarding each transaction.
So far the only way I have been able to come up with that reasonably satisfies this is to create a single history object for each transaction, sort of like this:
class history_item
belongs_to: media_object
belongs_to: user
(other transaction-specific data)
end
What concerns me about this is the number of database entries will quickly skyrocket with the typical use of this application. Is there a better way to approach this problem that I have not thought of? I am new to rails and large web application development in general, and I'm not entirely sure about how this sort of thing is normally done.
I would create such a model as a Viewing class as a HABTM model between User and MediaObject. This makes the actual structure more obvious than just having a relation called history. You can of course add methods for User#history and MediaObject#history as well, if you want that exact interface that you described.
class User
has_many :viewings
has_many :viewed_media_objects, :through => :viewings
end
class MediaObject
has_many :viewings
has_many :viewers, :through => :viewings
end
class Viewing
belongs_to :user
belongs_to :media_object
end
When querying these objects, for example given a user = User.first, if you know that you want to iterate over the user's viewed_media_objects in an action, you could use #user = User.include(:viewed_media_objects).find(params[:id]) to make sure rails fetches the related viewings and media objects at the same time as the user. This way, you won't get a whole bunch of database calls.
Related
I have 2 models, business and federation.
class Business < ApplicationModel
belongs_to :federation
class Federation < ApplicationModel
has_many :businesses
On the Federation index page, I need to display certain information about the businesses within that federation but some of that information comes from an API call using the ids of the businesses to get the information requested.
So far, I call federation.businesses, which gets me an ActiveRecord_Associations_CollectionProxy and then, using an each loop, I get the business ids and make the API call, from which I create an Array for each business containing the rest of the information I need.
#businesses = #federation.businesses
business_ids = []
#businesses.each do |business|
business_ids << business.id
end
#business_billing = JSON.parse(#resp.body.to_s).map { |e| e['billed_by_us'] }
On the index view page I have a table where I iterate through #businesses to display each businesses info and within each row I get the first value from the #business_billing array and display it, then using shift I update the array ready for the next row.
I was wondering if there is a better way to do this. Maybe combining the 2 sets of data so I don't have to do the array shifting? And also where would be a good place to do this (ie not in the federation_controller so that I could use the same information elsewhere in my app?
So I got the tables you can see in the image below:
.
What I would like to do is to create a relationship so that each user (of django auth_user) will be enrolled(or able to enrol) to exactly one "course" so that he will be able to see next events for his modules.
Do I have to create another table and place 2 foreign keys or this is a way to do it in 'php' and it's more simple with Django? I was suggested to create 'student' model inheriting from 'User' with extended behavior and one to many relationship on auth. I tried to do that but unfortunately had not results since I'm really new to Django & Python.
If every auth_user (or auth.User) will be or have the opportunity to be enrolled on a course I would create a 'user profile' model that has a 1-to-1 relationship with the django User model. You can store additional User data in this model, including what course they are enrolled on. See https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model for more details but here is an example:
class UserProfile(models.Model):
user = models.OneToOneField('auth.User')
course = models.ForeignKey('courseapp.Course', null=True)
You would probably need to create a signal that gets fired each time an auth.User object is saved, such that if it is the first time that User object has been saved, it automatically creates the UserProfile:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from yourusersapp.models import UserProfile
def create_user_profile(sender, instance, created, **kwargs):
# Automatically creates a UserProfile on User creation.
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
When you query a User object, you can then reference the User object's profile like:
user_object.userprofile
You could then create a Course object and link the user_object indirectly via its UserProfile to that Course:
course = Course.objects.create(name='course_name', next_field='whatever')
user_profile = user_object.userprofile
userprofile.course = course
userprofile.save()
Now you have a user object with a UserProfile that is linked to only 1 course. Many users can be on the same course, but a user can only be on 1 course. You can also reference all users on a particular course like:
course = Course.objects.get(name='course_name')
course_users = course.userprofile_set.all()
HTH
I think that you can go about this one of two ways.
Extend the User model. 'Student' would probably be a good name for your new model. It would have a OneToOne relationship with 'User', and a ForeignKey relationship with 'Course'. It can store any other information that is applicable to students only. Documentation for how to do that can be found here https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#extending-the-existing-user-model
Create a custom User model that has a ForeignKey relationship with Course. This approach is a bit more complicated, but yields a slightly cleaner end result. Documentation for that is here. https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#substituting-a-custom-user-model
Sorry if it seems like I'm just sending you to the Django docs, but both of those sections are well written and should explain things pretty clearly. If you'd like to post another question with example code we can try and see why your original attempt at extending the User model didn't work. By the way, your "Student" model shouldn't have to inherit from the User model in order to extend it.
I'm quite new with Django, and so far I have a pretty basic setup where I attach an extra model to the default User model from (django.contrib.auth.models). In my accounts.models.py I have something in the line of:
class UserExtension(models.Model):
user = models.OneToOneField(User, primary_key=True)
# more code
I also have another model which needs to be specified an owner. My question is: Which is the better (more django-ish, more readable, more efficient, more flexible) way to signify the owner:
class Owned(models.Model):
# code
owner = models.ForeignKey(User)
# more code
or:
class Owned(models.Model)
# code
owner = models.ForeignKey(UserExtension)
# more code
I'll really appreciate if you mention pros and cons of those approaches.
I'd recommend the first option. The user model is the nontrivial model in the sense that an owned object should not be able to exist without a user, but could exist without a UserExtension.
Also consider that in Django 1.5 you are able to create custom user model, eliminating the need for the UserExtension class. See the documentation for more information.
Consider using UserProfile for any per user add-on information. Check out this blog to see how to do it. Then you can be assured that you are creating UserProfile object every time you create the User.
Now whether you FK on User or UserProfile depends logically on what you are doing within Owned. If Owned works with User's data/field, FK on User; if it works with UserProfile's data, FK on UserProfile.
I have one document embedded in another in Mongoid.
class A < B
include Mongoid::Document
embeds_one :shipping_address, class_name: 'Address'
I have, in my case, omitted the inverse relation:
class Address
# embedded_in :A
Why is it, that although the API works fine and completely as expected:
address = A.address
address.zip = 1234
a.changed? #true
address.save
a.changed? #false
The document is not actually saved?
If i return the embedded_in statement, the save actually works fine.
My understanding of the Mongoid source is not the best so don't kick me too hard mods.
I assume that Mongoid is similar to ActiveRecord in this regard. With ActiveRecord, defining a :has_many does not change the parent object but includes methods for accessing the child. belongs_to on the other hand pulls methods for managing foreign keys.
Looking at the source code for Mongoid it seems that persistence is called from the embedded class to the parent and not the other way around (source). Removing the embedded_in would remove the additional methods for inserting the child into the parent.
Feel free to correct me if I am way off :)
While you can gain a lot when you choose to embed documents in MongoDB, you do give up the ability to query everything outside of the context of the parent. If you want to be able to work with Address documents independently, outside of the context of the parent document, you should link documents with has_many instead of embedding with embeds_many. This comes with it's own set of pros and cons.
If you choose to embed documents, you do specify embedded_in in the model and you access the embedded documents like this:
a = A.new # Parent document
a.addresses # Embedded Address documents
( Documentation Reference )
I would like to ask you guys if you could review my database design. I think it is quite self-explanatory, but to be absolutely clear:
My goal is to make an application which has a super flexible user management (which is why the groups are in tree-form and the groups and users have a habtm relationship) and a super modular way to build pages (which is why the pages consist of widget-blocks).
The reason I made users and profiles separate is because the users table will not change and is only needed for authentication and authorization. However, the profiles table will change according to the wishes of the client. So it might not have a signature, but an avatar field instead. Or maybe it will be completely empty / not exist at all.
A widget could be anything, it could be a poll, it could be a piece of content, it could be a navigation, it could be a collection of comments, whatever.
The reason I chose to make subdomains, locales and layouts separate tables instead of just putting the names into pages is because I want to limit the options that are available to the client. Just because I have a three-columns.ctp in my layouts folder doesn't necessarily mean I want the client to be able to choose it.
Same goes for the widgets. And besides limiting choice, not every plugin, controller and action in my plugins-folder is a widget, so I need a table to clarify which are.
A block is a widget on a page which sits in a container (e.g. the right column in a 3 column layout) at a particular position which is decided by the index (lower index means higher).
So that's my explanation, what do you guys think? Is this as good as it can be? Or do you have (a) suggestion(s) to make it even more flexible and modular.
[edit] Oh and to be clear, the widgets will of course have their own tables to store the information they need to store.
Well, I think that everything is great except "profiles".
When you try to get data from a logged user:
$this->Auth->user();
I don't think that you will get data about "profiles" so you will have to find profile by $this->Auth->user('id') etc. I think that you should merge "profiles" and "users" tables into "users" table.
So when you want to save, let's say, "signature" you should just put it in $this->request->data; and call $this->User->save($this->request->data); and the signature will be updated.
EDIT:
You can leave it the way it is but, to get other data than user, you will have to put:
$id = $this->Auth->user('id');
$current_user = $this->User->findById($id);