2015-04-22 82 views
-2

我正在嘗試將save_with_initial_vote方法添加到我的Post類中。它應該保存該帖子並在交易中創建投票。Ruby on Rails:未定義方法` - '爲零:NilClass

post.rb看起來是這樣的:

class Post < ActiveRecord::Base 
     has_one :summary 
     has_many :comments, dependent: :destroy 
     has_many :votes, dependent: :destroy 
     belongs_to :user 
     belongs_to :topic 
     mount_uploader :image, ImageUploader 
     def up_votes 
     votes.where(value: 1).count 
     end 
     def down_votes 
     votes.where(value: -1).count 
     end 
     def points 
     votes.sum(:value) 
     end 
     def update_rank 
     age_in_days = (created_at - Time.new(1970,1,1))/(60 * 60 * 24) # 1 day in seconds 
     new_rank = points + age_in_days 
     update_attribute(:rank, new_rank) 
     end 
     default_scope { order('rank DESC') } 
     scope :ordered_by_title, -> { order('posts.title ASC') } 
     scope :ordered_by_reverse_created_at, -> { order('posts.created_at DESC') } 
     validates :title, length: { minimum: 5 }, presence: true 
     validates :body, length: { minimum: 20 }, presence: true 
     validates :topic, presence: true 
     validates :user, presence: true 
     def markdown_title 
      render_as_markdown(self.title) 
     end 
     def markdown_body 
      render_as_markdown(self.body) 
     end 
     def create_vote 
      user.votes.create(value: 1, post: self) 
     end 
     def save_with_initial_vote 
      ActiveRecord::Base.transaction do 
      save 
      user.votes.create(value: 1, post: self) 
      end 
     end 

     private 

     def render_as_markdown(markdown) 
      renderer = Redcarpet::Render::HTML.new 
      extensions = {fenced_code_blocks: true} 
      redcarpet = Redcarpet::Markdown.new(renderer, extensions) 
      (redcarpet.render markdown).html_safe 
     end 
    end 

posts_controller.rb看起來是這樣的:

class PostsController < ApplicationController 
    def show 
    @topic = Topic.find(params[:topic_id]) 
    authorize @topic 
    @post = Post.find(params[:id]) 
    @comments = @post.comments 
    end 
    def new 
    @topic = Topic.find(params[:topic_id]) 
    @post = Post.new 
    authorize @post 
    end 
    def edit 
    @topic = Topic.find(params[:topic_id]) 
    @post = Post.find(params[:id]) 
    authorize @post 
    end 
    def create 
    @topic = Topic.find(params[:topic_id]) 
    @post = current_user.posts.build(post_params) 
    authorize @post 
    if @post.save_with_initial_vote 
     flash[:notice] = "Post was saved." 
     redirect_to [@topic, @post] 
    else 
     flash[:error] = "There was an error saving the post. Please try again." 
     render :new 
    end 
    end 
    def update 
    @topic = Topic.find(params[:topic_id]) 
    @post = Post.find(params[:id]) 
    authorize @post 
    if @post.update_attributes(post_params) 
     flash[:notice] = "Post was updated." 
     redirect_to [@topic, @post] 
    else 
     flash[:error] = "There was an error saving the post. Please try again." 
     render :new 
    end 
    end 
    def destroy 
    @topic = Topic.find(params[:topic_id]) 
    @post = Post.find(params[:id]) 
    authorize @post 
    if @post.destroy 
     flash[:notice] = "\"#{@post.title}\" was deleted." 
     redirect_to @topic 
    else 
     flash[:error] = "There was an error deleting your post. Please try again." 
     render :show 
    end 
    end 

    private 

    def post_params 
    params.require(:post).permit(:title, :body, :image) 
    end 
end 

vote.rb看起來是這樣的:

class Vote < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :post 
    validates :value, inclusion: {in: [-1, 1], message: "%{value} is not a valid vote." } 
    after_save :update_post 

    private 

    def update_post 
    post.update_rank 
    end 
end 

當我這樣做,我得到一個錯誤:

undefined method `-' for nil:NilClass 

回答

1

要解決您的問題,首先查看錯誤的來源。該錯誤說「未定義的方法」 - 「爲零:NilClass」。 這意味着你正試圖從一個實際上無的對象中減去。 當您嘗試保存投票時,您可以在vote.rb模型中保存後調用update_post。這將調用Post模型中的update_rank方法。這個方法然後從'created_at'中減去一個Time對象。因此,問題在於created_at返回一個零值。

您可以嘗試使用pry gem來更好地調試您的代碼。然後,您可以在模型/控制器代碼中的任意位置添加'binding.pry',並逐行查看每個變量在當時的值。