0

スキーマ:

  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: /home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:377:in run_callbacks からの未定義メソッド+' for nil:NilClass from /home/alex/rails/rating/app/models/star.rb:10:inadd_to_total_stars _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 ' 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:increate_record' from /home/alex/.rvm/gems/ruby-1.9 .3-p0/gems/activerecord-4.0.0/lib/active_record/persistence.rb:466: 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/home/alex/.rvm/gems/ruby-1.9.3-p0/gems/activesupport からの create_or_update のブロック内-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を使用しています)

4

2 に答える 2

1

の値Post.first.total_starsは nil のようです。スキーマとモデルの例では、データベースで 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 のスクリーンキャストです。

于 2013-07-24T18:47:40.180 に答える