title: Ruby on Rails - pundit gem - undefined method
body: <p>Don't know why this is happening here.</p>
  
  <p>NoMethodError in PostsController#update
  undefined method `user' for nil:NilClass</p>
  
  <p>My user has admin : true and I can't update other users.posts.</p>
  
  <p>I want to let all users see the content, but only registered users can create content. And if the user is admin or the creator of that content he can edit/update/destroy it as well.</p>
  
  <p>post.rb</p>
  
  <pre><code>class Post &lt; ApplicationRecord
    belongs_to :user
    has_many :comments, dependent: :destroy
  
    validates :title, presence: true, length: { minimum: 5 }
    validates :body, presence: true, length: { minimum: 240 }
  
  
  end
  </code></pre>
  
  <p>user.rb </p>
  
  <pre><code>class User &lt; ApplicationRecord
    include Encryptable
  
    has_many :posts, dependent: :destroy
    has_many :comments, dependent: :destroy
  
    has_attached_file :avatar
    validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\z/
    validates :level, numericality: { less_than_or_equal_to: 100,  only_integer: true }, allow_blank: true
  
    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable and :omniauthable
    devise :database_authenticatable, :registerable,
           :recoverable, :rememberable, :trackable
  
    before_validation :downcase_email #, :populate_iv_fields #if you need/want iv to change more often
    before_create :create_encryption_key
    after_create :save_encryption_key
    after_create :build_user_consents
    attr_encrypted :email, key: :encryption_key
    has_many :user_consents, dependent: :destroy
  
    #entry point for exporting user's personal information
    def self.export_personal_information(user_id)
      return nil unless User.exists?(user_id)
      descendants = ApplicationRecord.descendants.reject{|model| !model.has_personal_information?}
      result = Hash.new
      descendants.each do |descendant|
        result[descendant.name] = descendant.export_personal_information_from_model(user_id)
      end
      return result
    end
    #simplest example, we just export to json
    def self.export_personal_information_from_model(user_id)
      return User.find(user_id).to_json
    end
    #overwrite this to true for methods that you will want to be included in export_personal_information
    def self.has_personal_information?
      true
    end
  
    #helper method if you are creating a user from console and want them to have all consents set
    def fill_consents
      hash = Hash.new
      ConsentCategory.all.map(&amp;:id).each do |id|
        hash[id]='on'
      end
      self.registration_consents=hash
    end
  
    #unfortunately not having an email field that you can just "write to" breaks
    #Devise. Below some necessary workarounds
  
    def email_changed?
      encrypted_email_changed?
    end
  
    def downcase_email
      self.email = self.email.downcase
    end
  
    def registration_consents=(consents)
      @consents = consents
    end
  
    def registration_consents
      @consents
    end
  
    validate                  :validate_consents_completeness
    validates_presence_of     :email, if: :email_required?
    validates_uniqueness_of   :username, allow_blank: false, if: :username_changed?
    validates_length_of       :username, within: 6..20, allow_blank: true
  
    validate                  :validate_email_uniqueness #validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
    validates_format_of       :email, with: Devise.email_regexp, allow_blank: true, if: :email_changed?
    validates_presence_of     :password, if: :password_required?
    validates_confirmation_of :password, if: :password_required?
    validates_length_of       :password, within: Devise.password_length, allow_blank: true
  
    def password_required?
      !persisted? || !password.nil? || !password_confirmation.nil?
    end
    #end original devise
  
    def email_changed?
      self.encrypted_email_changed?
    end
  
    def email_required?
      true
    end
  
    def email_unique?
      records = Array(self.class.find_by_email(self.email))
      records.reject{|u| self.persisted? &amp;&amp; u.id == self.id}.empty?
    end
    #unfortunately, this is an O(n) operation now that has to go through ALL the users to see if an email is unique. Sorry!
    #if you need it to ne O(1) then consider adding email_hash field instead
    def self.find_by_email(email)
      users = User.all
      users.each do |user|
        return user if user.email.downcase == email.downcase
      end
      return nil
    end
  
    protected
  
    def validate_email_uniqueness
      errors.add(:email, :taken) unless email_unique?
    end
  
    def validate_consents_completeness
      return if self.id #we assume that already created user has all consents
      errors.add(:registration_consents, 'Sie müssen allen erforderlichen Bedingungen zustimmen um fortzufahren.') and return unless self.registration_consents
      consents = ConsentCategory.where(mandatory: true).map(&amp;:id)
      ids = self.registration_consents.keys.map(&amp;:to_i) #we are relying on a fact that checkboxes that are not checked are not sent to Rails back-end at all
      consents.each do |consent_type|
        errors.add(:registration_consents, 'Sie müssen allen erforderlichen Bedingungen zustimmen um fortzufahren.') and return unless ids.include?(consent_type)
      end
    end
  
    def build_user_consents
      ids = registration_consents.keys
      categories = ConsentCategory.where(id: ids)
      raise 'Die vom Benutzer eingereichte Zustimmungsliste enthält Objekte, die nicht in der Datenbank vorhanden sind!' if categories.count != ids.count
      categories.each do |category|
        consent = UserConsent.new
        consent.consent_category = category
        consent.user = self
        consent.requires_revalidation = false
        consent.agreed_at = self.created_at
        consent.save!
      end
    end
  
  end
  </code></pre>
  
  <p>post_policy.rb</p>
  
  <pre><code>       class PostPolicy &lt; ApplicationPolicy
    attr_reader :user, :post
  
    def initialize(user, post)
      @user = user
      @post = post
    end
  
    def index?
      true
    end
  
    def create?
      user.present?
    end
  
    def new?
      user.present?
    end
  
    def update?
      return true if post.user_id == user.id || user == user.admin?
    end
  
    def destroy?
      return true if post.user_id == user.id || user == user.admin?
    end
  
    private
  
    def post
      record
    end
  end
  </code></pre>
  
  <p>application_policy.rb</p>
  
  <pre><code>    class ApplicationPolicy
    attr_reader :user, :record
  
    def initialize(user, record)
      @user = user
      @record = record
    end
  
    def index?
      false
    end
  
    def show?
      false
    end
  
    def create?
      false
    end
  
    def new?
      create?
    end
  
    def update?
      user.admin?
    end
  
    def edit?
      user.admin?
    end
  
    def destroy?
      user.admin?
    end
  
    class Scope
      attr_reader :user, :scope
  
      def initialize(user, scope)
        @user = user
        @scope = scope
      end
  
      def resolve
        scope.all
      end
    end
  end
  </code></pre>
  
  <p>post_controller</p>
  
  <pre><code>    class PostsController &lt; ApplicationController
    before_action :find_post, only: %i[destroy edit update comment_owner upvote downvote]
    after_action :verify_authorized, except: [:index, :show]
  
    layout '_app_nav'
  
    def index
      return redirect_to post_path(params[:post_id]) if params[:post_id]
      return redirect_to user_path(params[:user_id]) if params[:user_id]
      @post = Post.all.order('created_at DESC')
      @posts = Post.all.order('created_at DESC')
      @user = User.all
      @posts = if params[:suche]
  
               else
                 Post.all.order('created_at DESC')
  
               end
      @comments = Comment.all
  
    end
  
    def new
      @post = Post.new
  
    end
  
    def create
      @post = current_user.posts.build(post_params)
      authorize @post
      if @post.save!
        redirect_to @post
      else
        render 'new'
      end
    end
  
    def show
      @post = Post.find(params[:id])
      @user = @post.user
      @comments = Comment.where(post_id: @post).order('created_at DESC').paginate(:page =&gt; params[:page], :per_page =&gt; 5)
    end
  
    def edit
      authorize @post
      @post = Post.find(params[:id])
  
    end
  
    def update
      @user = User.find(params[:id])
      @post = Post.find(params[:id])
      authorize @post
      @post.update(title: params[:title], body: params[:post_params])
      redirect_to post_path(@post)
    end
  
    def destroy
      @post = Post.find(params[:id])
      @post.destroy
      authorize @post
  
      redirect_to posts_path
    end
  
  =begin
    def upvote
      @post.upvote_from current_user
      redirect_to post_path(@post)
    end
  
    def downvote
      @post.downvote_from current_user
      redirect_to post_path(@post)
    end
  =end
  
    private
  
    def post_params
      params.require(:post).permit(:title, :body, :user_id)
    end
  
    def find_post
      @post = Post.find(params[:id])
    end
  
  
  end
  </code></pre>
  
  <p>application_controller</p>
  
  <pre><code>class ApplicationController &lt; ActionController::Base
    include Pundit
    protect_from_forgery with: :exception
    before_action :authenticate_user!
    before_action :configure_permitted_parameters, if: :devise_controller?
  
    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
  
    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up) do |user_params|
        user_params.permit(:username, :email, :password, :password_confirmation, registration_consents: {})
      end
    end
  
    private
  
    def user_not_authorized
      flash[:alert] = 'test'
      redirect_to(root_path)
    end
  
  end
  </code></pre>
  
  <p>registrations_controller:</p>
  
  <pre><code>class RegistrationsController &lt; Devise::RegistrationsController
  
  
    private
  
    def account_update_params
      params.require(:user).permit(:email, :username, :avatar, :current_password, :password, :password_confirmation)
    end
  end
  </code></pre>
  
  <p>edit:</p>
  
  <p>updating my post_policy.rb with @post such as <code>return true if user.present? &amp;&amp; user == @post.user || user == user.admin?</code> resolves in -> Pundit::NotAuthorizedError in PostsController#update
  not allowed to update?</p>