2016-11-01 6 views
1

저는이 문제로 꽤 오랫동안 고민되어 왔습니다.pundit policy error 정의되지 않은 메소드 'image'for nil : NilClass

레일즈 4.2.5.1, Pundit 1.1.0 및 Devise를 사용하고 있습니다.

나는 표시하는 블로그 게시물이 다음

  • 제목
  • 저자 이름
  • 이미지
  • (쇼 페이지)
  • 몸 (인덱스 페이지)
  • 소독 발췌

색인 페이지가 올바르게 표시됩니다 (예외 사용자 이름 param을 인식하지 못하기 때문에 표시되지 않는 작성자 사용자 이름). 나는 이미지를 표시하는 코드 행을 제거하면, 나는 같은과 함께 타이틀 오류가

undefined method `image' for nil:NilClass 

: 나는 쇼 페이지를 통해 개인 게시물을 보려고 할 때, 나는 다음과 같은 오류가 발생합니다 정의되지 않은 메소드 오류.

나는 정책과

모든 것이 관리자, 편집자, 그리고 사용자 간의 인증을 만들기위한 학자를 추가하기 전에 완벽하게 작동 된 컨트롤러 (경미한 변경)에 대한 거의 정확하게 SitePoint-source/Authorization_with_Pundit의 예를 따랐다. 여기

내 현재 코드입니다 :

class ApplicationController < ActionController::Base 
    include Pundit 
    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized 

    # Prevent CSRF attacks by raising an exception. 
    # For APIs, you may want to use :null_session instead. 
    protect_from_forgery with: :exception 
    before_filter :configure_permitted_parameters, if: :devise_controller? 

    private 

    def user_not_authorized 
     flash[:alert] = "Access denied. You are not authorized to view that page." 
     redirect_to (request.referrer || root_path) 
    end 


protected 

    def configure_permitted_parameters 
    devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) } 
    devise_parameter_sanitizer.permit(:sign_in) { |u| u.permit(:username, :email, :password, :remember_me) } 
    devise_parameter_sanitizer.permit(:account_update) {|u| u.permit(:username, :email, :password, :password_confirmation, :current_password)} 
    end 


end 

포스트 컨트롤러

응용 프로그램 컨트롤러

class PostsController < ApplicationController 
    before_action :set_post, only: [:show, :edit, :update, :destroy] 
    after_action :verify_authorized, only: [:destroy] 
    after_action :verify_policy_scoped, only: [:user_posts] 

    def index 
    @meta_title = "Blog" 
    @meta_description = "description here" 
    @posts = Post.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 4) 
    end 

    def show 
    end 

    def new 
    @meta_title = "Add New Blog" 
    @meta_description ="Add a new blog to your profile." 
    @post = Post.new 
    end 

    def edit 
    @meta_title = "Edit Blog" 
    @meta_description ="Edit an existing blog from your profile." 
    end 

    def create 
    @post = Post.new 
    @post.update_attributes(permitted_attributes(@post)) 

    if @post.save 
     redirect_to @post, notice: 'Post was successfully created.' 
    else 
     render :new 
    end 
    end 

    def update 

    @post = Post.find(params[:id]) 
    if @post.update_attributes(permitted_attributes(@post)) 
     redirect_to @post, notice: 'Post was successfully updated.' 
    else 
     render :edit 
    end 
    end 

    def destroy 
    if @post.present? 
     authorize @post 
     @post.destroy 
    else 
     skip_authorization 
    end 

    redirect_to posts_url, notice: 'Post was successfully deleted.' 
    end 

    def user_posts 
    @posts = policy_scope(Post) 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_post 
     @post = Post.find_by(id: params[:id]) 
    end 

    # Only allow the white list through. 
    def post_params 
     params.require(:post).permit(policy(@post).permitted_attributes) 
    end 
end 

응용 프로그램 정책

01 23,516,
class ApplicationPolicy 
    attr_reader :user, :record 

    def initialize(user, record) 
    raise Pundit::NotAuthorizedError, "You must be logged in to perform this action" unless user 
    @user = user 
    @record = record 
    end 

    def index? 
    false 
    end 

    def show? 
    scope.where(:id => record.id).exists? 
    end 

    def create? 
    false 
    end 

    def new? 
    create? 
    end 

    def update? 
    false 
    end 

    def edit? 
    update? 
    end 

    def destroy? 
    false 
    end 

    def scope 
    Pundit.policy_scope!(user, record.class) 
    end 

    class Scope 
    attr_reader :user, :scope 

    def initialize(user, scope) 
     @user = user 
     @scope = scope 
    end 

    def resolve 
     scope 
    end 
    end 
end 

포스트 정책

class PostPolicy < ApplicationPolicy 
    class Scope < Scope 
    def resolve 
     scope.where(user: user) 
    end 
    end 

    def permitted_attributes 
    if user.admin? || user.editor? 
     [:title, :body, :image, :permalink, :description, :tag_list, :username] 
    else 
     [:title, :body, :image, :username] 
    end 
    end 

    def new? 
    user.admin? || user.editor? 
    end 

    def index? 
    true 
    end 

    def create? 
    user.admin? || user.editor? 
    end 

    def update? 
    user.admin? || user.editor? || record.user == user 
    end 

    def destroy? 
    user.admin? || record.user == user 
    end 
end 

게시 할 수 있습니다.

class Post < ActiveRecord::Base 
    include ActiveModel::ForbiddenAttributesProtection 
    belongs_to :user 

    # This method associates the attribute ":image" with a file attachment 
    has_attached_file :image, styles: { 
     thumb: '100x100>', 
     square: '200x200#', 
     medium: '300x300>', 
    } 

    extend FriendlyId 
    friendly_id :permalink, use: [:slugged, :history, :finders] 
    validates :permalink, presence: true, uniqueness: true 
    validates :title, presence: true, length: { minimum: 5} 
    validates :description, presence: true, uniqueness: true, length: {maximum: 160} 
    validates :body, presence: true 
    validates :image, presence: true 
    # Validate the attached image is image/jpg, image/png, etc 
    validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/ 

    def should_generate_new_friendly_id? 
     permalink_changed? 
    end 
end 

우편 번호는

<% provide(:title, "@post.title") %> 
<% provide(:description, "@post.description") %> 

<div class="row"> 
    <div class="col-md-offset-1 col-md-10"> 
    <div class="panel panel-default"> 
     <div class="panel-heading center"> 
     <%= image_tag @post.image.url, :style => "width: 100%; height: auto;" %> 
     </div> 
     <div class="panel-body"> 
     <h2 class="title center"><%= @post.title %></h2> 
     <p class="posted"><i class="ion-android-time"></i> <%= @post.created_at.strftime("%B %d, %Y") %> </p> 
     <p class="posted"><i class="ion-person"></i> Author: <%= link_to @post.username, about_path(:anchor => "coaches") %></p> 
     <hr> 
     <div class="postBody" id="summernote"> 
      <%= @post.body.html_safe %> 
     </div> 
     </div> 
     <div class="panel-footer center"> 
     <%= link_to 'Back', posts_path %> | 
     <%= link_to 'Edit', edit_post_path(@post) %> | 
     <%= link_to 'Delete', @post, method: :delete, data: { confirm: 'Are you sure you want to delete this post?' } %> 
     <%= render 'disqus' %> 
     </div> 
     <div class="panel-footer center"> 
     <%= link_to 'Back', posts_path %> 
     </div> 
    </div> 
    </div> 
</div> 

을 보여 경우 rb 게시글 # 지수

<div class="container"> 
    <div class="row"> 
    <div class="col-md-9"> 
     <% @posts.each do |post| %> 
     <div class="post-wrapper"> 
      <h3 class="title center"><%= link_to post.title, post %></h3> 
      <p class="posted"><i class="ion-android-time"></i> <%= post.created_at.strftime("%B %d, %Y") %></p> 
      <p class="posted"><i class="ion-person"></i> Author: <%= link_to post.user(:username), about_path(:anchor => "coaches") %></p><br> 
      <div class="post-image center"><%= link_to image_tag(post.image.url, :style => "width: 100%; height: auto;"), post %></div><br> 

      <%= sanitize(post.body[0,300]) %>...<br> 
      <div class="center"> 
       <%= link_to 'View Blog', post, class: "btn btn-primary" %> 
       <% if policy(post).update? %> 
       <%= link_to 'Edit', edit_post_path(post) %> | 
       <% end %> 
       <% if policy(post).destroy? %> 
       <%= link_to 'Delete', post, method: :delete, data: { confirm: 'Are you sure?' } %> 
       <% end %> 
      </div> 
      <br> 
     </div> 
     <% end %> 
     <div class="center"> 
     <%= will_paginate @posts, renderer: BootstrapPagination::Rails %> 
     </div> 
    </div> 
    </div> 
</div> 
나는 또한 희망이 문제를 한 번 스스로 해결할 몇 가지 다른 문제가

수정 됨 :

  • 삭제 된 게시물은 삭제 말하는 플래시 메시지가 있지만
  • 편집 올리기이 그들로 사용자의 비는 서명
  • 메시지와 게시물을 볼 수있는 권한을 거부 같은 이미지 오류 원하는됩니다 아직 거기 로그인 여부에 관계없이 모든 게시물을 볼 수 있습니다. 이것은 같은 문제이지만 해결책은 저를 위해 작동하지 않으며 어떤 유형의 레일 오류 메시지도받지 못합니다 : Pundit policy_scope error. 어쩌면 이것은 앱 정책의 초기화와 관련이 있을까요?

이러한 다른 문제는 나중에 해결할 수 있습니다. 오류가 표시되면 도움을 주셔서 감사드립니다.

이 지금 내 주요 문제는 undefined method "image" for nil:NilClass 오류

+0

경로 파일에 무엇이 있습니까? – ArtOfCode

+0

'<% = image_tag @ post.image.url, : style => "width : 100 %, height : auto;" %>'이 줄이 아니야? – SomeSchmo

답변

0
undefined method `image' for nil:NilClass 

