Rails - How to store each update of an item - ruby-on-rails

I'm not sure how to do this in rails (maybe its a common topic but I'm not even sure if the title is correct)
I have a product table with this fields
Name
Quantity
Price
Size
and the columns that rails provide (id, created_at, updated_at)
This table is going to be updated periodically (lets say each day or so) but I want to save the QUANTITY that is being ADDED, and the date/time of the actualization (UPDATE).
I'm not sure if it's a design problem or something else.
Is there a way rails can handle this?
Thanks in advance
Javier QQ.

Given what you've said in your comments, why don't you just make a new table, say a "Stock" table. Each stock has two fields (in addition to the default created_at and updated_at): quantity and item_id.
Whenever you want to update an item with a new quantity, in the update method (or stock method, whatever it is) you do:
Stock.create(:item_id => #item.id, :quantity => params[:quantity])
This also ensures that you know when stock was added, because Rails will automatically keep track of when this Stock was made.

I'm not sure if this is exactly what you're looking for... but you can try the papertrail Gem. It stores each update of your model and you can easily step backwards or forwards in time through them to inspect your model and what fields changed, so it sounds like it'd be pretty ideal for what you have in mind.

Related

When last a table column was modified

Is there a way to know when a user updates a table column? For example, at what time a user changes their last name?
Im not interested when last a table was updated; only the column. Is it possible using Rails 5 and PostgreSQL?
If you are including timestamps in your models (.created_at and .updated_at) then .updated_at will tell you the last time that the record (i.e. the database row) was updated.
But that will not tell you which attribute of the record was changed (i.e. which database column). Nor will it tell you which user changed it, or if it was changed automatically by something in your system, etc.
You would need the schema to do that. You can a new table called as user_logs and implement a trigger which stores old_record and new_record. This will help you to get the desired log for change.

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

Three ways to use user_id in a rails database, which one is best?

I have a rails application linked to a database table, which contains e-mail addresses and passwords. I would like to create a unique number which will identify each of the users in the system. This number will be given to a user upon registration, and stored in the field user_id on the same table.
So, for example, john#foo.bar could get 0001 as an ID, martha#foo.bar could get 0002, and so on.
My question is: what is the best way to do this?
Should I seed the database (rake db:seed) with the first user_id (0001) and write a method in the controller to +1 the user_id every time? If that is the case, how can I access the last row in order to find out the last user_id?
An alternative way would be to find the largest user_id in the table and +1 it. For that I guess I need to use tablename.find_by_user_id or something similar (would tablename.find_by_user_id.max work?)
A third way would be to store the latest user_id somewhere, and have the application retrive it when needed. Where could this information be stored?
I'm very new to rails . Would appreciate your feedback about which is the best way to go.
Thanks,
TimmyOnRails
Lets assume your model has two attributes name and email. Now by default rails will generate three more columns for you
1 id - auto incremental
2 created_at and updated_at - timestamps
Rake db:seed is one of the good solution in case you want to prepopulate the database. All you need to worry about is name and email. Add proper validations for these attributes. Rest rails will handle ie id is maintained by rails itself. You don't need to worry about it. Created_at and updated_at columns are also maintained by rails.
If you new to rails then I will suggest you to check http://railsforzombies.com and that will you a good idea about active records
Railsguides and RailsCasts are also two other learning materials for rails.

rails and an up/down rating system

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.

Freezing associated objects

Does anyone know of any method in Rails by which an associated object may be frozen. The problem I am having is that I have an order model with many line items which in turn belong to a product or service. When the order is paid for, I need to freeze the details of the ordered items so that when the price is changed, the order's totals are preserved.
I worked on an online purchase system before. What you want to do is have an Order class and a LineItem class. LineItems store product details like price, quantity, and maybe some other information you need to keep for records. It's more complicated but it's the only way I know to lock in the details.
An Order is simply made up of LineItems and probably contains shipping and billing addresses. The total price of the Order can be calculated by adding up the LineItems.
Basically, you freeze the data before the person makes the purchase. When they are added to an order, the data is frozen because LineItems duplicate nessacary product information. This way when a product is removed from your system, you can still make sense of old orders.
You may want to look at a rails plugin call 'AASM' (formerly, acts as state machine) to handle the state of an order.
Edit: AASM can be found here http://github.com/rubyist/aasm/tree/master
A few options:
1) Add a version number to your model. At the day job we do course scheduling. A particular course might be updated occasionally but, for business rule reasons, its important to know what it looked like on the day you signed up. Add :version_number to model and find_latest_course(course_id), alter code as appropriate, stir a bit. In this case you don't "edit" models so much as you do a new save of the new, updated version. (Then, obviously, your LineItems carry a item_id and an item_version_number.)
This generic pattern can be extended to cover, shudder, audit trails.
2) Copy data into LineItem objects at LineItem creation time. Just because you can slap has_a on anything, doesn't mean you should. If a 'LineItem' is supposed to hold a constant record of one item which appeared on an invoice, then make the LineItem hold a constant record of one item which appeared on an invoice. You can then update InventoryItem#current_price at will without affecting your previously saved LineItems.
3) If you're lazy, just freeze the price on the order object. Not really much to recommend this but, hey, it works in a pinch. You're probably just delaying the day of reckoning though.
"I ordered from you 6 months ago and now am doing my taxes. Why won't your bookstore show me half of the books I ordered? What do you mean their IDs were purged when you stopped selling them?! I need to know which I can get deductions for!"
Shouldn't the prices already be frozen when the items are added to the order? Say I put a widget into my shopping basket thinking it costs $1 and by the time I'm at the register, it costs $5 because you changed the price.
Back to your problem: I don't think it's a language issue, but a functional one. Instead of associating the prices with items, you need to copy the prices. If every item in the order has it's own version of a price, future price changes won't effect it, you can add discounts, etc.
Actually, to be clean you need to add versioning to your prices. When an item's price changes, you don't overwrite the price, you add a newer version. The line items in your order will still be associated with the old price.

Resources