It is really helpful. I've also seen CanCan. But I'm little bit confuse, which one should I use? Do you have any suggestion? Beside this I've a request that it'll be very helpful, if provide a video on angularjs with rails.
Use whichever one makes the most sense to you. I tend to prefer Pundit, but that's my preference.
Pundit seems to look more like the rest of my app. I do like that in cancancan you can do the can? wrap which looks really sweet and you have the authorize resources in your controllers but once I get into abilities.rb things start to get messy.
Testing with Rspec seems to look quite similar for both after viewing an existing app I have inherited and looked at this article from Thunderbolt Labs http://thunderboltlabs.com/....
This article was also a good read to get the initial purpose for pundit http://www.elabs.se/blog/52....
I have a couple of questions: When are you actually passing in user and record into the the Pundit class because you never explicitly call ApplicationPolicy.new or PostPolicy.new ? How does Pundit know to assign a post to record variable and a user to user variable? Lastly does pundit know to associate @post with the PostPolicy?
You're always calling PostPolicy.new but Pundit provides a helper that creates the new policy and sends in those objects.
Since we inherited from ApplicationPolicy, the initialize method there is the one that sets the user and record variables. We created that, not Pundit so you have full control there.
When you call "authorize @post" it looks at the @post.class which is Post. Then it makes that a string, adds "Policy" on the end and looks up that class which would be "PostPolicy". That's how it knows to grab the right policy.
Hey @excid3:disqus I'm getting a strange error towards the end of the video where we add user == post.user I don't understand why this is happening because I have Devise setup properly. Any suggestions?
The error is happening inside Pundit. Check line 11 in your category_policy.rb. You're calling ".user" on something there that isn't valid. :)
Yeah I've been playing with it for awhile. My models look correct, user has_many categories and category belongs_to user but I'm still nt able to call category.user. I went in rails console and the associations are working.
Is "category" an instance or the class of the model itself? Only the instances have the relation so maybe you're testing the model? You may want to inspect exactly what the variable "category" is in the console.
category is a class of the model (I think:). I've not had this issue before. Should be pretty straight forward.
When I write category.inspect this is the output. (this is for the first category.)
"#<category id:="" 5,="" name:="" \"discovery="" tools\",="" created_at:="" \"2015-09-01="" 17:41:24\",="" updated_at:="" \"2015-09-01="" 17:41:24\",="" user_id:="" 1="">"
ok I got it... I was calling the class in the view instead of the actual instance... now I get it! learned something new. Thanks @excid3:disqus
Whoo! That's one of those gotchas that I didn't even think of until you mentioned it. :) Glad you got it working!
Very useful episode. Two things came into my mind while watching it regarding the best practice using pundit combined with devise:
- Since pundit policy is checking for user presence, devise before_action :authenticate_user! seems redundant. Is it good practice to keep it or delete it ?
- Another thing that seems interesting with pundit is scope, which let you avoid dealing with query starting with current_user.something. I tend to use the User class directly (instead of the current_user) on my queries, it allows me to let the user owning the object (address, avatar) or the admin editing the data simply by navigating on the users#edit page (or registrations#edit if devise). Is it a good practice or there is a better way ? Thank you in advance for your lights.
Hey Chris, thanks for the awesome video; however, I wonder how would you still use Pundit's provided helpers in an Angular raw html view?
For example, as you've explained in the video, you can use:
<% if policy(MyClass).new? %>
Do you know how I can leverage Pundit's helpers in a non erb view?
Hi Chris, please could you do another podcast that goes deeper than this. I'm struggling big time (current issues outlined here: http://stackoverflow.com/qu... ). It would be great to see you set scopes based on who the current user is and the conditions attaching to the record. I've been trying for 2 years to figure this out now and need some help. Do you think you could show how to use the scope and resolve methods in detail. Thank you
Yea, I had to use: <% if policy(@post).edit? %> in the Show View. policy(Post).edit? wouldn't work.
I notice that you add:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
after_action :verify_authorized, unless: :devise_controller?
In other tutorials I have seen :
class ApplicationController < ActionController::Base
after_action :verify_policy_scoped, unless: :devise_controller?
is there any difference with including things before or after the protect?
It shouldn't make any difference. Traditionally people do includes at the very top and that's what I generally do too, but in this case I just pasted below to make it a little more clear.
Hey guys, I'm hoping for some advice on how to set a role for a user when signing up. My signup page has 2 options (as images); music supervisor and artist. Both go to the User/new form. In my User model I added a :role column. My goal is to have a user click an image; either supervisor or artist and when they sign up it adds that role name to the database. I know I could use an option field in the form, but I would love to do it this way.
I added this to my Routes:
devise_scope :user do
get "/users/sign_up/:role", to: 'devise/registrations#new', as: 'new_user_with_role'
And each image has it's respected url like:
link_to new_user_with_role_path(role: 'supervisor')
So the url looks like: /users/sign_up/supervisor
I added a hidden field and unsuccessfully tried sucking the params through the field to the database, but I think that's an unsecure way to do this.
Any ideas on a good way to do this? Thanks!