rails sums model - ruby-on-rails

I have a lot of sum functions in my app. I am moving all data sums to a separate model...lets call it...sums. This will make calling those numbers faster as I wont nail the database everytime I need to sum many rows.
What I would like to do is update the sum row (many attributes) each time certain other models are created or updated. I am trying to this via each model using a class method but for some reason its not working.
Im wondering where I can create a universal method that can be called from an after_create callback for whichever models I choose. The sum is associated to an account, which is not the model being updated. Other account associated models are the ones that will hit the sums model. Therefor, I will probably need to pass self.account_id to the callback method.
Like Papertrails versions model, that is updated everytime another model is saved.

Have a look at Statistics gem.
It has a cache option that uses Rails cache to prevent repeated aggregation calls to database.
I would prefer something like this as opposed to have an update every time a property gets updated. If you are not planning to hold the sums model in memory, then you will have to fire as many updates to sums table as there are actual updates.
While it may be OK to have write-time overheads, as opposed to read-time, Statistics comes with other options to optimize.

Related

Rails model columns and performance

I am using postgresql.
I started to realise that I have created too many columns for the User model, and most of them are boolean fields.
Correct me if I am wrong, if I just update one boolean value, the whole table are being updated even though "Patch" verb is being used.
So I decided to create a specific model for some boolean columns, however, this would also trigger two queries, one for the User load and the other for the newly created model load.
My question is: Would it be better if I chop some of the columns to form a new model? Or a model with many columns just don't affect the performance of a rails app.
My main concern is the data connection speed, please advise.
Avoiding a join will be better than having two tables.
You can limit which columns are returned by using select in ActiveRecord. If you have large text fields, but don't need them at a particular time, this can be helpful in improving performance. The impact is probably negligible with boolean columns.

Rails - Good way to support creation of drafts for several models

I want to allow users to create drafts of several models (such as article, blog post etc). I am thinking of implementing this by creating a draft model for each of my current models (such as articleDraft, blogpostDraft etc.). Is there a better way to do this? Creating a new model for every existing model that should support drafts seems messy and is a lot of work.
I think the better was is to have a flag in the table (ex: int column called draft), to identify if the record is a draft or not.
Advantages of having such a column with out a separate table, as I can see:
It's easy to make your record non-draft (just change the flag)
you will not duplicate data (because practically you will have the same in draft and non-draft records)
coding will be easy, no complex login
all the data will be in one place and hence less room for error
I've been working on Draftsman, a Ruby gem for creating a draft state of your ActiveRecord data.
Draftsman's default approach is to store draft data for all drafted models in a single drafts table via a polymorphic relationship. It stores the object state as JSON in an object column and optionally stores JSON data representing changes in an object_changes column.
Draftsman allows for you to create a separate draft model for each model (e.g., article_drafts, blog_post_drafts) if you want. I agree that this approach is fairly cumbersome and error-prone.
The real advantage to splitting the draft data out into separate models (or to just use a boolean draft flag on the main table, per sameera207's answer) is that you don't end up with a gigantic drafts table with tons of records. I'd offer that that only becomes a real problem when your application has a ton of usage though.
All that to say that my ultimate recommendation is to store all of your draft data in the main model (blog) or a single drafts table, then separate out as needed if your application needs to scale up.
Check out the Active Record Versioning category at The Ruby Toolbox. The current leader is Paper Trail.
I'd go down the state machine route. You can validate each attribute when the model's in a certain state only. Far easier than multiple checkboxes and each state change can have an action (or actions) associated with it.
Having a flag in the model has some disadvantages:
You can not save as draft unless the data is valid. Sure, you can skip validations in the Rails model, but think about the "NOT NULL" columns defined in the database
To find the "real" records, you have to use a filter (like "WHERE draft = FALSE"). This can slow down query performance.
As an alternative, check out my gem drafting. It stores drafts for different models in a separate table.

Structuring database using Parse

I'm using Parse (www.parse.com) for the backend database for an iPhone app. I'm creating a fitness application and want advice as the best way to structure the classes and relationships.
A few needs for the database:
1)Sets(have attribute or weight and reps)
2)Exercise (a single instance of an Exercise which can contain multiple Sets)
3)Workout (which will be a single instance for a particular workout which will represent 1 single day. No single day can have 2 Workout objects. Can contain multiple Exercise objects.
Then I also need some classes for Routine which is independent from the ones above.
4) Routine can contain ExercseForRoutine objects (which will look the same as Exercise but will just be used for routines, will not be able to add sets to.
5) ExercseForRoutine will be added to Routine, but not related to the actual Exercise objects that will be used when the user enters workout data, this object is just used to create a Routine.
Any advice on tips and how to structure this using Parse would be appreciated
Don't get too hung up on your object model or your data store. If you haven't done so already, generate a list of core use cases and use those to drive your object model. But assume that you will iterate on it until you find a good fit with your domain. The one thing that sounds like it might be a bit fishy about your spec is writing the single day constraint into your Workout class. That doesn't sound like it's essential to the domain and probably will be awkward to code (e.g., what happens if I start my workout at 11:55pm?).