이 개체가 당신이 (@post 인)에 .image 전화를 위해 노력하고 있음을 의미를 해결하기 위해 노력 nil입니다. 저것을 찾아 내고 를 찾아내는 이유는입니다.

Posts#show보기에서 set_post 콜백을 사용하여 소식을 설정하고 있습니다. set_post 콜백은 id 매개 변수가있는 Post.find_by 매개 변수를 사용하여 레코드를 찾습니다. 이 주어진 것 매개 변수가 nil 경우

방법 find_by 동작합니다이 nil을 반환하는 것입니다 (당신이 Post.find_by(id: nil)를 호출하는 경우 즉, 당신은 다시 nil를 얻을 수 있습니다). 이것은 params[:id] 자체가 nil임을 나타낼 수 있습니다 - 쿼리 문자열 매개 변수 (example.com/posts/show?id=12) 또는 URL 자체 (example.com/posts/12)의 일부로 설정되어 있는지 확인하십시오. 당신은이 시점에서 - 실행하면서

def show 
    byebug 
end 

이 작업을 중단하며, 당신과 함께 일할 수있는 콘솔을 제공합니다 : 당신이 말할 수없는 경우

, 당신의 Posts#show 행동에 byebug 호출을 추가 그 값이 무엇인지 알아 내기 위해 params[:id]을 입력 할 수 있습니다.

Post.find_by을 사용하는 대신 Post.find을 사용하는 것이 좋습니다. 차이점은 find은 기본적으로 ID를 사용하므로 (사용중인 매개 변수를 지정할 필요가 없음) 레코드를 찾을 수없는 경우 nil을 반환하는 대신 404 찾을 수 없음 응답을 발생시킵니다.이렇게하려면 set_post 콜백이 다음과 같이 표시되어야합니다.

def set_post 
    @post = Post.find params[:id] 
end 
+0

'find_by'대신 'Post.find'를 사용했습니다. 도와 줘서 고마워! 또한 게시물을 편집하고 실제로 게시물을 삭제할 수 없다는 문제를 해결했습니다. 게시물과 관련된 사용자의 사용자 이름 표시 문제 (이 부분은 여전히 ​​'nil'. =이됩니다.)로 인해 비 사용자가 게시물을 볼 수있게되고 브라우저 탭에 제목이 다시 표시됩니다. . 그러나 나는 최종 제품으로 한단계 도약하고 있습니다. 다시 한번 감사드립니다! 나는 당신의 답을 해결책으로 표시 할 것입니다. – Nate