1 00:00:00,000 --> 00:00:02,000 [?music?] 2 00:00:02,000 --> 00:00:05,000 [Master Class: Designer and Developer Workflow: Protecting Job Modification] 3 00:00:05,000 --> 00:00:08,000 [Jim Hoskins] So now we have the ability to log in and log out, 4 00:00:08,000 --> 00:00:12,000 and when we're logged in, we're able to create a new job and when we're logged out, we're not. 5 00:00:12,000 --> 00:00:17,000 And when we create a new job, our currently logged-in user is associated with that job, 6 00:00:17,000 --> 00:00:21,000 as demonstrated by this new one where I was logged in as Nick when I created it 7 00:00:21,000 --> 00:00:23,000 and the job is associated with Nick 8 00:00:23,000 --> 00:00:26,000 while the other ones are associated with the Jim account. 9 00:00:26,000 --> 00:00:31,000 So now that I'm logged in as Nick, should I be able to edit one of Jim's? 10 00:00:31,000 --> 00:00:34,000 Probably not, so how do we go about restricting that? 11 00:00:34,000 --> 00:00:38,000 Well, we can write another before filter, so let's go back to our controller. 12 00:00:38,000 --> 00:00:43,000 So we use another before filter and what I want to do is call this 13 00:00:43,000 --> 00:00:58,000 before_filter :require_job_belongs_to_current_user. 14 00:00:58,000 --> 00:01:02,000 Now, that is a mouthful of a method name, but it really does describe 15 00:01:02,000 --> 00:01:06,000 what we're going for here. 16 00:01:06,000 --> 00:01:09,000 And we only want to do this for edit, which is the edit page, 17 00:01:09,000 --> 00:01:18,000 the update, which is the page that actually handles updating the information 18 00:01:18,000 --> 00:01:22,000 as well as destroy, which destroys the model. 19 00:01:22,000 --> 00:01:25,000 So I'm going to actually write 20 00:01:25,000 --> 00:01:28,000 :require_job_belongs_to_current_user in this controller 21 00:01:28,000 --> 00:01:32,000 and that's because it's really only focused around the jobs controller, 22 00:01:32,000 --> 00:01:35,000 not as general as require_current_user. 23 00:01:35,000 --> 00:01:39,000 So let's just grab that and below all my other methods here, 24 00:01:39,000 --> 00:01:44,000 go ahead and create a private method 25 00:01:44,000 --> 00:01:47,000 that we'll call require_job_belongs_to_current_user. 26 00:01:47,000 --> 00:01:50,000 Now, there's an interesting thing here. 27 00:01:50,000 --> 00:01:56,000 We actually do need to--from within the before filter--fetch the actual job 28 00:01:56,000 --> 00:01:58,000 that's being requested for this particular request, 29 00:01:58,000 --> 00:02:04,000 and we can see how the job is currently being fetched from destroy, update, and edit. 30 00:02:04,000 --> 00:02:08,000 It's simply being assigned to @job = Job.find(params[:id]) 31 00:02:08,000 --> 00:02:11,000 and if we look at the other ones, we see the same thing. 32 00:02:11,000 --> 00:02:17,000 So because our before filter will always be run before edit, update, and destroy, 33 00:02:17,000 --> 00:02:23,000 we can actually set @job from inside of our before filter, 34 00:02:23,000 --> 00:02:26,000 so I'm just going to go ahead and pull that. 35 00:02:26,000 --> 00:02:29,000 We don't need anything in edit anymore 36 00:02:29,000 --> 00:02:34,000 and we can remove the same line from update 37 00:02:34,000 --> 00:02:39,000 and from destroy, 38 00:02:39,000 --> 00:02:42,000 and we'll place it into require_job_belongs_to_current_user. 39 00:02:42,000 --> 00:02:46,000 Just to see that that had no adverse effect, let's just see if we can load up the edit page 40 00:02:46,000 --> 00:02:48,000 with this new code layout. 41 00:02:48,000 --> 00:02:51,000 I have the edit page already loaded, so if I refresh it, 42 00:02:51,000 --> 00:02:56,000 nothing broke because we just simply moved the fetching from one method 43 00:02:56,000 --> 00:02:59,000 to another method that happens right before that method. 44 00:02:59,000 --> 00:03:02,000 So functionally, they pretty much work the same. 45 00:03:02,000 --> 00:03:06,000 So now that we have @job, we actually want to only succeed 46 00:03:06,000 --> 00:03:11,000 if the job belongs to the current user. 47 00:03:11,000 --> 00:03:26,000 Now, one way we could do this is to test job.user_id == current_user.id 48 00:03:26,000 --> 00:03:28,000 and since this is the last line of our method, 49 00:03:28,000 --> 00:03:30,000 it will return true if it's true; 50 00:03:30,000 --> 00:03:36,000 otherwise false, which will stop the page from loading. 51 00:03:36,000 --> 00:03:39,000 So here, I'm on the Fashion Police Officer, which was actually created by Jim 52 00:03:39,000 --> 00:03:42,000 and I'm signed in as Nick, so if I refresh, 53 00:03:42,000 --> 00:03:46,000 so one way we can ensure that the job belongs to the current user 54 00:03:46,000 --> 00:03:50,000 is to actually scope the Job.find to the user's jobs. 55 00:03:50,000 --> 00:03:54,000 So instead of actually using our find method on the job class, 56 00:03:54,000 --> 00:03:59,000 we can do current_user.jobs, and what this will do 57 00:03:59,000 --> 00:04:04,000 is it will actually apply the find method, but only for the current user's jobs 58 00:04:04,000 --> 00:04:09,000 or the jobs where the user_id equals the current user's id, and if there is none, 59 00:04:09,000 --> 00:04:13,000 it will raise an exception for Not Found, which will result in a 404 page. 60 00:04:13,000 --> 00:04:18,000 And this is fine because we shouldn't be linking to the edit page anyway, 61 00:04:18,000 --> 00:04:22,000 so a 404 is actually kind of an appropriate error. 62 00:04:22,000 --> 00:04:26,000 Otherwise, you could modify this logic a little bit to either redirect 63 00:04:26,000 --> 00:04:29,000 or bring up a different type of error, 64 00:04:29,000 --> 00:04:33,000 but the 404 as a harsh error seems like it will work just fine for our needs, 65 00:04:33,000 --> 00:04:35,000 so let's save it out. 66 00:04:35,000 --> 00:04:37,000 So I'm on the edit page for the Fashion Police Officer, 67 00:04:37,000 --> 00:04:40,000 which was something that was created by the Jim account, 68 00:04:40,000 --> 00:04:42,000 and I'm logged in as the Nick account, so if I refresh this page, 69 00:04:42,000 --> 00:04:46,000 the new rule should take into effect and we should get a Not Found error, 70 00:04:46,000 --> 00:04:51,000 and we did because we couldn't find a job with the id of 2 where user_id = 2 71 00:04:51,000 --> 00:04:53,000 and that's how it was scoped to the current user. 72 00:04:53,000 --> 00:04:56,000 So the same thing would happen if we tried to submit the edit form somehow 73 00:04:56,000 --> 00:04:59,000 if we were able to get to it, so it looks like we should be pretty safe. 74 00:04:59,000 --> 00:05:04,000 We shouldn't be able to destroy or edit or update any of the information 75 00:05:04,000 --> 00:05:07,000 on a record that's not ours. 76 00:05:07,000 --> 00:05:12,000 But to check, let's go back, and I'm logged in as Nick, which the only job posting 77 00:05:12,000 --> 00:05:19,000 is Hammock Comfort Specialist, which I can edit and I will update the name of the company 78 00:05:19,000 --> 00:05:22,000 with some exclamation points and save it out, 79 00:05:22,000 --> 00:05:28,000 and we are able to successfully save. 80 00:05:28,000 --> 00:05:33,000 If I sign out and sign in as Jim, 81 00:05:33,000 --> 00:05:36,000 I can now try to edit Fashion Police Officer, for instance, 82 00:05:36,000 --> 00:05:40,000 and change this to Senior, 83 00:05:40,000 --> 00:05:44,000 save it out, and I can. 84 00:05:44,000 --> 00:05:48,000 If I were to try to edit the Hammock Comfort Specialist, again, we get an error. 85 00:05:48,000 --> 00:05:52,000 So one of the last things we want to do is we only want to show edit 86 00:05:52,000 --> 00:05:58,000 if the current user owns the job, so let's go and look in the index, 87 00:05:58,000 --> 00:06:03,000 and here we see our link to edit and what I want to do is I want to wrap this in 88 00:06:03,000 --> 00:06:11,000 - if job.user == current_user 89 00:06:11,000 --> 00:06:15,000 then we will link to edit, so now it's conditional. 90 00:06:15,000 --> 00:06:19,000 So now I'm signed in as Jim, the Hammock Specialist edit has disappeared 91 00:06:19,000 --> 00:06:22,000 and we want to definitely do the same thing here on the actual show page, 92 00:06:22,000 --> 00:06:25,000 which is easy enough to do. 93 00:06:25,000 --> 00:06:31,000 Just take show here, find our edit page, 94 00:06:31,000 --> 00:06:38,000 and here we'll do if @job.user == current_user, 95 00:06:38,000 --> 00:06:42,000 then we'll link to edit and we'll show the little bar there 96 00:06:42,000 --> 00:06:46,000 and Nick can fix up the markup for that when he gets to this page. 97 00:06:46,000 --> 00:06:51,000 So we'll save it out, refresh, and I forgot to put a - there. 98 00:06:51,000 --> 00:06:55,000 Otherwise, it was just interpreted as plain text, and there we go. 99 00:06:55,000 --> 00:06:59,000 So now we only see the Back button, but if we go to one of ours, 100 00:06:59,000 --> 00:07:03,000 we can see we have an Edit button, so now, we are restricted 101 00:07:03,000 --> 00:07:07,000 to only editing the jobs that we have created.