rails and an up/down rating system - ruby-on-rails

sorry if it's duplicate, I've been looking for something similar before posting, but no success.
So basically I need an up/down rating system ( it's very similar to the one here on stackoverflow ).
I have 6 rateable models, so polymorphic association seem to be the best option.
But since this table will probably hold a solid number of records, won't it take too much time to get the item rating ( upvotes_count - downvotes_count )?
I actually though about adding a new row to each and every rateable model, something like current_rating_value. So that this value will be changed every time the rating object will be created/destroyed.
Could you please advice, what might be a better option in this case? Extra UPDATE call to change the current_rating_value or an extra SELECT(SUM...) call to calculate it?

Depending on how much traffic you get loading these models it could tax resources more then desired. I've ended up using acts_as_votable gem in my projects. Its very easy to make a model votable and it also caches the data which is also awesome.

for the long-term performance, you should add something like current_rating_value into every ratable model. Everytime there is new rate, just update this field.
Otherwise, it will be very harmful to performance when you have to calculate the rating everytime.

Related

calculated fields: to store in DB or not to store?

I am building a ruby on rails application where a user can learn words from a story (having many stories on his list of stories to learn from), and conversely, a story can belong to many users. Although the story is not owned by the user (it's owned by the author), the user can track certain personal things about each story that relate to him and only to him, such as how many words are left to learn in each of his stories (which will obviously differ from user to user).
Currently, I have a has_many :through relationship set up through a third table called users_stories. My concern/question has to do with "calculated fields": is it really necessary to store things like words_learnt_in_this_story (or conversely, words_not_yet_learnt_in_this_story) in the database? It seems to me that things like this could be calculated by simply looking at a list of all the words that the user has already learnt (present on his learnt_words_list), and then simply contrast/compare that master list with the list of words in the story in order to calculate how many words are unlearnt.
The dilemma here is that if this is the case, if all these fields can simply be calculated, then there seems to be no reason to have a separate model. If this is the case, then there should just be a join model in the middle and have it be a has_and_belongs_to_many relationship, no? Furthermore, in such a scenario, where do calculated attributes such as words_to_learn get stored? Or maybe they don't need to get stored at all, and rather just get calculated on the fly every time the user loads his homepage?
Any thoughts on this would be much appreciated! Thanks, Michael.
If you're asking "is it really necessary to store calculated values in the DB" I answer you. No, it's not necessary.
But it can give you some pros. For example if you have lots of users and the users call those values calculating a lot then it could be more winnable strategy to calculate them once in a while. It will save your server resources.
Your real question now is "What will be more effective for you? Calculate values each time or calculate them once in a while and store in DB?"
In a true relational data model you don't need to store anything that can be calculated from the existing data.
If I understand you correctly you just want to have a master word list (table) and just reference those words in a relation. That is exactly how it should be modelled in a relational database and I suggest you stick with it for consistency reason. Just make sure you set the indices right in the database.
If further down the road you run into performance issue (usually you don't) you can solve that problems then by caching/views etc.
It is not necessary to store calculated values in the DB, but if the values are often used in logic or views its good idea to store it in Database once(calculate again on change) and use from there rather then calculating in views or model.

ROR / Database: How to create a custom order list for database records?

I have a database table with some articles (for a website) like so:
Articles:
id title order_id
1 - 1
2 - 4
3 - 3
4 - 2
Now on the webpage I want to use the order_id to order the articles, this works perfectly fine, using ROR active record.
However when I want to update the order_id I would have to update all of the records using this technique, each time a change to the order_id is made. What is a better way of doing this ?
Thanks
You want acts_as_list:
class Article < ActiveRecord::Base
acts_as_list :column => 'order_id'
end
There's no way around updating lots of records when you perform a reordering, but acts_as_list can do all that for you with methods like Article#move_to_top and Article#move_lower.
There are some gems to solve your problem. The Ruby Toolbox has them in the category Active Record Sortables. As the time of writing (March 2017) the top gems in this list are:
act_as_list (Website, GitHub)
This is the most popular choice for managing an ordered list in the database and it is still maintained 10 years after its creation. It will do just what you wanted and manage the numbers of the items. The gem will keep your position field numbers form 1 to n in the correct order. This however means that inserting items in the middle of the list means increasing all of the position values for the list items below it, which can be quite some work for your database.
ranked-model (GitHub)
This gem also manages custom ordered lists for you. However it uses another approach behind the scenes, where your list items get position numbers big and spaced apart across the full range of integer values. This should get you performance benefits if you have large lists and need to reorder the items often. It seems to me that this gem might no longer be maintained though, since the author is now doing Ember.js development, it should work though. Edit: It is still maintained.
sortable (GitHub)
This seems to be the same like act_as_list but with the ability to put your items into multiple list. I'm not really sure if this is a valid use-case since you could just create multiple items. It looks like it was not maintained for a long time and not used by many.
resort (GitHub)
This gem uses a linked list approach, i.e. every database entry gets a pointer to the next entry. This might be a good idea if you need a lot of inserts in the middle of your lists, but seems like a terrible idea for just getting the list of entires or if something goes wrong in the database and the chain breaks. It is quite new, so let's see how it develops.
acts_as_restful_list (GitHub)
This gem is "Just like acts_as_list, but restful". It seems to aim for a nicer API. The company behind it does no longer exist, so I'd rather use act_as_list and deal with its API, which is not too bad anyway.

Howto "virtually" create and save an attribute of a separate model in rails

The title may appear as if I am asking howto access/find/update an attribute of a related/nested model but this is not the case and unfortunately this is the best title I could figure out.
I would like to build a soccer management game with ruby on rails, where routine total_attack_value and total_defense_values are matched etc. I don't plan to make the simulation too deep like in here and here, such as calculating and matching separate corner_attack or side_attack values but seriously intend to include the goalkeeper's skill in total_defense_value.
To clarify, the total_attack_value is going to be calculated as "total_shooting_value x total_pass_value x total_possess_value x/+ Rand() etc" and all of these ..._values are going to be calculated inside the Team model but the total_defense_value should have "goalkeeper_skill_value" which is going to be the skill of the player selected as the goalkeeper by the user for the coming match, as I planned.
I cannot think of anything else than saving and retrieving which player is put into goalkeeper position by the user using virtual attributes, since the user is going to schedule the match for a future time and the goalkeeper selection should persist until then. In this case I'm going to create a Player_Position model and an association model belonging to both Position and Player and an assign_positions function in Player model etc. However this is exactly what I am trying to avoid, code- and complexity-wise being the same as to offer the user the possibility to drag&drop players to positions separately as seen in some games like soccermanager and goalunited.
Does rails offer any simple/ready solution to this problem as it does to simple CRUD operations, like an attribute or STI?
I'm not sure if I completely understand what you are trying to achieve but the next version of Rails, 3.2, has simple Key Value Store functionality that you may be able to use. The release candidate is already out so you would be able to try it out to see if it met your needs.
A short note on the functionality was included in the latest release notes.

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.

How to implement row ordering in Rails?

I'm trying to implement a UI feature for a listings page where the user can change the order of the records they have created.
I'd assume one way to do it would be to store a position field with some kind of editable auto-increment rule; The position values of rows could then be swapped as the user raises or the lowers the position. However I'm not quite sure how that would be done, I'm still a Rails newbie.
I should also mention that I am trying to a avoid solutions that tie me to a particular database.
Any suggestions?
acts_as_list is the standard solution here. You will have a position column in your model that will hold the ordering.
This is a commment/addition to the accepted answer above.
acts_as_list is not designed for anything beyond a prototype, and out of the box it does not handle concurrency or data integrity at all. At the very least, you must set your isolation level to serializable! Here's a short screen cast with more information, and some workarounds.

Resources