Ruby on Rails 3 Tutorial gravatar_for test error - ruby

So I am working through the Ruby on Rails 3 Tutorial. I am currently on section 7.1.3 Testing the User show page using factories.
The code is working and pulls the proper gravatar image however I keep getting an error when running my tests.
Here is the error:
Failure/Error: before { visit user_path(user) }
ActionView::Template::Error:
undefined method `downcase' for nil:NilClass
Here is the code from the show.html.erb file:
<% provide(:title, #user.name) %>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
<%= #user.name %>, <%= #user.email %>
Here is the code from the users_helper.rb file:
module UsersHelper
# Returns the Gravatar (http://gravatar.com/) for the given user.
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
Here is the code from factories.rb file:
FactoryGirl.define do
factory :user do
name "Curtis Test"
email "test#gmail.com"
password "foobar"
password_confirmation "foobar"
end
end
Here is the code from the test file user_pages_spec.rb
require 'spec_helper'
describe "User Pages" do
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
describe "signup page" do
before { visit signup_path }
it { should have_selector('title', text: full_title('Sign Up')) }
end
end

I discovered my problem. It had nothing to do with FactoryGirl. The problem was in my user model (user.rb), the line that was causing the issue was
before_save { |user| user.email = user.email.downcase! }
The bang after the downcase was causing the email address to be saved as nil since the return of the downcase! is nil. Once I removed that and made the line look like the following it worked just fine.
before_save { |user| user.email = user.email.downcase }
The way I found it was to load the rails console in test environment and tried to create a new user. I noticed that everything was fine but the email was null.

In general, you can debug issues such as this one by referring to the Rails Tutorial sample app reference implementation.

Related

Rails 5.2 ActionMailer Mail won't send. Can't see any error in server

Trying to send a volunteering form through SMTP using Gmail, Sendgrid or anything really however I have Action Mailer all set up and I presume I should really be seeing the email come through when I look at the email. I can see this error below but cannot see any error or receive any email at all. I've tried writing puts in my create action but I do not see those either so this is hopefully an easy fix as I'm missing something or have something not follow the usual Rails convention.
I'm using rails 5.2
What I see in the server:
Started GET "/volunteer?utf8=%E2%9C%93&authenticity_token=AZ%2FAflVf%2BlqRUYm45Jo82wAMpq%2B%2BY%2F93piLbeRXdK5n%2FQIWhuaUL3Oe2%2FSwzR%2FCLvj%2FAKW%2BBgD8dPd8vJYRDBA%3D%3D&volunteer_message%5Bname%5D=test+name&volunteer_message%5Bemail%5D=email%40test.com&volunteer_message%5Bphone_number%5D=88888888&volunteer_message%5Bbody%5D=test+email&commit=Send" for 127.0.0.1 at 2018-10-10 17:29:42 +0100
Processing by PagesController#volunteer as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"AZ/AflVf+lqRUYm45Jo82wAMpq++Y/93piLbeRXdK5n/QIWhuaUL3Oe2/SwzR/CLvj/AKW+BgD8dPd8vJYRDBA==", "volunteer_message"=>{"name"=>"test name", "email"=>"email#test.com", "phone_number"=>"88888888", "body"=>"test email"}, "commit"=>"Send"}
Ok so here's my code and the way it's all layed out.
PagesController.rb contains a page called volunteer and this contains the partial (Called _new.html.erb) which is the form which is in it's own folder called volunteer_messages
views/volunteer_messages/_new.html.erb
<%= simple_form_for #volunteer_message, url: create_volunteer_message_url do |f| %>
<%= #volunteer_message.errors.full_messages.join(', ') %>
<%= f.input :name, placeholder: 'name' %>
<%= f.input :email, placeholder: 'email' %>
<%= f.input :phone_number, placeholder: 'phone number' %>
<%= f.input :body, placeholder: 'body' %>
<%= f.submit 'Send' %>
<% end %>
routes created
# is this causing a problem do you think?
get '/volunteer' => 'pages#volunteer'
# volunteer message routes
get '/volunteer', to: 'volunteer_message#new', as: 'new_volunteer_message'
post '/volunteer', to: 'volunteer_message#create', as: 'create_volunteer_message'
models/volunteer_message.rb
class VolunteerMessage
include ActiveModel::Model
attr_accessor :name, :email, :phone_number, :body
# validates :name, :email, :phone_number, :body, presence: true
end
mailers/volunteer_message_mailer.rb
class VolunteerMessageMailer < ApplicationMailer
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.volunteer_message_mailer.volunteer.subject
#
def volunteer(volunteer_message)
#body = volunteer_message.body
#subject = "Volunteer Request sent from www.myapp.com"
mail to: "myemail#example.com", from: volunteer_message.email
end
end
volunteer_messages_controller.rb
class VolunteerMessagesController < ApplicationController
def new
#volunteer_message = VolunteerMessage.new
end
def create
#volunteer_message = VolunteerMessage.new volunteer_message_params
if #volunteer_message.valid?
VolunteerMessageMailer.volunteer(#volunteer_message).deliver_now
redirect_to new_volunteer_message_url
flash.now[:notice] = "We have received your volunteer request and will be in touch soon!"
else
flash.now[:notice] = "There was an error sending your volunteer request. Please try again."
render :new
end
end
private
def volunteer_message_params
params.require(:volunteer_message).permit(:name, :email, :phone_number, :body)
end
end
pages_controller.rb
class PagesController < ApplicationController
def volunteer
#lead = Lead.new
#volunteer_message = VolunteerMessage.new
end
end
development.rb
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
domain: 'gmail.com',
enable_starttls_auto: true,
user_name: 'me#gmail.com',
password: 'gmailapppassword',
authentication: 'plain'
}
Not sure what else I can add here. I do not think I even need he stmp_settings to see action mailer actually show the template of the email being sent?
Also I'm guessing it is somehting to do with the form and the route because ive added puts messages into the create action on the volunteer_message controller and do not see them in my server log.
I'm not getting any errors when pressing submit. I do notice the params going into the url but that's it. it stays there and when refreshes stays on the same screen.
example:
http://localhost:3000/volunteer?utf8=%E2%9C%93&authenticity_token=AZ%2FAflVf%2BlqRUYm45Jo82wAMpq%2B%2BY%2F93piLbeRXdK5n%2FQIWhuaUL3Oe2%2FSwzR%2FCLvj%2FAKW%2BBgD8dPd8vJYRDBA%3D%3D&volunteer_message%5Bname%5D=test+name&volunteer_message%5Bemail%5D=email%40test.com&volunteer_message%5Bphone_number%5D=88888888&volunteer_message%5Bbody%5D=test+email&commit=Send
Is the clue in the server text in the image that shows params going to the pages controller. I do not really want that. Just want the partial to be there but the action to work of the create action in the volunteer_messages controller.
Any help be much appreciated. Thanks.

wrong redirect with capybara

I have problem in my previous question, me helped, but and now I've took new.
I'm make integration tests with rspec and capybara.
this my profiles_controllers.rb :
before_filter :authenticate_user!
def update
#profile = current_user.profile
if #profile.update_attributes(params[:profile])
flash[:success] = "Профиль обновлен!"
redirect_to user_path(current_user)
else
render 'edit'
end
end
it's my test file:
describe "ProfilePages" do
subject { page }
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
let(:profile) { FactoryGirl.create(:profile, user: user) }
before do
login user
visit edit_profile_path(profile)
end
it { should have_selector('h2', text: 'Заполните информацию о себе') }
describe "change information" do
let(:new_city) { "Ulan-Bator" }
let(:new_phone) { 1232442 }
let(:new_gamelevel) { "M2" }
let(:new_aboutme) { "nfsfsdfds" }
let(:submit) { "Сохранить" }
before do
fill_in "Город", with: new_city
fill_in "Телефон", with: new_phone
select new_gamelevel, from: "Уровень игры"
fill_in "О себе", with: new_aboutme
click_button submit
end
specify { profile.reload.city.should == new_city }
specify { profile.reload.phone.should == new_phone }
specify { profile.reload.gamelevel.should == new_gamelevel }
specify { profile.reload.aboutme.should == new_aboutme }
end
describe "submitting to the update action" do
before { put profile_path(profile) }
specify { response.should redirect_to(user_path(user)) }
end
end
end
And I have error:
Failure/Error: specify { response.should redirect_to(user_path(user)) }
Expected response to be a redirect to http://www.example.com/users/1 but was a redirect to http://www.example.com/users/sign_in
I use Devise and have login helper in spec/support:
def login(user)
page.driver.post user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
end
And config.include Devise::TestHelpers, :type => :controller in spec_helper.rb
I tried use warden helper login_as , but have same error. How I understand it's don't start session, I'am right?
This is nothing to do with your app code, but the test code.
response object is for controller integration tests, and there is no such object in Capybara.
Normally you can use page object to check response information. And for path checking, a better approach is current_path or current_url.
So your code will work by:
current_path.should be(user_path(user))

Ruby on Rails RSpec put method doesn't see signed in user

so I've been using Michael Hartl's tutorial for some time and I can say it's really useful but there's a problem and I gues it's not on the tutorial's part. So in chapter "9.2.2 Requiring the right user" ther's a test for checking that a user can access neither other user's edit page nor submit a direct PUT reauest.
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user }
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
end
describe "submitting a PUT request to the Users#update action" do
before { put user_path(wrong_user) }
specify { response.should redirect_to(root_path) }
end
end
So long all seems right but the test fails:
1) Authentication authorization as wrong user submitting a PUT request to the Users#update action ←[31mFailure/Error:←[0m ←[31mspecify { response.should redirect_to(root_path }←[0m←[31mExpected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>←[0m←[36m # ./spec/requests/authentication_pages_spec.rb:107:in `block (5 levels) in <top (required)>'←[0m
Here's the User controller:
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
before_filter :correct_user, only: [:edit, :update]
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
private
def signed_in_user
unless signed_in?
puts "No user signed in"
store_location
redirect_to signin_path, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
puts "Incorrect user" unless current_user?(#user)
redirect_to(root_path) unless current_user?(#user)
end
end
So as you can see the problem is that when using RSpec put method, the test fails even before checking for the right user because it sees ther's no user signed in.
This is a small problem which can easily be omitted (incorrect user cannot make direct PUT request anyway) but it's a puzzle for me why doesn't it work correct and I can't get the answer for quite a time already.
It looks like the signed_in_user filter is redirecting back to the sign in page before the correct_user fires. That suggests that the user is not actually signed in correctly by the sign_in user call in the before block.
Have you defined sign_in in spec/support/utilities.rb?
include ApplicationHelper
def sign_in(user)
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
# Sign in when not using Capybara as well.
cookies[:remember_token] = user.remember_token
end

RSpec: ActionView::Template::Error: undefined method `full_name' for nil:NilClass

I am getting this error, when starting spec tests. I understand that connection with the user is not set. What shall I do to pass the tests?
RSpec file : posts_controller_spec.rb
require 'spec_helper'
include Devise::TestHelpers
describe PostsController do
render_views
context "Logged in as user" do
let(:user) { FactoryGirl.create(:user) }
before { login_as(user) }
context "on viewing index page" do
let!(:p) { FactoryGirl.create(:post) }
before { get :index }
it { should respond_with(:success) }
it { assigns(:posts).should == [p] }
end
end
end
My view: _home.html.erb
<% #posts.each do |post| %>
<%= link_to post.title, post %>
<%= post.user.full_name %></i></b><hr />
<div>
<%= post.content.html_safe %>
</div>
<% end %>
RSpec failures:
PostsController Logged in as user on viewing index page
Failure/Error: before { get :index }
ActionView::Template::Error:
undefined method `full_name' for nil:NilClass
# ./app/views/posts/_home.html.erb:5:in `block in _app_views_posts__home_html_erb__709569216_93469850'
# ./app/views/posts/_home.html.erb:2:in `each'
# ./app/views/posts/_home.html.erb:2:in `_app_views_posts__home_html_erb__709569216_93469850'
# ./app/views/posts/index.html.erb:1:in `_app_views_posts_index_html_erb___825727830_90641210'
# ./spec/controllers/posts_controller_spec.rb:33:in `block (4 levels) in <top (required)>'
Without seeing your model for Post and User, it looks like you need to change
let!(:p) { FactoryGirl.create(:post) }
to
let!(:p) { FactoryGirl.create(:post, :user => user) }
or
let!(:p) { FactoryGirl.create(:post, :user_id => user.id) }
to correctly set up the association.
However, if your view is assuming that a Post always has a User, maybe your Post model should validate the presence of a User, or maybe you should change your view to handle the case where a Post does not have a User.

Rails Tutorial Chapter 7, Exercise 4 [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm having trouble with Exercise 4 in Chapter 7 of railstutorial.org.
Here are the tests:
describe "signup" do
before { visit signup_path }
describe "with invalid information" do
it "should not create a user" do
expect { click_button "Create my Account".not_to change(User, :count) }
end
end
describe "error messages" do
before { click_button "Create my account" }
it { should have_selector('title', text: "Sign up") }
it { should have_content('error') }
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect do
click_button "Create my account"
end.to change(User, :count).by(1)
end
end
describe "after saving the user" do
before { click_button "Create my account" }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
end
end
Here is what it's supposed to test, users_controller.rb:
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
Here's the show.html.erb code as well:
<% provide(:title, #user.name) %>
<div class="row">
<aside class="span4">
<section>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
</section>
</aside>
</div>
When I run my tests, I get this:
$ bundle exec rspec spec/requests/user_pages_spec.rb
........FF
Failures:
1) User Pages signup after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:57:in `block (4 levels) in <top (required)>'
2) User Pages signup after saving the user
Failure/Error: it { should have_selector('div.alert.alert-success', text: 'Welcome') }
expected css "div.alert.alert-success" with text "Welcome" to return something
# ./spec/requests/user_pages_spec.rb:58:in `block (4 levels) in <top (required)>'
Finished in 0.86152 seconds
10 examples, 2 failures
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:57 # User Pages signup after saving the user
rspec ./spec/requests/user_pages_spec.rb:58 # User Pages signup after saving the user
It should save the test user to the test db, but for some reason, user.name is turning out nil. Any ideas?
Thank you!
Without going over your code in detail to understand the context of everything, it's not that user.name is returning nil, it's that user is nil, and therefore has no method/property name as seen here:
undefined method `name' for nil:NilClass
You have this line here before the test case defining the symbol :user:
let(:user) { User.find_by_email('user#example.com') }
yet you reference the object user in your test:
it { should have_selector('title', text: user.name) }
Change the symbol :user to user in the former and your tests should pass.

Resources