2013-07-24 28 views
0

模式:before_create拋出NoMethodError?

create_table "posts", force: true do |t| 
    t.string "title" 
    t.text  "content" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.integer "user_id" 
    t.integer "total_stars" 
    t.integer "average_stars" 
    end 

    create_table "stars", force: true do |t| 
    t.integer "starable_id" 
    t.string "starable_type" 
    t.integer "user_id" 
    t.integer "number" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    add_index "stars", ["starable_id", "starable_type"], name: "index_stars_on_starable_id_and_starable_type" 

    create_table "users", force: true do |t| 
    t.string "name" 
    t.string "email" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

型號:

class Post < ActiveRecord::Base 
    has_many :stars, :as => :starable, :dependent => :destroy 
    belongs_to :user 
end 

class Star < ActiveRecord::Base 
    before_create :add_to_total_stars 

    belongs_to :starable, :polymorphic => true 

    protected 

    def add_to_total_stars 
    if [Post].include?(starable.class) 
     self.starable.update_column(:total_stars, starable.total_stars + self.number) 
    end 
    end 
end 

class User < ActiveRecord::Base 
    has_many :posts, dependent: :destroy 
    has_many :votes, dependent: :destroy 
end 

於是,我就創造了Rails的控制檯這樣的明星:

post = Post.first 
user = User.first 
star = post.stars.build(number: 1) 
star.user_id = user.id 

而且一切正常的話,直到」這裏。但是,當我嘗試將其保存:

star.save 

我得到這個錯誤:

NoMethodError: undefined method +' for nil:NilClass from /home/alex/rails/rating/app/models/star.rb:10:in add_to_total_stars' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:377:in _run__956917800__create__callbacks' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:80:in run_callbacks' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-4.0.0/lib/active_record/callbacks.rb:303:in create_record' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-4.0.0/lib/active_record/timestamp.rb:57:in create_record' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-4.0.0/lib/active_record/persistence.rb:466:in create_or_update' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-4.0.0/lib/active_record/callbacks.rb:299:in block in create_or_update' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:383:in _run__956917800__save__callbacks' from /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:80:in run_callbacks'

可能是什麼原因?

(我使用Rails 4)

回答

1

它看起來像的Post.first.total_stars的價值爲零。按照您的架構和模型示例,您允許在數據庫中爲null,並且不驗證它在ActiveRecord中的存在。

如果將此值默認爲0是有意義的,那麼您應該在模式中設置默認值。

所以我會添加以下架構:

create_table "posts", force: true do |t| 
    # ... 
    t.integer "total_stars", null: false, default: 0 
end 

而且在模型下面的驗證:

class Post < ActiveRecord::Base 
    has_many :stars, :as => :starable, :dependent => :destroy 
    belongs_to :user 

    validates :total_stars, presence: true 
end 

順便說一句,我就會完全擺脫total_stars,讓軌道改爲使用counter_cache選項替代您。這裏是Railscast screencast讓你開始。

1

您獲得的錯誤,因爲starable.total_stars是零在回調方法。你需要確保starable.total_stars設置爲0 RO可以調用to_i方法就可以了(nil.to_i #=> 0),以確保您有0,如果沒有初始化

相關問題