I have a method in my Rails User model that looks like this:
def prep_data
if email.present?
self.email = email.downcase
end
if username.present?
self.username = username.downcase
end
puts "***********************"
puts self.email
puts self.inspect
puts "***********************"
end
When I run this, I'm getting:
***********************
john#me.com
#<User id: nil, username: nil, email: nil, password_salt: nil, password_digest: nil, created_at: nil, updated_at: nil>
***********************
I'm at a loss to explain why self.email seems to be set, but then when I inspect self, it is nil. This is also causing the object to not save because it's nil. A more complete version of the log is
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓","authenticity_token"=>"7ocuB7GiyPjMZ84SHKo9CDSPjY8uOdtDc5A9wr+stzTPrIHnvfxAkdp1HxWActd07ZWzJVEBH43A3V/4sX1ixg==", "user"=>{"username"=>"John", "email"=>"John#me.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create User"}
(0.0ms) begin transaction
***********************
john#me.com
#<User id: nil, username: nil, email: nil, password_salt: nil, password_digest: nil, created_at: nil, updated_at: nil>
***********************
***********************
john#me.com
#<User id: nil, username: nil, email: nil, password_salt: "$2a$10$T92qOVBwjGm4t550POLVHu", password_digest: "$2a$10$T92qOVBwjGm4t550POLVHuXhss6lniJJekxMbeKR/yU...", created_at: nil, updated_at: nil>
***********************
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = 'john' LIMIT 1
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'john#me.com' LIMIT 1
SQL (0.7ms) INSERT INTO "users" ("password_salt", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["password_salt", "$2a$10$T92qOVBwjGm4t550POLVHu"], ["password_digest", "$2a$10$T92qOVBwjGm4t550POLVHuXhss6lniJJekxMbeKR/yU.79uMqtZJa"], ["created_at", "2016-09-23 17:51:31.692923"], ["updated_at", "2016-09-23 17:51:31.692923"]]
SQLite3::ConstraintException: NOT NULL constraint failed: users.username: INSERT INTO "users" ("password_salt", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?)
The end goal is to get this to actually save. You can see that when rails does the Insert, username and email are nil, but I can tell from the debug puts statements that the email and username exist and are getting at least to the validation. That said, even it I remove the validation completely, I have this problem.
Have you tried this?
self.email.downcase! if email.present?
#arieljuod solved this for me by recommending that I use custom setters instead of trying to change things before validation. Problem solved although I don't fully understand why the other way didn't work even if it wasn't "best"
def username=(value)
self[:username] = value.downcase
end
def email=(value)
self[:email] = value.downcase
end
You need to call save on the model. So just call self.save on the model.
Related
On my site, a user registers and gives their credit card information in the same form. The form uses Devise to save the user. I needed to import the actual devise code into the controller (a bad practice, i know, but with Braintree I couldn't see any other way to wrap the user and charge into one transaction). I finally got the whole thing to work except I am having trouble with Braintree error messages. I just tried creating a transaction with an amount of $2600 which should trigger a Braintree error and display a message, but no such error was triggered. Here is my code:
def create
nonce_from_the_client = params[:payment_method_nonce]
# code taken from devise
build_resource(sign_up_params)
begin
#charge = resource.charges.build
#charge.nonce = nonce_from_the_client
braintree_call = nil
#braintree_errors = nil
ActiveRecord::Base.transaction do
puts "beforer resource saved".green
resource.save!
puts "resource saved".green
puts "charge built".green
puts "before call_braintree".green
braintree_call = #charge.call_braintree!
if braintree_call.success? && !braintree_call.errors.any?
puts "braintree_call was a success".green
#charge.save
#do nothing. All good
else
puts "braintree error".red
#braintree_errors = braintree_call.errors
braintree_call.errors.each do |error|
puts "#{error.code}\n".red
puts "#{error.message}".red
end
raise "#Charge Failed"
end
end
rescue
puts "#charge #{#charge.inspect}".red
puts "#charge errors: #{#charge.errors.inspect}".red
end
yield resource if block_given?
if resource.persisted?
puts "resource persisted".green
if resource.active_for_authentication?
flash[:success] = "Welcome! You have signed up successfully."
# set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
puts "not sure about this".blue
# set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
flash[:danger] = "signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
puts "resource did not persist".red
clean_up_passwords resource
set_minimum_password_length
# respond_with resource
puts "NOW WE KNOW".on_red
render 'new' #not sure if this works
end
puts "resource errors are #{resource.errors.inspect}".red
end
And here is the model for Charge that includes the call_braintree method above:
class Charge < ActiveRecord::Base
belongs_to :user
attr_accessor :nonce
after_create :activate_user_account
def activate_user_account
puts "in the activate user account after_Create method".green
self.user.activate
end
def set_amount
amount = self.user.plan.amount * self.user.plan.length
puts "amount is #{amount} and is class #{amount.class}".green
return amount
end
def call_braintree!
puts "in call braintree".green
result = Braintree::Transaction.sale(
:amount => "#{self.set_amount}",
:payment_method_nonce => self.nonce,
:options => {
:submit_for_settlement => true
}
)
end
end
Here are the server logs this generates:
Started POST "/users" for 127.0.0.1 at 2016-02-26 15:06:29 -0500
Processing by Users::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Z0jHeFqXJk6iEwdEohilVd2Io85NKoPuzUepjfSXxU0=", "user"=>{"type"=>"Presenter", "plan_id"=>"2", "organization_name"=>"", "first_name"=>"David", "last_name"=>"Applebau,", "email"=>"asfdjhfasdlk#dffadsdf.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "telephone"=>"6462343800", "group_code"=>""}, "field-fnames"=>"", "field-lnames"=>"", "payment_method_nonce"=>"815abd1c-0be5-40e4-8135-a468021c8b75"}
(0.2ms) BEGIN
beforer resource saved
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'asfdjhfasdlk#dffadsdf.com' LIMIT 1
Plan Load (0.1ms) SELECT "plans".* FROM "plans" WHERE "plans"."id" = $1 LIMIT 1 [["id", 2]]
SQL (0.2ms) INSERT INTO "users" ("created_at", "email", "encrypted_password", "first_name", "last_name", "organization_name", "plan_id", "plan_length", "plan_start_date", "plan_status", "telephone", "type", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING "id" [["created_at", "2016-02-26 20:06:29.294712"], ["email", "asfdjhfasdlk#dffadsdf.com"], ["encrypted_password", "$2a$10$jeIa3c.i73f/hBV7ne/Dfu0MAawQzoNak808zLqjjkFeJKmXt78yK"], ["first_name", "David"], ["last_name", "Applebau,"], ["organization_name", ""], ["plan_id", 2], ["plan_length", 1], ["plan_start_date", "2016-02-26 20:06:29.289691"], ["plan_status", "active"], ["telephone", "6462343800"], ["type", "Presenter"], ["updated_at", "2016-02-26 20:06:29.294712"]]
SQL (0.1ms) INSERT INTO "charges" ("created_at", "updated_at", "user_id") VALUES ($1, $2, $3) RETURNING "id" [["created_at", "2016-02-26 20:06:29.307071"], ["updated_at", "2016-02-26 20:06:29.307071"], ["user_id", 20]]
in the activate user account after_Create method
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 20]]
in the after method of the state machine
Plan Load (0.1ms) SELECT "plans".* FROM "plans" WHERE "plans"."id" = $1 LIMIT 1 [["id", 2]]
SQL (0.2ms) UPDATE "users" SET "plan_start_date" = $1, "updated_at" = $2 WHERE "users"."type" IN ('Presenter') AND "users"."id" = 20 [["plan_start_date", "2016-02-26 20:06:29.310158"], ["updated_at", "2016-02-26 20:06:29.311003"]]
resource saved
charge built
before call_braintree
in call braintree
braintree error
(0.2ms) ROLLBACK
ichabod is yolo
#charge #<Charge id: nil, user_id: 20, stripe_id: nil, created_at: "2016-02-26 20:06:29", updated_at: "2016-02-26 20:06:29">
#charge errors: #<ActiveModel::Errors:0x007ffac3f16790 #base=#<Charge id: nil, user_id: 20, stripe_id: nil, created_at: "2016-02-26 20:06:29", updated_at: "2016-02-26 20:06:29">, #messages={}>
resource did not persist
NOW WE KNOW
Rendered layouts/logged_in/_error_messages.html.erb (0.0ms)
#type is Presenter
#free_trial is
in here
Plan Load (0.3ms) SELECT "plans".* FROM "plans" WHERE "plans"."user_type" = 'Presenter' AND ("plans"."name" != 'free_trial') ORDER BY "plans"."display_order_number" ASC
Rendered layouts/logged_in/_registration_form_header.html.erb (1.7ms)
Rendered layouts/logged_in/_payment_form.html.erb (0.1ms)
Rendered layouts/logged_in/_registration_submit_button.html.erb (0.1ms)
Rendered charges/_braintree_js.html.erb (0.0ms)
Rendered devise/registrations/new.html.erb within layouts/logged_in (8.3ms)
Rendered layouts/logged_in/_navbar.html.erb (0.4ms)
resource errors are #<ActiveModel::Errors:0x007ffac3fd6ae0 #base=#<Presenter id: nil, email: "asfdjhfasdlk#dffadsdf.com", encrypted_password: "$2a$10$jeIa3c.i73f/hBV7ne/Dfu0MAawQzoNak808zLqjjkF...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2016-02-26 20:06:29", updated_at: "2016-02-26 20:06:29", confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, organization_id: nil, type: "Presenter", organization_name: "", organization_code: nil, identifier: nil, stripe_customer_id: nil, plan_id: 2, presenter_maximum: nil, workshop_id: nil, presentation_allowance: 2, plan_status: "active", plan_start_date: "2016-02-26 20:06:29", plan_length: 1, contact_name: nil, contact_phone: nil, first_name: "david", last_name: "applebaum", telephone: "6462343800", group_id: nil>, #messages={:plan_id=>[], :organization_name=>[], :first_name=>[], :last_name=>[], :email=>[], :password=>[], :password_confirmation=>[], :telephone=>[], :group_code=>[]}>
Completed 200 OK in 2171ms (Views: 81.0ms | ActiveRecord: 1.8ms)
The only thing I did differently in order to get a braintree error was switch the amount in the call_braintree method with 2600.
As you can see in the logs, some type of error was thrown or the call was not a success, and yet Braintree did not provide an error. Whenever the users card does not work, for whatever reason, I need an error message from braintree to show the user. How do I get braintree errors to properly display?
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact our support team.
Errors are only populated for Braintree validation errors. Processor errors are reported in the Transaction's processor_response_code
Appropriate error handling for Transactions that fail at the processor level would look like this:
if braintree_call.success? && !braintree_call.errors.any?
puts "braintree_call was a success".green
#charge.save
#do nothing. All good
elsif braintree_call.transaction
puts "Transaction processing error: #{braintree_call.transaction.status}: Response Code: #{braintree_call.transaction.processor_response_code}\n".red
raise "#Charge Failed"
else
puts "braintree error".red
#braintree_errors = braintree_call.errors
braintree_call.errors.each do |error|
puts "#{error.code}\n".red
puts "#{error.message}".red
end
raise "#Charge Failed"
end
Check out our docs for more info on transaction statuses and processor response codes
I try saving a row that has an attribute named class_datetime (which is a DateTime) and it silently fails. Here's an example:
I create a new LittleClassSession, like so:
irb(main):010:0> l = LittleClassSession.new
=> #<LittleClassSession id: nil, length: nil, class_datetime: nil, created_at: nil, updated_at: nil, little_class_id: nil, location_id: nil, session_series_token: nil>
The class_datetime is a DateTime:
irb(main):011:0> LittleClassSession.columns_hash["class_datetime"].type
=> :datetime
I set the attribute:
irb(main):012:0> l.class_datetime = DateTime.now
=> 2015-08-13 22:02:09 -0400
And I save (no validations yet):
irb(main):013:0> l.save
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "little_class_sessions" ("class_datetime", "created_at", "updated_at") VALUES (?, ?, ?) [["class_datetime", "2015-08-13 22:02:09.976030"], ["created_at", "2015-08-13 22:03:01.255911"], ["updated_at", "2015-08-13 22:03:01.255911"]]
(2.6ms) commit transaction
=> true
Looks like it worked. Let's see what I saved:
irb(main):014:0> l
=> #<LittleClassSession id: 728, length: nil, class_datetime: "2015-08-14 02:02:09", created_at: "2015-08-14 02:03:01", updated_at: "2015-08-14 02:03:01", little_class_id: nil, location_id: nil, session_series_token: nil>
Let's see what's in the table:
irb(main):015:0> LittleClassSession.last
LittleClassSession Load (0.2ms) SELECT "little_class_sessions".* FROM "little_class_sessions" ORDER BY "little_class_sessions"."id" DESC LIMIT 1
=> #<LittleClassSession id: 728, length: nil, class_datetime: nil, created_at: nil, updated_at: nil, little_class_id: nil, location_id: nil, session_series_token: nil>
My LittleClassSession model looks like:
class LittleClassSession < ActiveRecord::Base
belongs_to :little_class
belongs_to :location
end
What could be causing this? Recently I changed the default timezone in application.rb, but I don't see why that might be the reason.
Your :date_time field is DateTime object.
Try this:
l.class_datetime = DateTime.now
Rather than:
l.class_datetime = Time.now
The issue went away once I removed these two lines from application.rb:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
This evidently caused some chaos.
I have 2 models with a one-to-many association: User and Recipe. the User class has_many :recipes while the Recipe class belongs_to :user. I've already run the migration, reloaded the rails console, and checked to make sure that user_id is a column in the recipes table. Still, I get an undefined method error when I try to append a recipe to a user:
2.0.0-p598 :047 > user.recipes << Recipe.first
NoMethodError: undefined method `recipes' for #<User:0x00000004326fa0>
here is the migration code (I've already run rake db:migrate):
class AddUserIdToRecipes < ActiveRecord::Migration
def change
add_column :recipes, :user_id, :integer
end
end
Here is the User model code:
class User < ActiveRecord::Base
has_one :profile
has_many :recipes
end
Here is the Recipe model code:
class Recipe < ActiveRecord::Base
validates_presence_of :title, :body
belongs_to :user
def long_title
"#{title} - #{published_at}"
end
end
Why does recipes still show up as an undefined method?
Try this on your console:
irb(main):007:0> user = User.new first_name: 'John', last_name: 'Doe'
=> #<User id: nil, first_name: "John", last_name: "Doe", created_at: nil, updated_at: nil>
irb(main):008:0> user.save
(0.1ms) begin transaction
SQL (0.6ms) INSERT INTO "users" ("created_at", "first_name", "last_name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-01-19 21:14:33.489371"], ["first_name", "John"], ["last_name", "Doe"], ["updated_at", "2015-01-19 21:14:33.489371"]]
(0.6ms) commit transaction
=> true
irb(main):009:0> r = Recipe.new name: 'oooohh awesome', description: 'my description goes here'
=> #<Recipe id: nil, name: "oooohh awesome", description: "my description goes here", created_at: nil, updated_at: nil, user_id: nil>
irb(main):010:0> r.save
(0.1ms) begin transaction
SQL (0.2ms) INSERT INTO "recipes" ("created_at", "description", "name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-01-19 21:15:16.548090"], ["description", "my description goes here"], ["name", "oooohh awesome"], ["updated_at", "2015-01-19 21:15:16.548090"]]
(1.2ms) commit transaction
=> true
irb(main):011:0> user.recipes << Recipe.first
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" ORDER BY "recipes"."id" ASC LIMIT 1
(0.0ms) begin transaction
SQL (0.2ms) UPDATE "recipes" SET "updated_at" = ?, "user_id" = ? WHERE "recipes"."id" = 1 [["updated_at", "2015-01-19 21:15:49.181586"], ["user_id", 1]]
(1.3ms) commit transaction
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" WHERE "recipes"."user_id" = ? [["user_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>]>
irb(main):012:0> user.save
(0.1ms) begin transaction
(0.0ms) commit transaction
=> true
irb(main):013:0> user.recipes
=> #<ActiveRecord::Associations::CollectionProxy [#<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>]>
irb(main):014:0> user.recipes.first
=> #<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>
irb(main):015:0>
you can see that Recipe.first has been inserted into user.recipes and its saved.
I made two models similar to yours, and have exactly the same setup as you. You can follow code above to write your controllers.
I have a model spec that is failing with "undefined method 'save' for nil:NilClass'." This occurs in the class method 'create_and_send_self_eval'. The method is creating a new Evaluation, but it always returns nil in the test environment. I've also tried using 'create', 'create!' and they also return nil. However, this only occurs in the test environment. In the development environment, it returns the correct object. I'm using rspec 3.1.5, rails 4.1.6, and ruby 2.1.2.
I've included the code for the class and my debug output. Any suggestions?
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 output using pry in the test environment
[1] pry(Evaluation)> participant
=> #<Participant id: 167, first_name: "Puff", last_name: "Daddy", evaluation_url: nil, created_at: "2014-10-07 19:43:47", updated_at: "2014-10-07 19:43:47">
[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 output in rails console
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
=> #<Participant id: 3, first_name: "Puff", last_name: "Daddy", evaluation_url: nil, created_at: "2014-10-06 06:32:40", updated_at: "2014-10-06 06:32:40">
2.1.2 :006 > Evaluation.new
=> #<Evaluation id: nil, participant_id: nil, access_key: nil, created_at: nil, updated_at: nil>
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
=> #<Evaluation id: 4, participant_id: 3, access_key: "c688b05ee4625c60", created_at: "2014-10-07 19:47:15", updated_at: "2014-10-07 19:47:15">
pry debug output at beginning of method
[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
=> #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:0x007f8158eb8ee0
[4] pry(Evaluation)> 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
=> #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:0x007f8158eb8ee0
I didn't show the entire output for self.connection or Evaluation.connection. But connection is returning correctly.
The answer to this question had to do with how the tests were written. In my spec, I'm checking to see if "new" is called on Evaluation. Since, I'm using rspec-mocks, Evaluation is not actually being created. Fixed this by changing the test to test the output results.
Try doing this instead:
evaluation = self.new.tap do |e|
e.participant_id = participant.id
e.evaluator = participant
end
Using Object#tap should guarantee that you set evaluation to the object rather than to the return value of the block.
I am using Devise for my user authentication and would like to destroy an associated profile along with the user.
My failing spec looks like this:
it "should destroy associated profile" do
profile = #user.profile
#user.destroy
expect(profile).to be_nil
end
And
In my user model:
has_one :profile, dependent: :destroy
In my profile model:
belongs_to :user
In the console, I can reproduce the issue like this:
2.0.0p247 :001 > #user = FactoryGirl.create(:user)
(1.5ms) BEGIN
User Exists (2.9ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'person946979#example.com' LIMIT 1
User Exists (1.7ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('person946979#example.com') LIMIT 1
SQL (15.7ms) INSERT INTO "users" ("created_at", "email", "encrypted_password", "name", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Fri, 16 Aug 2013 01:21:12 UTC +00:00], ["email", "person946979#example.com"], ["encrypted_password", "$2a$10$0704XOlw.6ZE4HEfDhaIeuwnEbbJZvZda3Jwr052aLS5z3G77Dgja"], ["name", "Example User"], ["updated_at", Fri, 16 Aug 2013 01:21:12 UTC +00:00]]
SQL (3.8ms) INSERT INTO "profiles" ("created_at", "updated_at", "user_id") VALUES ($1, $2, $3) RETURNING "id" [["created_at", Fri, 16 Aug 2013 01:21:12 UTC +00:00], ["updated_at", Fri, 16 Aug 2013 01:21:12 UTC +00:00], ["user_id", 25]]
Profile Load (3.4ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["user_id", 25]]
(2.2ms) COMMIT
=> #<User id: 25, email: "person946979#example.com", encrypted_password: "$2a$10$0704XOlw.6ZE4HEfDhaIeuwnEbbJZvZda3Jwr052aLS5...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2013-08-16 01:21:12", updated_at: "2013-08-16 01:21:12", name: "Example User">
2.0.0p247 :002 > #user.destroy
(1.0ms) BEGIN
SQL (2.5ms) DELETE FROM "profiles" WHERE "profiles"."id" = $1 [["id", 4]]
SQL (5.4ms) DELETE FROM "users" WHERE "users"."id" = $1 [["id", 25]]
(2.0ms) COMMIT
=> #<User id: 25, email: "person946979#example.com", encrypted_password: "$2a$10$0704XOlw.6ZE4HEfDhaIeuwnEbbJZvZda3Jwr052aLS5...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2013-08-16 01:21:12", updated_at: "2013-08-16 01:21:12", name: "Example User">
Interestingly, the user appears to actually have been deleted.
2.0.0p247 :003 > #user.reload.destroy
User Load (2.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 25]]
ActiveRecord::RecordNotFound: Couldn't find User with id=25
What is going on here?
Your model seems fine. Try something like this:
it "should destroy associated profile" do
profile = #user.profile
#user.destroy
expect(Profile.find(profile.id)).to be_nil
end
Like Heungju said, while the database row that corresponds to profile is being destroyed, the variable itself isn't.
How about this?
it "should destroy associated profile" do
profile = #user.profile
#user.destroy
expect(#user.profile).to be_nil
end
After #user.destroy, the 'profile', variable that expected to be nil, was not changed. I think...
Rewriting my spec like this does what I need:
it "should destroy associated profile" do
expect {
#user.destroy
}.to change(Profile, :count).by(-1)
end