How do I avoid constantly re-calculating summary data using Rails?

I have a user profile page that has a sidebar with user stats like not unlike the Stack Overflow profile page (e.g., total visits, number of badges).
The trouble is that currently I'm hitting the database and calculating these stats with every single request. I can implement fragment caching to cut down on this, but is there a better way to handle this type of thing?
Storing the aggregated summary data in the database seems like it might lead to problems (i.e., inconsistency).
You could store this information in the database instead of recalculating it, using:
Counter caching
Custom callbacks
Counter Caching
As an example, if measuring the number of badges, you could create a database field in User called badges_count, then in the Badge model, have belongs_to :user, :counter_cache => true. Now, whenever the number of badges changes, you can access the count without any new calculations at #user.badges_count.
A basic implementation: http://asciicasts.com/episodes/23-counter-cache-column
Custom Callbacks
Let's say you have a field that measures behavior that is more complex than a simple count. In this case, just implement callbacks that update a field whenever a certain action occurs using before_save, after_save, before_create, etc.
Concerns about Inconsistency
Storing the data in your database will only be inconsistent if you're doing it wrong. There are a finite number of paths through which any statistic can be updated, and you should ensure that all paths are covered in updating whichever field you are using. Rails does it for you with counter_caching, and you have to do it yourself if you use custom callbacks or you have some unusual situation.
You could use a hidden div like in this question (Caching data by using hidden divs). Depending on how much data you want to cache this might be a good solution.

Tracking changes on instances of a class and their associations - thoughts?

I have a class Question which has a lot of assocated models. On one page on my app i list a summary of all the current questions, with various info from associated records. Ultimately this is a hash of values that i then just print out into a csv-style row (i'll call this the 'row hash' from hereon)
I now have a requirement to only show the changes to questions (or their associated data) over a given period. I'm currently deliberating the best way to do this. Here's some ideas i've had so far, i'd welcome any feedback, thoughts, suggestions etc.
1) Approach 1 - acts_as_audited
This was my first thought as i've used this before in other apps. The porblem with aaa though is that it only tracks changes to the record's data (ie it doesn't care if the associations change). So, i could audit all of the associated records as well but then trying to piece together what had changed by tying different audit records together sounds like a nightmare.
2) Save the old and new hash out into serialized fields: ie
- when someone goes to the question/edit page, i calculate the current row hash and save it in a serialized field "old_data" in the question table. Then after they save the question i calculate the new current row hash and save it into a serialized field "new_data" in the question table. Also, i compare the two serialized hashes and save the differences into another serialized hash field 'changes'. Now to do my report i just look for questions updated in the last x days and output their changes data.
3) make a view
- i make a view which corresponds to the data that i want to output (ie that amalgamates all the data that i pull into my report). Then i track changes to the view - somehow. I'm not sure how exactly i would do that.
I'm leaning towards option 2 right now.
Any other thoughts/comments? grateful for any suggestions - max.
So, like you said, you only want to show changes to the records between time x and time y, right? This would seem perfect to me using the acts_as_audited plugin because you end up with a table of changes, right? So make a has_many_through association from Question to all these related tables, then search it for related changes, where date created is after time X. This would return a list of changes. From there, you could connect this list back to the parent object if you need to, or whatever - but it in the end seems like a more reasonable thing to search. You're not looking for a list of related objects, after all, you're looking for a list of changes, so having a table of changes seems a reasonable way to accomplish that?
Hey I had a similar problem, check this out. If you can, go with Mongoid or Mongomapper, embedded versioned documents are sweet.
Thanks guys. I ended up rolling my own solution because what i really needed to do was to capture changes in the results of various methods called on the object, some of which involved associated objects. I wasn't so much interested in the associated objects as (for example) a text string generated as a result of looking at a few different associated objects. I had methods to do all of this already so i really just needed to track changes in the results of calling these methods.
None of the plugins i saw could really do that simply and effectively, so i ended making a table called states which just holds a serialized hash with results of all of these method calls. This gets saved when the record is altered and saved or when any of the relevant associated objects get altered and saved. Then i have some methods to return the differences between different saved state records. It works well for my needs. Thanks very much for your advice anyway.

Resources