MarkUs Blog

MarkUs Developers Blog About Their Project

Archive for the ‘database’ tag

Data Simulator

without comments

The simulator creates random data to fill in the database.
The simulator creates by default 2 assignments with random due date and total mark. For each assignment, it creates some Tas, students and groupings and then assign the groupings to the Tas. Each grouping may have up to four submissions and it might have been partially or completely marked.

If there is no admin account in the data base, the simulator creates two: “a” and “reid”.
There are four environment variables that can be provided to the simulator:
– NUM_OF_ASSIGNMENTS: it indicates how many assignments the simulator should create. The default value is 2.
– PASSED_DUE_DATE: if it is true, then all the created assignments by the simulator will have their due date passed; if it is false, then the created assignments have due dates two months ahead from the date the assignments were created. If this environment variable was no provided, then the assignments due date randomly can be passed or not.
– NUM_OF_TAS: it is the number of tas each assignment can have. If it was not provided, the number of tas is at least 1 and at most 3.
– NUM_OF_STUDENTS: it is the number of students each ta can have. If it was not provided, the number of students is at least 10 and at most 15.

Written by g9sabied

August 22nd, 2010 at 10:57 am

Posted in Developer Essentials

Tagged with ,

Rebooting the Schema (part 2)

with 2 comments

Last time, I talked about the old model schema, and the problems it had that lead us to refactor the code. After refactoring, this is what the database looks like:

Association

The relationships are now more concrete with the addition of memberships and assignments_groups tables. The assignments_groups is a Rails convention of declaring a many-to-many relationship between two objects by use of the join table. Thus, an assignment can have many groups, and groups can also have many assignments if a group persists throughout the course. A caveat though is to make sure that the join table is in alphabetical order, meaning it must be assignments_groups and not groups_assignments. That’s just the “convention-over-configuration” mantra of Rails at work.

Once we have the database schema set, we can then just go in and declare those relationships in the ActiveRecord classes respectively:


class Group < ActiveRecord::Base
has_and belongs_to_many :assignments
end
class Assignment < ActiveRecord::Base
has_and belongs_to_many :groups
end

However it is a different case if the join table contains extra information, which is our case with the memberships table. Here, not only does it reference the user and the group together, but it also contains extra information such as status of the member. Thus, we need to have a Membership class representing a member, and use has-many-through relationship. which sort of explicitly states that the association between a User and a Group uses memberships as its link. Here we declare the relationship as follows:

class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
end
class Group < ActiveRecord::Base
has_many :memberships
has_many :members, :through => :memberships, :source => :user
end

Abstraction

We’ve also separated the old submissions table to a submissions and submission_files tables. The new submissions table doesn’t seem to have much information and seems to be a waste of space. However, having this table allows us to delegate submission functions to a Submissions class rather than mixing them directly with either the User or Group classes. All we have to do now is just ask a User or Group for its Submission instance, and handle all queries related to submitted files from it.

Since we also want to avoid checking to see if it is a User or a Group submission everytime, we’ve abstracted the Submissions class and added separate classes for each type, UserSubmission and GroupSubmission – classes that are linked to Users and Groups respectively. Since instead of declaring the relationship with Submissions, we have:

class User < ActiveRecord::Base
has_many :submissions, :classname => UserSubmission
end
class Group < ActiveRecord::Base
has_many :submissions, :classname => GroupSubmission
end

class UserSubmission < Submission
has_many :users
end
class Group
Submission < Submission
has_many :groups
end

This allows us to call either user.submissions or group.submissions and return with an instance of the appropriate Submission subclass type.

Final Results

The refactored models with the appropriate associations gave way to a much cleaner code in the end. With the schema set in place, I’ve revisited the old code and heeded the advice in the first post, stuffing all the business logic in the appropriate models and leaving workflow control to the controllers. The result turned several functions with 200+ lines into a single function with less than 50 lines. I was also able to create more thorough unit testing while code was being written. Here, we can see that we’ve improved our stats quite a bit:

$ for f in app/controllers app/models app/helpers; do echo $f
`find $f -name "*.rb" |xargs wc -l |tail -n1`; done
app/controllers 563
app/models 591
app/helpers 60

In retrospect, I think the refactoring decisions suits us very well with what we have in mind and gives us room for modifications at the same time…until we actually start porting OLM. Stay tuned.

Written by Geofrey

October 14th, 2008 at 6:32 pm

Migrate Your Tests

without comments

Rails has a nice way of maintaining versions of your database schema through ActiveRecord:Migration.  This lets you modify your existing schema without the hassle of manually copying the same schema to all the different deployed instances that you have, and does this automatically for you.

When I usually change the schema, I usually drop all the tables and recreate them using:

rake db:migrate VERSION=0
rake db:migrate

and then repopulate my development DB environment using a script I use.  However it turns out that this doesn’t migrate your test environment automatically with it. I tried creating a simple test of making sure that my ActiveRecord validation works.  However, I ended up getting this error:

test_numericality_group_limit(AssignmentTest):
NoMethodError: undefined method `group_limit=' for #<Assignment:0xb7242018>
/var/lib/gems/1.8/gems/activerecord-2.1.0/lib/active_record/attribute_methods.rb:251:in `method_missing'
test/unit/assignment_test.rb:11:in `test_numericality_group_limit'
/var/lib/gems/1.8/gems/activesupport-2.1.0/lib/active_support/testing/setup_and_teardown.rb:33:in `__send__'
/var/lib/gems/1.8/gems/activesupport-2.1.0/lib/active_support/testing/setup_and_teardown.rb:33:in `run'

After hours of finding the bug, I found out that you have to migrate your test DB environment as well, by executing the following:

rake db:schema:dump
rake db:test:prepare

This will copy the schema that you have right now in your development environment, and copy it to your test environment.

Written by Geofrey

August 6th, 2008 at 10:49 am