2 Stimmen

Rails-Modell create und new gibt in der Testumgebung nil zurück

Ich habe eine Model-Spezifikation, die mit "undefined method 'save' for nil:NilClass'" fehlschlägt. Dies tritt in der Klassenmethode 'create_and_send_self_eval' auf. Die Methode erstellt eine neue Bewertung, gibt jedoch immer nil in der Testumgebung zurück. Ich habe auch 'create' und 'create!' versucht und sie geben ebenfalls nil zurück. Dies tritt jedoch nur in der Testumgebung auf. In der Entwicklungsumgebung gibt es das richtige Objekt zurück. Ich verwende rspec 3.1.5, Rails 4.1.6 und Ruby 2.1.2.

Ich habe den Code für die Klasse und meine Debug-Ausgabe hinzugefügt. Irgendwelche Vorschläge?

Evaluation.rb

class Evaluation < ActiveRecord::Base
  has_one :evaluator
  validates_uniqueness_of :access_key
  validates_presence_of :participant_id

  before_validation :set_access_key, on: :create

  def send_invite
    return true
  end

  def self.create_and_send_self_eval(participant)
    evaluation = self.new do |e|
      e.participant_id = participant.id
      e.evaluator = participant
    end
    if evaluation.nil?
      binding.pry
    end
    evaluation.save
  end

  private

    def set_access_key
      return if access_key.present?

      begin
        self.access_key = SecureRandom.hex(8)
      end while self.class.exists?(access_key: self.access_key)
    end

end

Debug-Ausgabe mit pry in der Testumgebung

[1] pry(Evaluation)> participant
=> #
[2] pry(Evaluation)> Evaluation.new
=> nil
[3] pry(Evaluation)> Evaluation.create(participant_id: participant.id)
NoMethodError: undefined method `save' for nil:NilClass
from /Users/diyahm/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.6/lib/active_record/persistence.rb:34:in `create'
[4] pry(Evaluation)> Evaluation.create!(participant_id: participant.id)
NoMethodError: undefined method `save!' for nil:NilClass
from /Users/diyahm/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.6/lib/active_record/validations.rb:41:in `create!'

Debug-Ausgabe in der Rails-Konsole

2.1.2 :005 > p = Participant.last
  SQL (0.9ms)  SELECT  "participants"."id" AS t0_r0, "participants"."first_name" AS t0_r1, "participants"."last_name" AS t0_r2, "participants"."evaluation_url" AS t0_r3, "participants"."created_at" AS t0_r4, "participants"."updated_at" AS t0_r5, "evaluators"."id" AS t1_r0, "evaluators"."email" AS t1_r1, "evaluators"."created_at" AS t1_r2, "evaluators"."updated_at" AS t1_r3, "evaluators"."actable_id" AS t1_r4, "evaluators"."actable_type" AS t1_r5, "evaluators"."evaluation_id" AS t1_r6 FROM "participants" LEFT OUTER JOIN "evaluators" ON "evaluators"."actable_id" = "participants"."id" AND "evaluators"."actable_type" = 'Participant'  ORDER BY "participants"."id" DESC LIMIT 1
 => # 
2.1.2 :006 > Evaluation.new
 => # 
2.1.2 :007 > Evaluation.create(participant_id: p.id)
   (0.2ms)  BEGIN
  Evaluation Exists (2.1ms)  SELECT  1 AS one FROM "evaluations"  WHERE "evaluations"."access_key" = 'c688b05ee4625c60' LIMIT 1
  Evaluation Exists (0.3ms)  SELECT  1 AS one FROM "evaluations"  WHERE "evaluations"."access_key" = 'c688b05ee4625c60' LIMIT 1
  SQL (1.7ms)  INSERT INTO "evaluations" ("access_key", "created_at", "participant_id", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["access_key", "c688b05ee4625c60"], ["created_at", "2014-10-07 19:47:15.877706"], ["participant_id", 3], ["updated_at", "2014-10-07 19:47:15.877706"]]
   (2.3ms)  COMMIT
 => #

pry Debug-Ausgabe am Anfang der Methode

[1] pry(Evaluation)> self
=> Evaluation(id: integer, participant_id: integer, access_key: string, created_at: datetime, updated_at: datetime)
[2] pry(Evaluation)> self.class
=> Class
[3] pry(Evaluation)> self.connection
=> # Evaluation
=> Evaluation(id: integer, participant_id: integer, access_key: string, created_at: datetime, updated_at: datetime)
[5] pry(Evaluation)> Evaluation.class
=> Class
[6] pry(Evaluation)> Evaluation.connection
=> #

`

Ich habe nicht die gesamte Ausgabe für self.connection oder Evaluation.connection gezeigt. Aber die Verbindung wird korrekt zurückgegeben.

`

3voto

Hadiyah Mujhid Punkte 177

Die Antwort auf diese Frage hatte damit zu tun, wie die Tests geschrieben wurden. In meiner Spezifikation überprüfe ich, ob "new" auf Evaluation aufgerufen wird. Da ich rspec-mocks benutze, wird Evaluation tatsächlich nicht erstellt. Dies wurde behoben, indem der Test geändert wurde, um die Ausgabenergebnisse zu testen.

0voto

Pius Uzamere Punkte 1414

Versuchen Sie stattdessen dies zu tun:

evaluation = self.new.tap do |e|
  e.participant_id = participant.id
  e.evaluator = participant
end

Die Verwendung von Object#tap sollte garantieren, dass Sie die Bewertung auf das Objekt setzen und nicht auf den Rückgabewert des Blocks.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X