Episode #127 - ActiveRecord Tricks

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this episode we're going to look at playing around with some different active record tricks and to start off let's have a look at our application we have a model users and the users belongs to these status and it also has many messages and then our status has many users and the message belongs to the user and if we look at the schema our users has a first name last name email and then a status ID the statuses table has a name and a boolean for active and the active could be true or false and it defaults to false then the messages has a user ID a content to store the messages and then a bullying to see if the message has been read or if it's still unread and the red bullying defaults to false and then in the seeds RB file I'll create a initial seed with some data I'm creating two statuses one that is active and the active attribute is set to true and then I'm creating another status called inactive and it's active attribute is set to false and then creating 20 users and when setting the user status I'm just getting a sample which is going to be a random selection from the available statuses and then going through and creating a hundred messages and the messages are going to be assigned to a random user it's generating some fake data and I'm going to set the message red to a true or false and it's just going to be a random sample right so to get started I'll run rails DB migrate and then also run rails DB seed another said I am running the migration and the seed in the same line and that's something that you're able to do with break tasks you could also do something like a rails DB create DB migrate and DB seed all from the same line and it's going to go through and do its thing and it did see the database it just didn't show any kind of output so then we'll launch the rails console and we can do a user account we see we have our 20 users we do a status count we get our two statuses and then we can do a message count and we have our hundred messages so let's see if we have a problem now where we want to get a list of all of our active users so let's say we have a active statuses and we set this equal to these status where the active is set to true so now we have our collection of all these statuses that are true but we don't need all of the fields for the statuses so we could do something like the same thing except now we add pluck and we just want to return the ID and we should just get a array back and notice that the difference in the queries is the first one is selecting statuses and all columns so whenever you see this asterisks on these statuses dot that's going to return all columns and that's unnecessary and it's a bit of overhead that's not needed we don't need the name attribute or the active attribute or as well as the time stamps and said we're just concerned about the ID where the active status is set to true on the second query where we ran the pluck you can see that we only selected these statuses ID from these statuses table where the active is set to one or true and instead of getting back a active record collection or a relation this time we got back just an array so now that we have an array of ID's of our active statuses we can call the active users is equal to the user dot where and we want to find where these status ID is said to the array of the active statuses and if we have multiple active statuses in this array then we can still pass it in like this and it will return our list of records and we can call that size on the end here to just see what the count is so we have ten active users however I think that there is a much better way instead of running two separate lines code or queries to do this we could do something like a user dot joins and we're going to join these status table and from here within our query we then reference these statuses and we want to find where all these statuses has the active set to true and so now you can see that we ran just one query and this one query did a inner join on these statuses and it still performed the query where the active status is true if we get a size on this we can see that we still have our 10 users so while this query is good in ficient and it only makes one call out to the database Asil thing that this can be cleaned up a bit because realistically when you are using this in your application you don't want to have to have this replicated code over multiple places in your application and this does seem like one of the type of things that you would be calling multiple times throughout the application and a scope is basically a class method that you can call with self dot and we'll call this active and then we'll call the where and then the active is set to true however on single lines I really don't like using a class method like this instead I'll actually create a scope and the scope alcohol active again and then I'll create a lambda and within the lambda I can call the where the active is set to true and this is going to do the same thing as the class method and the difference between a class method and a instance method an instance method would be something like def active and then it's going to return something like this and the main difference is you can call set aside active and it's going to return a active record collection of all these statuses that have the active set to true with a instance method you would have to first call these status maybe dot first to get the first record and then you can call active so this isn't really applicable in our case because we're not dealing with one record we're dealing with our collection of records so now if we were to call satis at active you'll see that it doesn't work because we haven't reloaded our console so instead we need to call reload with the bang first and this is going to reload the rails application we can then call these status stud active and then we get our active record collection so now that we know that we had the status active to get our active statuses let's try to see if we can change something like the pluck ID to get our list of ID's you can see that that works and it yields the exact same query as we had initially when we ran the separate query plucking the ID so let's get our users again we joins our status and then we can call where these statuses and then on these statuses we can search where the ID is equal to our status active and the pluck ID we can call that size to see that we still get our 10 users but Nunda said this does make the two queries because we have our status active pluck ID which is one query and then we have this outside query and really you wouldn't have to join such statuses because we have our IDs we could just search on these status ID on the user however taking this let's see if we can't clean this up a little more so instead of calling the where you can actually call something called merge and with the merge we can reference our status not active and this is going to do essentially the same single query and because we are able to chain that merged query within our console let's try to go ahead and add the scope under our user so we have our scope and we'll call this the active will create another lamda and we'll call the joins status just like we did before and then we'll call the merge and we'll reference our other scope on these status and going back to our console will call the reload just to pick up our new code and then we can call the user not active and you can see that this is calling the same query as it was before except before we're calling the count so it wasn't selecting all the records whoever you were to call the user active and then this size you can see that we're getting the same query as we were before and now we just had this user dot active so this is much cleaner and for the most part it's pretty clear what is expecting to do so next let's look at some of the messages so we'll set our user equals to the user first and then if we look at our user messages because a user has many messages we can see that this user has four messages if we pluck the red column we can see that the user has three unread messages and then one of the messages has already been read so if we want to find all of the messages that the user has that is unread then we could do something like user type messages where red is equal to false and this works and we can also get dot size to see that we have our three unread messages however again we may use this throughout the application especially if we are using it in something like a header where we can show the user that they have X number of unread messages so instead I would like to create a scope so we don't have to keep typing the where read is equal to false just in case if we had to refactor this sometime down the road we would only have to edit it in one place instead of multiple so in our message model we'll create a scope and we'll just call this the unread and within our lambda will call the where where the read is equal to false and likely we would also probably want one eventually for the read messages where the read is equal to true so reloading the application we can get our user eagle to the user dot first and then we can do our user messages dot unread if we get the size on this you see that we still have our three messages so let's say we wanted to look at our user active so this is going to return all of our active users and we have ten of them whatever it let's say if we also would define all of the active users unread messages so this gets a bit more complicated because now we are training on three different models we have our users that we're looking up and that we have our status model where we need to search where the users are active based on these status active attribute and then we need to go up onto the messages to see where the messages have any unread so this is actually very simple so then we can chain in with our active and then call the joins and then the messages and we can merge the message unread so very similar to what we were doing before but now we're just changing it a bit deeper and then we can check these sides of this and we're going to get the 37 messages so this is getting the count of unread messages for active users because remember we only have ten users and of those ten users they have 37 unread messages if we were to just check the messages unread dot size we'll see that we're getting a much larger number because this is including the inactive users as well and with this we can also create a nother scope on our users and with this scope we could probably call this the unread messages and we would just simply copy and paste in what we had before you can see that this looks very similar to our active scope so reloading the console we can then call the user active to get our active users and then the unread messages and if we call that size on there we would so expect the 37 and there's also a couple other cool little tricks that I like to show so let's say if we have our active users you can then call scoping on here and with the scoping you can pass in a block and you can do something like user dot last if we call it on here you can see that this returns to user ID number 17 however if we were simply to call user dot last you can see that it returns a user ID 20 so with the scoping this user lass is in reference to what we have up here with the user active but in the scoping we pass in our block and then we're able to perform some other kind of query and let's say the unread messages is something for a particular user or for any user where it is something that is always going to be called so throughout your application you are just using this everywhere and it might not be messages it could be something else however it's something where whenever you were pulling up a user or referencing a user you are always going to reference also the unread messages so there's something in rails called the default scope so with the default scope you're able to include something so you can do something like includes the messages and then you can do something like the unread messages so if we reload our console we can do the user dot first and then you can see that we get our user and then we're also getting all of the messages and I broke it out because we have either loaded the messages as well so if we have our user dot first but then we do the messages and if we get the first message you can see that we still have just those two queries read because we have eager loaded all of the messages and with the same query call well that's all for this episode thank you for watching for more videos check out drift and ruby calm
Info
Channel: Drifting Ruby
Views: 20,478
Rating: undefined out of 5
Keywords: rails, development, screencast, tutorial, learning, education, tips, tricks, podcasts, programming, ruby, framework, training, activerecord
Id: 1ZkwvPMiq4Q
Channel Id: undefined
Length: 13min 26sec (806 seconds)
Published: Sun Apr 01 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.