Reputation: 152
I am following the Ruby on Rails Tutorial and am coming across an error which says, in full: ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"password_resets", :email=>"[email protected]", :id=>nil}, possible unmatched constraints: [:id]
This relates to code allowing the user to reset their password from a form. The error refers to a route, so I'll start there with routes.rb
:
get 'sessions/new'
root 'static_pages#home'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/help', to: 'static_pages#help'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
The error mentions the edit
action which is blank within the controller. The reset functionality is produced from the create
action in the password_resets_controller
like:
def create
@user = User.find_by(email: params[:password_reset][:email].downcase)
if @user
@user.create_reset_digest
@user.send_password_reset_email
flash[:info] = "Email sent with reset instructions"
redirect_to root_url
else
flash[:danger] = "Email address not found"
render 'new'
end
end
def edit
end
This pulls the user from the database using the email submitted on the form. Then calls two methods from the model to walk through the reset process. First, the create_reset_digest
method which creates a token and updates the attributes for that user:
def create_reset_digest
self.activation_token = User.new_token # <- error here; wrong attribute
update_attributes(reset_digest: User.digest(reset_token),
reset_sent_at: Time.zone.now)
end
Then, it sends the password reset email:
def send_password_reset_email
UserMailer.password_reset(self).deliver_now
end
In the email, there is mention of the edit_password_reset_url
which I think is the cause of this error. The view for that email is:
<%= link_to "Password reset", edit_password_reset_url(@user.reset_token,
email: @user.email) %>
This method takes the user's reset token and email and presents this in a url that the user can visit to reset their password. The url takes the form http://example.com/password_resets/reset_token/edit?email="steve%40example.com"
The error implies that there's a constraint that remains unmatched; that the [:id]
isn't matched - indeed, it is shown to be nil
. Where does that :id=>nil
come from and how can I get it to match to, presumably, the user id? Can I imply anything else from the error message?
I am getting this error when I run a rudimentary test:
test "password_reset" do
@user.activation_token = User.new_token
mail = UserMailer.password_reset(@user)
assert_equal "Password reset", mail.subject
assert_equal ["[email protected]"], mail.to
assert_equal ["[email protected]"], mail.from
assert_match "Hi", mail.body.encoded
end
When I use the web app to fire the password reset, I get a slightly different error in that it is a ActionController::UrlGenerationError in PasswordResets#create
. This highlights the edit_password_reset_url((@user.reset_token, email: @user.email)
method. I've checked in the book and can't see that this line is incorrect.
Your advice is welcomed.
Upvotes: 0
Views: 981
Reputation: 20263
It appears you do not set @user.reset_token
(used in link_to
)? I see something like self.activation_token = User.new_token
. But not something like self.reset_token = ....
.
Upvotes: 2