Related
Location is basically an address with other information fields. This is my first app and I followed Hartl and others in building it, but ignored failing tests that I couldn't fix at the time. Now I'm trying to rectify that. I've looked at all the postings I found with this problem, but still can't figure it out (discussed at end). The app works, I can create new locations, so I think the error is with the test.
FAIL["test_should_create_location", LocationsControllerTest, 2017-02-28 12:02:08 -0800]
test_should_create_location#LocationsControllerTest (1488312128.31s)
"Location.count" didn't change by 1.
Expected: 4
Actual: 3
test/controllers/locations_controller_test.rb:21:in `block in <class:LocationsControllerTest>'
Edited location_controller_test.rb (The location controller test has 8 tests, this is the one that fails):
require 'test_helper'
class LocationsControllerTest < ActionController::TestCase
setup do
#location = locations(:one)
end
test "should create location" do
assert_difference('Location.count') do
post :create, location: { address: #location.address,
city: #location.city,
state: #location.state,
longitude: #location.longitude,
latitude: #location.latitude,
geom: #location.geom,
coords_not_locked: #location.coords_not_locked,
geocoded_with: #location.geocoded_with,
extant: #location.extant,
current_description: #location.current_description,
source: #location.source,
ref_link: #location.ref_link,
notes: #location.notes }
# debugger
end
assert_redirected_to location_path(assigns(:location))
end
locations_controller.rb:
class LocationsController < ApplicationController
helper_method :sort_column, :sort_direction
before_action :set_location, only: [:show, :edit, :update, :destroy]
def index
#locations = Location.all
# For sortable columns
#locations = Location.order(sort_column + " " + sort_direction)
end
def show
end
def new
#location= Location.new({:address=> "Use W E etc and St without PERIODS"})
repopulateResidResto()
end
def edit
end
def create
# Instantiate a new object using form parameters (notes here from Lynda>Skoglund)
#location = Location.new(location_params)
# Save the object
respond_to do |format|
if #location.save
# If save succeeds, redirect to the index action
format.html { redirect_to #location, notice: 'Address was successfully created.' }
format.json { render :show, status: :created, location: #location}
else
# If save fails, redisplay the form with information user filled in
format.html { render :new }
format.json { render json: #location.errors, status: :unprocessable_entity }
end
end
repopulateResidResto()
end # end create
def update
respond_to do |format|
if #location.update(location_params)
# If update succeeds, redirect to the show page
format.html { redirect_to #location, notice: 'Address was successfully updated.' }
format.json { render :show, status: :ok, location: #location }
else
# If update fails, redisplay the edit form for fixing
format.html { render :edit }
format.json { render json: #location.errors, status: :unprocessable_entity }
end
end
repopulateResidResto()
end # End update
def destroy
location = #location.destroy
respond_to do |format|
format.html { redirect_to locations_url, notice: "Location '#{location}' was successfully destroyed." }
format.json { head :no_content }
end
repopulateResidResto()
end
private
# Use callbacks to share common setup or constraints between actions.
def set_location
#location = Location.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def location_params
params.require(:location).permit(:address, :city, :state, :longitude, :latitude, :geom, :coords_not_locked, :geocoded_with, :extant, :current_description, :source, :ref_link, :notes)
end
def sort_column
Location.column_names.include?(params[:sort]) ? params[:sort] : "address"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end
end
locations.yml:
one:
address: 1 Address1
city: Los Angeles
state: California
longitude: 99.99
latitude: 99.99
extant: false
current_description: MyString2
notes: Notes1
source: Source1
geocoded_with: geocoded_with_1
coords_not_locked: false
ref_link: ref_link_1
geom: 0101000020E61000008B187618938F5DC0C2189128B4064140
two:
address: 2 Address2
city: Los Angeles
state: California
longitude: 9.99
latitude: 9.99
extant: true
current_description: MyString
notes: MyString
source: MyString
geocoded_with: MyString
coords_not_locked: true
ref_link: MyString
geom: 0101000020E61000007B4963B48E8F5DC0467C2766BD064140
three:
address: 3 Address3
city: Los Angeles
state: California
longitude: 9.99
latitude: 9.99
extant: true
current_description: MyString
notes: MyString3
source: MyString3
geocoded_with: MyString3
coords_not_locked: true
ref_link: MyString3
geom: 0101000020E61000007B4963B48E8F5DC0467C2766BD064140
The model, location.rb:
class Location < ActiveRecord::Base
has_many :years, dependent: :destroy
has_many :people, through: :years
has_many :resto_resid_lines
def longlat
"#{longitude} #{latitude}"
end
def notes_plus_geocode
if notes == ""
"#{geocoded_with}"
else
"#{notes} #{geocoded_with}"
end
end
def full_address
full_address = "#{address}, #{city}, #{state}"
end
# For next and previous in show.
def next
Location.where(["id > ?", id]).first
end
def previous
Location.where(["id < ?", id]).last
end
geocoded_by :full_address
after_validation :geocode, :if => :coords_not_locked?
validates :address, length: { minimum: 5, maximum: 50 }, uniqueness: true
end
test_helper.rb
require 'simplecov'
SimpleCov.start
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!
class ActiveSupport::TestCase
fixtures :all
# Returns true if a test user is logged in.
def is_logged_in?
!session[:user_id].nil?
end
# Logs in a test user.
def log_in_as(user, options = {})
password = options[:password] || 'password'
remember_me = options[:remember_me] || '1'
if integration_test?
post login_path, session: { email: user.email,
password: password,
remember_me: remember_me }
else
session[:user_id] = user.id
end
end
private
# Returns true inside an integration test.
def integration_test?
defined?(post_via_redirect)
end
end
If I turn the debugger on in the test, #location is
(byebug) pp #location
#<Location:0x007ff26ffa1ba8
id: 980190962,
address: "MyString21",
city: "MyString23",
state: "MyString25",
longitude: #<BigDecimal:7ff26ff96b40,'0.9999E2',18(27)>,
latitude: #<BigDecimal:7ff26ff96a50,'0.9999E2',18(27)>,
extant: false,
current_description: "MyString2",
notes: "MyString24",
created_at: Sun, 05 Mar 2017 18:46:12 UTC +00:00,
updated_at: Sun, 05 Mar 2017 18:46:12 UTC +00:00,
geom: "0101000020E61000008B187618938F5DC0C2189128B4064140",
source: "MyString",
geocoded_with: "MyString",
coords_not_locked: false,
ref_link: "MyString">
#<Location id: 980190962, address: "MyString21", city: "MyString23", state: "MyString25", longitude: #<BigDecimal:7ff26ff96b40,'0.9999E2',18(27)>, latitude: #<BigDecimal:7ff26ff96a50,'0.9999E2',18(27)>, extant: false, current_description: "MyString2", notes: "MyString24", created_at: "2017-03-05 18:46:12", updated_at: "2017-03-05 18:46:12", geom: "0101000020E61000008B187618938F5DC0C2189128B4064140", source: "MyString", geocoded_with: "MyString", coords_not_locked: false, ref_link: "MyString"
I'm not sure what to expect for this.
One posting that seemed relevant "User.count" didn't change by 1 - Rails had incomplete yml—I've triple checked mine, but maybe still missing something.
#ArtOfCode. Creating in console (I think this is what you're asking). And since id is nil and it doesn't appear in the database, you may be on the right track:
irb(main):004:0> location = Location.create( address: "1 Address1", city: "Los Angeles", state: "California", longitude: 99.99, latitude: 99.99, extant: false, current_description: "MyString2", notes: "MyString24", source: "MyString", geocoded_with: "MyString", coords_not_locked: false, ref_link: "MyString", geom: "0101000020E61000008B187618938F5DC0C2189128B4064140")
(0.2ms) BEGIN
Location Exists (0.4ms) SELECT 1 AS one FROM "locations" WHERE "locations"."address" = '1 Address1' LIMIT 1
SQL (2.5ms) INSERT INTO "locations" ("address", "state", "longitude", "latitude", "extant", "current_description", "notes", "source", "geocoded_with", "coords_not_locked", "ref_link", "geom", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING "id" [["address", "1 Address1"], ["state", "California"], ["longitude", "99.99"], ["latitude", "99.99"], ["extant", "f"], ["current_description", "MyString2"], ["notes", "MyString24"], ["source", "MyString"], ["geocoded_with", "MyString"], ["coords_not_locked", "f"], ["ref_link", "MyString"], ["geom", "0101000020E61000008B187618938F5DC0C2189128B4064140"], ["created_at", "2017-03-05 20:00:28.246188"], ["updated_at", "2017-03-05 20:00:28.246188"]]
(2.1ms) COMMIT
#<Location:0x007fe851a9bac8> {
:id => 177,
:address => "1 Address1",
:city => "Los Angeles",
:state => "California",
:longitude => 99.99,
:latitude => 99.99,
:extant => false,
:current_description => "MyString2",
:notes => "MyString24",
:created_at => Sun, 05 Mar 2017 20:00:28 UTC +00:00,
:updated_at => Sun, 05 Mar 2017 20:00:28 UTC +00:00,
:geom => "0101000020E61000008B187618938F5DC0C2189128B4064140",
:source => "MyString",
:geocoded_with => "MyString",
:coords_not_locked => false,
:ref_link => "MyString"
}
The application is incomplete, but you can see a location here. Not currently allowing sign-ups, so obviously create can't be used. The addresses are more than 100 years old and the geo coordinates may not be generated. geom is created later in PostGIS.
I imagine there is a simple solution, but it alludes me. gem 'rails' , '4.2.7' and ruby '2.3.1'
Fixtures create database entries automatically. Your location fixture one exists in the database.
So when you try a post to create a new location and you specify...
post :create, location: { address: #location.address,
You are trying to create a location with an address that already exists, but
validates :address, length: { minimum: 5, maximum: 50 }, uniqueness: true
...specifies that the address must be unique, so the record you're attempting to post is not valid because it has the same address as an existing record.
Simply change the address in your post :create call
post :create, location: { address: "1 A New Address",
I'm following the Treebook tutorial on teamtreehouse.com (making a facebook clone) using rails. I have created a userfriendships controller and am getting this error when trying to reference a friend's full name in my index.html page of the friendships view: undefined method `full_name' for nil:NilClass. The problem occurs on line 4 here, (this is /views/user_friendships/index.html)
<div class="page-header">
<h1>Friends</h1>
</div>
<hr />
<% if #user_friendships.empty? %>
<em>No <%= params[:list] %> friends yet!</em>
<% end %>
<% #user_friendships.each do |friendship| %>
<% friend = friendship.friend %>
<div id="<%= dom_id(friendship) %>" class="friend panel">
<div class="panel-heading">
<span class="pull-right label>"><%= "#{friendship.state}".upcase %></span>
<h3 class="panel-title"><%= friend.full_name %></h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-1">Put gravatar url here</div>
<div class="col-md-11">
<em>Friends since time_ago_in_words ago</em>
</div>
</div>
</div>
<div class="panel-footer clearfix">
<%= link_to "Update friendship", edit_user_friendship_path( friend.profile_name), class: 'btn btn-primary pull-right' %>
</div>
</div>
<% end %>
Here's the User Friendships Controller:
class UserFriendshipsController < ApplicationController
before_filter :authenticate_user!
def index
#user_friendships = current_user.user_friendships.all
end
def new
if params[:friend_id]
#friend = User.where(profile_name: params[:friend_id]).first
raise ActiveRecord::RecordNotFound if #friend.nil?
#user_friendship = current_user.user_friendships.new(friend: #friend)
else
flash[:error] = "Friend required"
end
rescue ActiveRecord::RecordNotFound
render file: 'public/404', status: :not_found
end
def create
if params[:user_friendship] && params[:user_friendship].has_key?(:friend_id)
#friend = User.where(profile_name: params[:user_friendship][:friend_id]).first
#user_friendship = UserFriendship.request(current_user, #friend)
respond_to do |format|
if #user_friendship.new_record?
format.html do
flash[:error] = "There was a problem creating that friend request."
redirect_to profile_path(#friend)
end
format.json { render json: #user_friendship.to_json, status: :precondition_failed }
else
format.html do
flash[:success] = "Friend request sent to #{#friend.full_name}."
redirect_to profile_path(#friend.profile_name)
end
format.json { render json: #user_friendship.to_json }
end
end
else
flash[:error] = "Friend required"
redirect_to root_path
end
end
def edit
#friend = User.where(profile_name: params[:id]).first
#user_friendship = current_user.user_friendships.find(params[:id])
end
def destroy
#user_friendship = current_user.user_friendships.find(params[:id])
if #user_friendship.destroy
flash[:success] = "Friendship destroyed."
end
redirect_to user_friendships_path
end
def accept
#user_friendship = current_user.user_friendships.find(params[:id])
if #user_friendship.accept!
flash[:success] = "You are now friend with #{#user_friendship.friend.full_name}"
else
flash[:error] = "That friendship could not be accepted."
end
redirect_to user_friendships_path
end
def block
#user_friendship = current_user.user_friendships.find(params[:id])
if #user_friendship.block!
flash[:success] = "You have blocked #{#user_friendship.friend.full_name}."
else
flash[:error] = "That friendship could not be blocked."
end
redirect_to user_friendships_path
end
private
def friendship_association
case params[:list]
when nil
current_user.user_friendships
when 'blocked'
current_user.blocked_user_friendships
when 'pending'
current_user.pending_user_friendships
when 'requested'
current_user.requested_user_friendships
when 'accepted'
current_user.accepted_user_friendships
end
end
private
def user_friendship_attributes
params.require(:user_friendship).permit(:user, :friend, :user_id, :friend_id, :state)
end
end
Lastly, I will include the user friendships model:
class UserFriendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: 'User', foreign_key: 'friend_id'
state_machine :state, initial: :pending do
after_transition on: :accept, do: :send_acceptance_email
state :requested
event :accept do
transition any => :accepted
end
end
def self.request(user1, user2)
transaction do
friendship1 = create(user: user1, friend: user2, state: 'pending')
friendship2 = create(user: user2, friend: user1, state: 'requested')
friendship1.send_request_email
friendship1
end
end
def send_request_email
UserNotifier.friend_requested(id).deliver
end
def send_acceptance_email
UserNotifier.friend_request_accepted(id).deliver
end
def mutual_friendship
self.class.where({user_id: friend_id, friend_id: user_id}).first
end
# Manually updating the state to avoid callbacks and infinite loops
def accept_mutual_friendship
mutual_friendship.update_attribute(:state, 'accepted')
end
end
I'm aware that I must have to change this somehow, but am at a loss as to how to do that. I would like this page to display all of the friends that a user has, either in an accepted or pending state. Can anyone see what I need to do?
Thanks!
EDIT: If I change the views/user_friendships/index.html to friend.full_name instead of #friend.full_name I still get the same error. I can verify that the users currently in the db all have a valid first and last name (so the full name method should work).
Another EDIT: Here is a rails console entry showing that I do have userfriendships in the database:
2.1.2 :003 > UserFriendship.all
UserFriendship Load (0.3ms) SELECT "user_friendships".* FROM "user_friendships"
=> #<ActiveRecord::Relation [#<UserFriendship id: 1, user_id: 6, friend_id: nil, created_at: "2014-10-04 14:20:42", updated_at: "2014-10-04 14:20:42", state: nil>, #<UserFriendship id: 2, user_id: 6, friend_id: nil, created_at: "2014-10-04 14:21:32", updated_at: "2014-10-04 14:21:32", state: nil>, #<UserFriendship id: 3, user_id: 6, friend_id: 3, created_at: "2014-10-04 14:21:50", updated_at: "2014-10-04 14:21:50", state: nil>, #<UserFriendship id: 4, user_id: 6, friend_id: 6, created_at: "2014-10-04 14:23:58", updated_at: "2014-10-04 14:23:58", state: nil>, #<UserFriendship id: 5, user_id: 6, friend_id: 6, created_at: "2014-10-04 14:25:05", updated_at: "2014-10-04 14:25:05", state: nil>, #<UserFriendship id: 6, user_id: 6, friend_id: 4, created_at: "2014-10-04 14:25:15", updated_at: "2014-10-04 14:25:15", state: nil>, #<UserFriendship id: 7, user_id: 6, friend_id: 6, created_at: "2014-10-04 20:42:40", updated_at: "2014-10-04 20:42:40", state: nil>, #<UserFriendship id: 8, user_id: 6, friend_id: 6, created_at: "2014-10-04 20:45:44", updated_at: "2014-10-04 20:45:44", state: nil>, #<UserFriendship id: 9, user_id: 6, friend_id: 6, created_at: "2014-10-04 21:38:17", updated_at: "2014-10-04 21:38:17", state: nil>, #<UserFriendship id: 10, user_id: 6, friend_id: 6, created_at: "2014-10-09 16:53:44", updated_at: "2014-10-09 16:53:44", state: "pending">, ...]>
2.1.2 :004 >
Another Edit: Here is the user model models/user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :first_name, presence: true
validates :last_name, presence: true
validates :profile_name, presence: true,
uniqueness: true,
format: {
with: /\A.+\z/,
message: "must be formatted correctly"
}
has_many :statuses
has_many :user_friendships
has_many :friends, -> { where user_friendships: { state: 'accepted'} }, through: :user_friendships
has_many :pending_user_friendships, -> { where state: 'pending' },
class_name: 'UserFriendship',
foreign_key: :user_id
has_many :pending_friends, through: :pending_user_friendships, source: :friend
def full_name
first_name + " " + last_name
end
def gravatar_url
stripped_email = email.strip
downcased_email = stripped_email.downcase
hash = Digest::MD5.hexdigest(downcased_email)
"http://gravatar.com/avatar/#{hash}"
end
end
instead of #friend.full_name use friend.full_name
You have define it here <% friend = friendship.friend %>
So I am pretty sure what happened was that some of my database tables were dropped during a rake db:migrate that I ran. I did it because I was looking at a similar rails app that was building a social network site and switching my database back and forth between the two. Not sure how or why migrate deleted something ( i believe it deleted first and last name which is why full_name would be an nil error). I am going to revert to a previous commit where everything was working and try to rebuild from there.
Thanks for the posts!
tl;dr: dont run db:migrate without knowing what you're doing
This question already has an answer here:
Why can't I create active records that count for something in rspec?
(1 answer)
Closed 8 years ago.
I can create users in the console find with:
2.0.0-p247 :020 > User.create(username: 'user30', password: 'abc123', admin: true)
(0.3ms) BEGIN
User Exists (0.6ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'user30' LIMIT 1
SQL (0.5ms) INSERT INTO `users` (`admin`, `created_at`, `pwd_hashed`, `salt`, `updated_at`, `username`) VALUES (NULL, '2014-07-17 01:34:41', 'd3272da7e3fc0f6e1b035dfb10e6f412ae84fac8', '415066400.06787292634781616', '2014-07-17 01:34:41', 'user30')
(75.6ms) COMMIT
=> #<User id: 14, username: "user30", pwd_hashed: "d3272da7e3fc0f6e1b035dfb10e6f412ae84fac8", salt: "415066400.06787292634781616", created_at: "2014-07-17 01:34:41", updated_at: "2014-07-17 01:34:41", admin: nil>
2.0.0-p247 :021 > User.create(username: 'user31', password: 'abc123', admin: true)
(0.3ms) BEGIN
User Exists (1.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'user31' LIMIT 1
SQL (0.4ms) INSERT INTO `users` (`admin`, `created_at`, `pwd_hashed`, `salt`, `updated_at`, `username`) VALUES (NULL, '2014-07-17 01:34:46', '1ea5630a3c28b36e714625c4b44f3f951ef16c7a', '416177200.3102826047096757', '2014-07-17 01:34:46', 'user31')
(77.5ms) COMMIT
=> #<User id: 15, username: "user31", pwd_hashed: "1ea5630a3c28b36e714625c4b44f3f951ef16c7a", salt: "416177200.3102826047096757", created_at: "2014-07-17 01:34:46", updated_at: "2014-07-17 01:34:46", admin: nil>
2.0.0-p247 :022 > User.create(username: 'user32', password: 'abc123', admin: true)
(0.3ms) BEGIN
User Exists (0.6ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'user32' LIMIT 1
SQL (0.6ms) INSERT INTO `users` (`admin`, `created_at`, `pwd_hashed`, `salt`, `updated_at`, `username`) VALUES (NULL, '2014-07-17 01:34:50', '9aeb6cfcb80f57a08c421999dcfb5ad332317789', '417559200.14647833904112617', '2014-07-17 01:34:50', 'user32')
(12.0ms) COMMIT
=> #<User id: 16, username: "user32", pwd_hashed: "9aeb6cfcb80f57a08c421999dcfb5ad332317789", salt: "417559200.14647833904112617", created_at: "2014-07-17 01:34:50", updated_at: "2014-07-17 01:34:50", admin: nil>
2.0.0-p247 :023 >
2.0.0-p247 :005 > User.count
(0.6ms) SELECT COUNT(*) FROM `users`
=> 3
but in rspec when I have
describe "keep admin" do
its "Can't delete the only admin" do
user1 = User.create(username: 'user1', password: 'abc123', admin: true)
user2 = User.create(username: 'user2', password: 'def456', admin: true)
user3 = User.create(username: 'user3', password: 'ghi798', admin: true)
expect(User.where(admin: true).count).to eq 3
end
end
why do I get 0 instead of 3:
Failures:
1) keep admin Can't delete the only admin should eq 3
Failure/Error: expect(User.where(admin: true).count).to eq 3
expected: 3
got: 0
(compared using ==)
# ./spec/models/user_spec.rb:24:in `block (2 levels) in <top (required)>'
Finished in 0.37602 seconds
5 examples, 1 failure
User model:
$ cat app/models/user.rb
class User < ActiveRecord::Base
require 'digest/sha1'
attr_accessor :password_confirmation
attr_accessor :admin
validates_presence_of :username
validates_uniqueness_of :username
validates_confirmation_of :password
validate :password_non_blank
def self.delete_me(user)
how_many_admins = User.where(admin: true).count
if how_many_admins > 1
puts "delete ok!"
user.delete
else
puts "delete not ok!"
end
end
def self.authenticate(name, password)
user = self.find_by_username(name)
if user
expected_password = encrypted_password(password, user.salt)
if user.pwd_hashed != expected_password
user = nil
end
end
user
end
def password
#password
end
def password=(pwd)
#password = pwd
return if pwd.blank?
create_new_salt
self.pwd_hashed = User.encrypted_password(self.password, self.salt)
end
def is_admin
admin ? 'Yes' : 'No'
end
private
def password_non_blank
errors.add(:password, "Missing password") if pwd_hashed.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypted_password(password, salt)
string_to_hash = password + "wibble" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
It appears your admin assignment in your create call isn't working. In your console you set admin: true in all of your users, yet look at the log:
User.create(username: 'user30', password: 'abc123', admin: true)
#<User id: 14, username: "user30", pwd_hashed: "d3272da7e3fc0f6e1b035dfb10e6f412ae84fac8", salt: "415066400.06787292634781616", created_at: "2014-07-17 01:34:41", updated_at: "2014-07-17 01:34:41", admin: nil>
admin: nil is what is being stored.
You're trying to set a ruby boolean value into what I'm guessing is a "string" field in the database? If so, try this:
User.create(username: 'user30', password: 'abc123', admin: "true")
Then change your rspec test to:
expect(User.where(admin: "true").count).to eq(3)
Similar question, but user was not actually creating an ActiveRecord object.
Following Michael Hartl's tutorial, and I've hit a wall. There is a method call in before_save that doesn't seem to be working. I have double checked that my code aligns with his and is syntactically valid (although I often overlook simple syntax errors).
class User < ActiveRecord::Base
before_create { :create_remember_token } <------ here
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 30 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.?]+\.[a-z]{2,4}\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password # automatically checks presence of password and confirmation
validates :password, length: { minimum: 6 }
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.encrypt(User.new_remember_token)
end
end
Here's a console session to show that the db schema includes a remember_token, the class methods indeed work, yet something is wrong with the create callback.
2.0.0p247 :001 > User
=> User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime, password_digest: string, remember_token: string)
2.0.0p247 :002 > User.create(name:"Confused", email:"stack#overflow.com", password:"password", password_confirmation:"password")
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('stack#overflow.com') LIMIT 1
Binary data inserted for `string` type on column `password_digest`
SQL (3.9ms) INSERT INTO "users" ("created_at", "email", "name", "password_digest", "updated_at") VALUES (?, ?, ?, ?, ?) [["created_at", Wed, 09 Oct 2013 22:50:41 UTC +00:00], ["email", "stack#overflow.com"], ["name", "Confused"], ["password_digest", "$2a$10$Pca7ZokAVlca/floQRY1KesM1SFoSfiUxWjEJ8xHyA4NJueK4GVbG"], ["updated_at", Wed, 09 Oct 2013 22:50:41 UTC +00:00]]
(101.5ms) commit transaction
=> #<User id: 9, name: "Confused", email: "stack#overflow.com", created_at: "2013-10-09 22:50:41", updated_at: "2013-10-09 22:50:41", password_digest: "$2a$10$Pca7ZokAVlca/floQRY1KesM1SFoSfiUxWjEJ8xHyA4N...", remember_token: nil>
2.0.0p247 :003 >
2.0.0p247 :004 > token = User.new_remember_token
=> "md1vrpB2PH1VNMWaliuT6g"
2.0.0p247 :005 > User.encrypt(token)
=> "522d45ee2771c2cb36ffe6536b316ad004e5038b"
2.0.0p247 :006 >
2.0.0p247 :006 > User._create_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:create_remember_token)
=> false
Just remove brackets, try:
before_create :create_remember_token
If you pass a block it is evaluated, if you pass symbol a method with given name is called.
I have been trying to figure out what is wrong with my test.
First, it works in the console.
The console:
1.9.2-p290 :015 > a = Allergy.all
Allergy Load (0.4ms) SELECT "allergies".* FROM "allergies"
=> [#<Allergy id: 1, name: "Milk", desc: "Allergic to milk", created_at: "2012-01-08 16:38:55", updated_at: "2012-01-09 11:48:20", patient_id: 1>, #<Allergy id: 2, name: "Blah", desc: "Test", created_at: "2012-01-09 12:20:48", updated_at: "2012-01-09 12:20:48", patient_id: 2>]
1.9.2-p290 :016 > a[0]
=> #<Allergy id: 1, name: "Milk", desc: "Allergic to milk", created_at: "2012-01-08 16:38:55", updated_at: "2012-01-09 11:48:20", patient_id: 1>
1.9.2-p290 :017 > a[0].patient.full_name
Patient Load (0.5ms) SELECT "patients".* FROM "patients" WHERE "patients"."id" = 1 LIMIT 1
=> "Test Full Name"
1.9.2-p290 :018 >
Allergy Controller
class AllergiesController < ApplicationController
# GET /allergies
# GET /allergies.json
def index
#allergies = Allergy.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #allergies }
end
end
# GET /allergies/1
# GET /allergies/1.json
def show
#allergy = Allergy.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #allergy }
end
end
...
Allergy Model
class Allergy < ActiveRecord::Base
validates :name, :presence => true
belongs_to :patient
end
Patient Model
class Patient < ActiveRecord::Base
validates :first_name, :last_name, :dob, :presence => true
has_many :allergies
def age
now = Time.now.utc.to_date
now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end
def full_name
first_name
end
end
The test:
require 'test_helper'
class AllergiesControllerTest < ActionController::TestCase
setup do
#allergy = allergies(:one)
#allergy.patient = patients(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:allergies)
end
...
The fixtures:
# For Allergy
one:
name: MyString
desc: MyText
patient_id: 1
two:
name: MyString
desc: MyText
patient_id: 1
#For Patient
one:
first_name: Jose
last_name: Rizal
middle_name: H
dob: 2009-10-29
two:
first_name: MyString
last_name: MyString
middle_name: MyString
dob: 1982-02-11
The error:
AllergiesControllerTest:
PASS should create allergy (0.22s)
PASS should destroy allergy (0.01s)
PASS should get edit (0.13s)
ERROR should get index (0.14s)
ActionView::Template::Error: undefined method `full_name' for nil:NilClass
/Users/wenbert/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.1.3/lib/active_support/whiny_nil.rb:48:in `method_missing'
PASS should get new (0.02s)
PASS should show allergy (0.02s)
PASS should update allergy (0.02s)
I have checked the logs and no Patient is saved when I run the test. I just get:
--- !ruby/object:Allergy
attributes:
id: 298486374
name: MyString
desc: MyText
created_at: 2012-01-09 14:28:21.000000000Z
updated_at: 2012-01-09 14:28:21.000000000Z
patient_id: 1
Patient Load (0.2ms) SELECT "patients".* FROM "patients" WHERE "patients"."id" = 1 LIMIT 1
--- !!null
...
So, what gives?
Any replies will be greatly appreciated. I have been stuck at this for almost 4 hours now. :(
Could it be my fixtures? My Models?
Best Regards,
W
FYI: I am using Ruby on Rails 3.1
Your fixtures have the same names, name them as following
allergy_one:
name: ...
patient: patient_one
allergy_two:
name: ...
patient_one:
name: ..
You will notice that I do not use patient_id in the fixtures. You need to reference the patient fixture you want as fixtures use random ids and do not start at 1.