Reputation: 47
I will briefly explain the feature before I start explaining the issue. When a user signs up they get an activation token in their email which expires in 2 hours. I was trying to implement a feature which allows users to resend the activation token in their email.
The code for the resend activation token feature is given below.
Controller code in users controller
def resend_verification_email
@user = User.find_by(email: params[:resend_verification_email] [:email].downcase)
if valid_email(params[:resend_verification_email] [:email])
if !@user
redirect_to resend_verification_path
flash[:danger] = "Email does not exist"
elsif
[email protected]?
UserMailer.resend_activation(@user).deliver_now
flash[:success] = "Check your email for the activation token"
redirect_to resend_verification_path
else
redirect_to resend_verification_path
flash[:success] = "User is already activated."
end
else
flash[:danger] = "Email format is Invalid"
redirect_to resend_verification_path
end
end
Account activations controller
class AccountActivationsController < ApplicationController
def edit
user = User.find_by(email: params[:email])
if user && !user.activated? && user.authenticated?(:activation, params[:id]) #the token is actually available by params id
user.activate
log_in user
flash[:success] = "Account activated."
redirect_to home_path
else
flash[:danger] = "Invalid activation link"
redirect_to root_url
end
end
end
The mailer controller method
def resend_activation(user)
@user = user
@userid = user.id
mail to: user.email, subject: "Account activation"
end
The mailer view
<%= link_to "Activate your account", edit_account_activation_url(id: @user.activation_token, email: @user.email) %>
I get the following error. No route matches {:action=>"edit", :controller=>"account_activations", :email=>"[email protected]", :id=>nil} missing required keys: [:id]
.
I understand what the error is saying. The url's first argument is the token and the way to grab is through params[:id] because in RESTful routes, id is always the first argument. The email is sent out fine if I get rid of the URL. The URL is throwing that error and I am not really sure why. Any help would be appreciated. Thanks!
I only included the relevant routes.
get 'resend_verification' => 'users#resend_verification'
post 'resend_verification_email' => 'users#resend_verification_email'
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
Relevant rake routes
edit_account_activation GET /account_activations/:id/edit(.:format) account_activations#edit
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
resend_verification GET /resend_verification(.:format) users#resend_verification
resend_verification_email POST /resend_verification_email(.:format) users#resend_verification_email
Upvotes: 0
Views: 86
Reputation: 2218
:activation_token
is created virtually as attr_accessor
This is not a routing issue.
@user.activation_token
is actually returning nil.
You will need to save activation_token to the user model if you wish to send further validation emails.
Upvotes: 0
Reputation: 520
Redefine your email link as follows:
<%= link_to "Activate your account", edit_account_activation_path( @user.activation_token, @user.email) %>
Or you can just pass the primary key of your object to your controller and ex: @user.id
and use
before_action :set_user, only: [:edit]
define private method inside of your controller for set user ex:
private
def set_user
@user = User.find_by_id(params[:id])
redirect_to xyz_path if @user.blank?
end
Upvotes: 0
Reputation:
Well, I wouldn't define account_activations
as a resourceful route.
The comment: #the token is actually available by params id
explains why, imo id
should refer to a model resource instead.
Here's my workaround for the issue:
get "/account_activations/edit", to: "account_activations#edit", as: 'edit_account_activation'
<%= link_to "Activate your account", edit_account_activation_url(token: @user.activation_token, email: @user.email) %>
class AccountActivationsController < ApplicationController
def edit
user = User.find_by(email: params[:email])
if user && !user.activated? && user.authenticated?(:activation, params[:token])
#... rest of code...
Alternatively, if you really wanna keep as it currently is, then try redefining you email link as follows:
<%= link_to "Activate your account", edit_account_activation_url(@user.activation_token, email: @user.email) %>
Then, params[:id]
might refer to the token you're providing.
Upvotes: 1