After finishing Michael Hartl's tutorial on Rails, my first pet project is building a call tracking app using the Twilio API. The basic idea is the following -
There are 4 plans users can sign up for, which limit the number of phone numbers they have, and the number of minutes they can use
Each user, once registered gets their own subaccount from Twilio
Each user can buy phone numbers, limited to their plan
Each user can track what's happening on their phone numbers.
Right now, I've build a basic authorization system, and brainstormed a potential data structure. I have huge loop holes in understanding though, so an experienced programmer's eyes would be greatly appreciated. I.e is there a better data structure, does what I outline below even make sense?
---So, here's the data structure
Table : Plans
max_phone_numbers: integer
max_minutes: integer
has_many: users
Table : Users
name:string
email:string
password_digest:string
remember_token:string [For log in system]
Twilio_SubAccountSid: string
Twilio_SubAccountAuthToken: string
Plan id : integer [to connect to plan]
stripe_token : string [for charging]
belongs_to: plan
has_many: phone_numbers
Table : Phone Numbers
belongs_to users
phone_number:string
user_id: integer
has_many: data_points
Table : Twilio Data
belongs_to phone_numbers
phone_number_id: string
[All of Twilio's call tracking data..i.e duration of call, location etc.]
Okay, that's pretty much my interpration of how it might work. Please tear it apart!
In terms of the data structure, I think this seems to be it. What I didn't realize though is that there's a lot more controllers involved. For example, searching and buying in Twilio involved two CREATE actions, so I had to make another controller. I imagine there would be another controller that would be responsible for routing calls.
Related
I have 3 models
User - has many debits and has many credits
Debit - belongs to User
Credit - belongs to User
Debit and credit are very similar. The fields are basically the same.
I'm trying to run a query on my models to return all fields from debit and credit where user is current_user
User.left_outer_joins(:debits, :credits).where("users.id = ?", #user.id)
As expected returned all fields from User as many times as there were records in credits and debits.
User.includes(:credits, :debits).order(created_at: :asc).where("users.id = ?", #user.id)
It ran 3 queries and I thought it should be done in one.
The second part of this question is. How I could I add the record type into the query?
as in records from credits would have an extra field to show credits and same for debits
I have looked into ActiveRecordUnion gem but I did not see how it would solve the problem here
includes can't magically retrieve everything you want it to in one query; it will run one query per model (typically) that you need to hit. Instead, it eliminates future unnecessary queries. Take the following examples:
Bad
users = User.first(5)
users.each do |user|
p user.debits.first
end
There will be 6 queries in total here, one to User retrieving all the users, then one for each .debits call in the loop.
Good!
users = User.includes(:debits).first(5)
users.each do |user|
p user.debits.first
end
You'll only make two queries here: one for the users and one for their associated debits. This is how includes speeds up your application, by eagerly loading things you know you'll need.
As for your comment, yes it seems to make sense to combine them into one table. Depending on your situation, I'd recommend looking into Single Table Inheritance (STI). If you don't go this route, be careful with adding a column called type, Rails won't like that!
First of all, in the first query, by calling the query on User class you are asking for records of type User and if you do not want user objects you are performing an extra join which could be costly. (COULD BE not will be)
If you want credit and debit records simply call queries on Credit and Debit models. If you load user object somewhere prior to this point, use includes preload eager_load to do load linked credit and debit record all at once.
There is two way of pre-loading records in Rails. In the first, Rails performs single query of each type of record and the second one Rails perform only a one query and load objects of different types using the data returned.
includes is a smart pre-loader that performs either one of the ways depending on which one it thinks would be faster.
If you want to force Rails to use one query no matter what, eager_load is what you are looking for.
Please read all about includes, eager_load and preload in the article here.
I'm trying to create my models for storing users and different contact information fields.
The idea is to allow a user to have 0 or more registered contact info (eg. 2 telephone numbers, 1 Skype account, personal and work email addresses), so I understand I cannot add said fields to the users model, nor is a good idea in my case to model phone, skype, email, etc as individual tables. This makes me consider using a generic contact info table, with a column for the type of contact info (eg. phone, im, email) and the contact info itself.
My doubt, due to my lack of experience on this matter, is this: Should I use an integer for the contact info type and handle it on the controller/view side (either through an array or case-like fashion)? Or would it be better to just use a string (gaining clarity in the db data, but with the added penalty in storage, validation and normalization times of said strings)? Is there any best practice regarding this?
I tried searching in multiple ways, but after reading or skimming through 20+ articles I couldn't find anything even close to what I'm trying to ask.
Thank you in advance!
there's rails' built in enum, which you can use in such a case. it maps integer to string values. e.g.
class Contact < Activerecord::Base
enum contact_type: {email: 0, phone: 1}
#enum contact_type: [:email, :phone]
end
i would not use it without explicitly stating the name to integer mapping. if somebody changed the order of values in the array at some later point, the meaning of the contact_type would suddenly change all over your application, because the already stored integers in the database wouldn't automagically change as well.
I'm a bit confused on the topic of index columns in model associations.
(From the The Rails 4 Way) We have User, Timesheet, and Expense Report models.
The User model:
has_many: timesheets
has_many: expense_reports
(along with the corresponding belongs_to in the other models)
The Rails 4 Way book says to add_index into the timesheets and expense_reports model as so:
add_index :timesheets, :user_id
add_index :expense_reports, :user_id
I don't understand the reasoning for adding an index after every foreign key column. The timesheet and expense_report tables already have a primary_key column so why isn't that used for "performance boos?" Adding two additional indices seems redundant to me? Can someone explain the benefit?
I can see where your frustration comes from, just follow along and I am sure you'll get it pretty fast...
Problem:
When you create a column in a database, it is vital to consider whether you will need to find and retrieve records from that column. So, lets say we have a User table and every user has an email, that in many applications is used for authentication and authorization of users. When we allow users to log in to our application, we will need to find the user record corresponding to the submitted email address. Unfortunately, the only way to find a user by email address is to scan through each user row in the database and compare its email attribute to the given email - which, therefore, implies we might have to examine every row(since the user can be the last person inside the database). This would take a lot of time as you can imagine. Simply, this is not good.
Solution:
Putting an index on the email column would fix the problem. Think of it as an appendix at the end of the book. In a book, to find all the occurrences of a given string, say “foobar”, you would have to scan each page for “foobar” - the paper version of a full-table scan. With a book index, on the other hand, you can just look up “foobar” in the index to see all the pages containing “foobar”. A database index works essentially the same way.
I hope this helps you out.
I am fairly new to Ruby and Rails, made a few blogs etc. I am slowy learning the ruby language and rails framework. I am wanting to create a workout journal/tracker application and need help establishing the models and or to get me started on the right path. I basically want to be able to create a workout/different types of workouts (back, arms, legs, etc), be able to use the # of sets and reps used for that workout, how many days/which days a week, add, edit, delete the workouts, track weight loss/weight, track the workouts, reps, sets you did prior, set goals in the journal, track progress, eventually be able to share workouts etc. I know what I am looking to do just need help getting started and establishing what models to use and what associations to use. I know it seems like alot of info. Any help getting at all getting going would be awesome. Thanks all!
This might be a bit tricky, since there are many styles of exercises -- N sets of M reps, pyramid, max lifts, etc. You may want polymorphic associations in the final version.
But I think you'll have a more clear vision of where to take the project once you've built a few tables and classes; I think I'd start with a Workout class that has_many WOSets (don't use Set; having class names that conflict with built-in class names is way more irritating than you may think), and each WOSet has_many Reps. Then your Reps will keep track of count and weight. Store the order of the reps in the WOSet.
You'll also need a Station class for all the machines and exercises; probably your WOSet will belongs_to the Station, and the Station will has_many WOSet. (So you can retrieve all the sets ever performed on a specific station.)
I hope this quick sketch gets you to the point of playing with creating new workouts, new stations, and playing with the interface in script/console.
Models = Tables
You should have a look at database design and normalization. Its paramount you get the basics right. Otherwise you might end up with database with common errors like performance issues and redundancy (which is is a bad thing).
One you understand what it is you need to store, mapping it to Rails is easy.
http://en.wikipedia.org/wiki/Database_normalization
How do people generate auto_incrementing integers for a particular user in a typical saas application?
For example, the invoice numbers for all the invoices for a particular user should be auto_incrementing and start from 1. The rails id field can't be used in this case, as it's shared amongst all the users.
Off the top of my head, I could count all the invoices a user has, and then add 1, but does anyone know of any better solution?
Typical solution for any relation database could be a table like
user_invoice_numbers (user_id int primary key clustered, last_id int)
and a stored procedure or a SQL query like
update user_invoice_numbers set last_id = last_id + 1 where user_id = #user_id
select last_id from user_invoice_numbers where user_id = #user_id
It will work for users (if each user has a few simultaneously running transactions) but will not work for companies (for example when you need companies_invoice_numbers) because transactions from different users inside the same company may block each other and there will be a performance bottleneck in this table.
The most important functional requirement you should check is whether your system is allowed to have gaps in invoice numbering or not. When you use standard auto_increment, you allow gaps, because in most database I know, when you rollback transaction, the incremented number will not be rolled back. Having this in mind, you can improve performance using one of the following guidelines
1) Exclude the procedure that you use for getting new numbers from the long running transactions. Let's suppose that insert into invoice procedure is a long running transaction with complex server-side logic. In this case you first acquire a new id , and then, in separate transaction insert new invoice. If last transaction will be rolled back, auto-number will not decrease. But user_invoice_numbers will not be locked for long time, so a lot of simultaneous users could insert invoices at the same time
2) Do not use a traditional transactional database to store the data with last id for each user. When you need to maintain simple list of keys and values there are lot of small but fast database engines that can do that work for you. List of Key/Value databases. Probably memcached is the most popular. In the past, I saw the projects where simple key/value storages where implemented using Windows Registry or even a file system. There was a directory where each file name was the key and inside each file was the last id. And this rough solution was still better then using SQL table, because locks were issued and released very quickly and were not involved into transaction scope.
Well, if my proposal for the optimization seems to be overcomplicated for your project, forget about this now, until you will actually run into performance issues. In most projects simple method with an additional table will work pretty fast.
You could introduce another table associated with your "users" table that tracks the most recent invoice number for a user. However, reading this value will result in a database query, so you might as well just get a count of the user's invoices and add one, as you suggested. Either way, it's a database hit.
If the invoice numbers are independent for each user/customer then it seems like having "lastInvoice" field in some persistent store (eg. DB record) associated with the user is pretty unavoidable. However this could lead to some contention for the "latest" number.
Does it really matter if we send a user invoices 1, 2, 3 and 5, and never send them invoice
4? If you can relax the requirement a bit.
If the requirement is actually "every invoice number must be unique" then we can look at all the normal id generating tricks, and these can be quite efficient.
Ensuring that the numbers are sequenctial adds to the complexity, does it add to the business benefit?
I've just uploaded a gem that should resolve your need (a few years late is better than never!) :)
https://github.com/alisyed/sequenceid/
Not sure if this is the best solution, but you could store the last Invoice ID on the User and then use that to determine the next ID when creating a new Invoice for that User. But this simple solution may have problems with integrity, will need to be careful.
Do you really want to generate the invoice IDs in an incremental format? Would this not open security holes (where in, if a user can guess the invoice number generation, they can change it in the request and may lead to information disclosure).
I would ideally generate the numbers randomly (and keep track of used numbers). This prevents collisions as well (Chances of collision are reduced as the numbers are allocated randomly over a range).