Cannot seem to find a working answer for this. I'm on Chapter 10, section 10.1.2 of the Rails Tutorial and can't seem to get the mailer preview working. All the answers I've found dealing with the error are related to different sections of the tutorial, and I'm assuming the error I'm making is staring me in the face. I've gone through and copy/pasted the code from the tutorial into the relevant files and so far haven't been able to see a difference between what I typed and what was in the tutorial. So far, the suggestions have been to add or remove the argument user
from the function definitions, but that hasn't solved the problem. The url triggering the error is http://localhost:3000/rails/mailers/user_mailer/account_activation. http://localhost:3000/rails/mailers/user_mailer/ is having no issues, and neither is http://localhost:3000/rails/mailers/user_mailer/password_reset (which I haven't done any customization of yet). What am I missing?
Here's the error:
NoMethodError in Rails::MailersController#preview
undefined method `activation_token=' for nil:NilClass
Extracted source:
def account_activation
user = User.first
user.activation_token = User.new_token # highlighted line
UserMailer.account_activation(user)
end
From what I can tell, the files involved here are:
user_mailer.rb:
class UserMailer < ApplicationMailer
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.account_activation.subject
#
def account_activation(user)
@user = user
mail to: user.email, subject: "Account activation"
end
def password_reset
@greeting = "Hi"
mail to: "[email protected]"
end
end
user_mailer_preview.rb:
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
def account_activation
user = User.first
user.activation_token = User.new_token
UserMailer.account_activation(user)
end
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset
def password_reset
UserMailer.password_reset
end
end
development.rb:
Rails.application.configure do
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :test
host = 'localhost:3000'
config.action_mailer.default_url_options = { host: host }
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params.
config.assets.digest = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
and for completeness, here are the views and my user model:
account_activation.html.erb:
<h1>Sample App</h1>
<p>Hi <%= @user.name %>,</p>
<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>
<%= link_to "Activate", edit_account_activation_url(@user.activation_token,
email: @user.email) %>
account_activation.text.erb: Hi <%= @user.name %>,
Welcome to the Sample App. Click on the link below to activate your account:
<%= edit_account_activation_url(@user.activation_token, email: @user.email) %>
user.rb:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }, allow_blank: true
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token
def User.new_token
SecureRandom.urlsafe_base64
end
# Remembers a user in the database for use in persistent sessions
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
private
# Converts email to all lower-case.
def downcase_email
self.email = email.downcase
end
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
Wow, lot's of debugging and confusion to discover a really simple problem: I wasn't logged in, and hadn't defined any kind of error message for those trying to access that page if they weren't logged in (hence the user.activation_token
method triggering a Nil:NilClass
error). Seems like a good example of why TDD can help out a ton.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With