Rails 4 - Ordering by something not stored in the database - ruby-on-rails

I am using Rails 4. I have a Room model with hour_price day_price and week_price attributes.
On the index, users are able to enter different times and dates they would like to stay in a room. Based on these values, I have a helper method that then calculates the total price it would cost them using the price attributes mentioned above.
My question is what is the best way to sort through the rooms and order them least to greatest (in terms of price). Having a hard time figuring out the best way to do this, especially when considering the price value is calculated by a helper and isn't stored in the database.

You could load all of them and do an array sort as is suggested here, and here. Though that would not scale well, but if you've already filtered by the rooms that are available this might be sufficient.
You might be able to push it back to the database by building a custom sql order by.
Rooms.order("(#{days} * day_price) asc")

Related

Rails and understanding "belong_to"

So im pretty new with rails, and am working on an API that takes POST requests (from a raspberry-pi) and sets up data in the database.
I have 2 models/schema:
a "Measurement" model. Which simply just contains 2 floats (humidity and temp for now)
and a "Unit" model. Which im not 100% sure how I want to do this, but it will probably just contain an "id" identifying the unit-id in some sort of way.
Anyways, I want measurements to belong to a unit (so I can reference the units for historical value) IE: This raspberry-pi had these temps the past 5 hours..or whatever.
How would I want to arrange this.
I imagine i'd need at the very least "Measurement" model to "belong_to" "Units" model. Am I forgetting something else? Besides the "has_many" of course for Units. How would I go about creating seed data for this?
I want to eventually be able to have an index page for the "Unit" id that contains it's humidity/temps it's been sent.
A measurements database record will have a unit_id integer field, matching the id primary key field of the units table.
Rails's ActiveRecord expresses this many-to-one relationship by saying Unit.has_many :measurements, and Measurement.belongs_to :unit.
From here, take time to just read your tutorials, to soak in all this before trying to code.

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.

Creating a YAML based list vs. a model in Rails

I have an app that consists mainly of restaurant model instances. One of the essential attributes for these restaurants is labeling the cuisine it falls under. I'm currently at odds with myself in regards to designing this. On one hand I thought of creating a Cuisine model and creating either a HMT or HABTM association between Restaurants and Cuisines.
More recently I came across this post which shows how to create a pre-defined set of attributes. To take the answer one step further I'm assuming (in my case) I'd add a string-based cuisine column to my restaurant model and setup a select box in my restaurant form that would save the selected value.
What I was wondering was what would be the most efficient way of doing this? The goal is to eventually be able to query restaurants based what cuisine(s) they fall under. I wasn't sure if a model would be the best choice due to it only serving as a join table in a sense with a name attribute. Wasn't sure if having this extra table for something so minute would be optimal.
On the other hand I didn't know if using YAML for this would be conducive since the values are essentially dummy strings with no tangible records on file like I'd have with a model instance. Can someone help me sort out this confusion?
There are many benefits of normalizing many-to-many relationships in the db. Here are some:
Searching, sorting, and creating indexes is faster, since tables are narrower, and more rows fit on a data page.
You can have more clustered indexes (one per table), so you get more flexibility in tuning queries.
Index searching is often faster, since indexes tend to be narrower and shorter.
More tables allow better use of segments to control physical placement of data.
You usually have fewer indexes per table, so data modification commands are faster.
Fewer null values and less redundant data, making your database more compact.
Triggers execute more quickly if you are not maintaining redundant data.
Data modification anomalies are reduced.
Normalization is conceptually cleaner and easier to maintain and change as your needs change.
Also, by normalizing you get the cleaner syntax and other infrastructure benefits from ActiveRecord, e.g.
cuisine.restaurants.where(city: 'Toledo')

Optimising a large number of rows in a Rails app database

We have a number of Meters which read a number of Parameters at a given interval and uploads the data (in CSV format) to a MYSQL database.
I have modelled this in Rails as follows:
Meter
has_many :parameters
Parameter
belongs_to :meter
has_many :readings
Reading
belongs_to :parameter
(I've used normal foreign keys - meter_id and parameter_id - to link the tables)
This is working great with my seed data and I'm using self.readings.pluck(:value).latest in my Parameter model in order to grab the latest value and pass it to the view.
The only problem is that the meters upload the data every 30 seconds. This means that - as there are currently 20 parameters - just over a months worth of data has left me with over 20,000,000 rows in my Readings table and this means that the queries to grab the latest are taking around 500ms each.
I'm after suggestions of ways to optimise this. I've added an index to the parameter_id field but, other than that, I'm not really sure of the best way to proceed...
It may be that I need to rethink the way that my database is structured, but this seemed to make most sense as I want to be able to dynamically add new parameters down the line (hence why I couldn't just make my columns the parameter names) and this seems to be the way that Rails stores data by default.
Thanks in advance.
If you are using Rails 3 and want to keep using a relational database your best option is to use table partitioning.
If you use PostgreSQL you can use the partitioned gem and check this slides to get an overview.
If you want to use Rails 4, since the partitioned gem is not compatible with ActiveRecord 4, I would advise you to use manual partitioning, you can use the year as your partition point, for example.
Check this blog post on Sharding and Partitioning and evaluate what should work best.

In Ruby/Rails, how can I create one column in a table based on the value of two other columns in the same table?

I am trying to create a Reddit type app where the order of a list depends on a combination of the number of upvotes a link has and the created date. My plan is to create a new column in my "Links" table that combines "created_date" and "upvotes" into a "Rank Value" and then sort the list by the "Rank Value".
Is this the right approach? If so, how do I create this table column using ActiveRecord?
If there is a meta attribute that is used purely for display purposes, creating a method that will generate it on the fly would be appropriate.
If you want to use it for sorting your objects as well, it's better to store it in a column. Hopefully, it doesn't depend on things like the current time, and only on its other attributes:
before_save :calculate_rank
def calculate_rank
self.rank = self.upvotes + self.clicks * 5;
end
Unfortunately, for your use case you specifically said your column depends on the creation date, probably in terms of "how fresh is it" -- a moving target.
You can solve this two ways: by constantly increasing the rank values for newer links indefinitely, or by putting items into time buckets and updating them periodically (degrading their scores when the day or week ends, perhaps).
You can create methods in your model such as "rank_value" which would sort by your criteria and just call Model.rank_value

Resources