Alain Goldman
Alain Goldman

Reputation: 2908

Rails - Email confirmation link giving 'Unknown Action' error

I need a bit of help. I am trying to:

  1. Send am email with a link.
  2. Have the link set the user.email_activation_token = true
  3. Then redirect to the home page.

Currently I have a link that goes to the email but it gives me this error. (I'm using HAML btw.)

Edit: There is no view currently.

Unknown action

The action 'show' could not be found for UsersController

user_mailer/registration_confirmation

Confirm your email address please!

= accept_invitation_users_url({:token=>@user.email_activation_token})

users_controller.rb

class UsersController < ApplicationController
  def new
    @user = User.new
  end
  def create
    @user = User.new(params[:user])
    if @user.save
      UserMailer.registration_confirmation(@user).deliver
        redirect_to root_url, :notice => "Signed up!"
    else
        render "new"
    end

    def accept_invitation
        @user = User.find_by_email_activation_token!(params[:token])
        @user.email_activation_token = true
        redirect_to root_url, :notice => "Email has been verified."
    end
  end
end

email_activations_controller.rb

class EmailActivationsController < ApplicationController
    def edit
        @user = User.find_by_email_activation_token!(params[:id])
        @user.email_activation_token = true
        save!
        redirect_to root_url, :notice => "Email has been verified."
    end
    def new
        @user = User.find_by_email_activation_token!(params[:id])
    end

    def edit
    end
end

user.rb (user model)

    class User < ActiveRecord::Base
      attr_accessible :email, :password, :password_confirmation

      attr_accessor :password
      before_save :encrypt_password
      before_save { |user| user.email = email.downcase }
      before_create { generate_token(:auth_token) }
      # before_create { generate_token(:email_activation_token) }

      VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
      VALID_PASSWORD_REGEX = /^(?=.*[a-zA-Z])(?=.*[0-9]).{6,}$/
      validates_confirmation_of :password
      validates :password, :on => :create, presence: true, format: { with: VALID_PASSWORD_REGEX }
      validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }

  def self.authenticate(email, password)
   user = find_by_email(email)
   if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
    user
   else  
    nil
  end
end

  def send_password_reset
    generate_token(:password_reset_token)
    self.password_reset_sent_at = Time.zone.now
    save!
    UserMailer.password_reset(self).deliver
  end

  def encrypt_password
    if password.present?
        self.password_salt = BCrypt::Engine.generate_salt
        self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
    end
  end

def generate_token(column)
  begin
    self[column] = SecureRandom.urlsafe_base64
  end while User.exists?(column => self[column])
end

end

routes.rb

LootApp::Application.routes.draw do
  get "password_resets/new"

  get "sessions/new"

  resources :users
  resources :sessions
  resources :password_resets
  resources :email_activations

  resources :users do
    collection do 
      get :accept_invitation
    end 
  end

  # get "users/new"
  get "static_pages/home"
  get "static_pages/help"


  root to: 'static_pages#home'
  match "sign_up",  to: "users#new"
  match '/help',    to: 'static_pages#help'
  match '/log_in',  to: 'sessions#new'
  match '/log_out', to: 'sessions#destroy'
end

Upvotes: 1

Views: 453

Answers (4)

rubyprince
rubyprince

Reputation: 17793

Why are you passing, activation token instead of id in the accept_invitation_users_url? When you have this code:

resources :users do
  member do 
    get :accept_invitation
  end 
end

in the routes, we are assuming that, accept_invitation is a Restful route and will give id in its url. See http://guides.rubyonrails.org/routing.html#adding-more-restful-actions

So, I think you should be doing something like this:

routes.rb

# resources :users ### Remove this as it is reduntant

resources :users do
  member do 
    get :accept_invitation
  end 
end

user_mailer/registration_confirmation

Confirm your email address please!

= accept_invitation_users_url(@user)

users_controller.rb

def accept_invitation
  @user = User.find(params[:id])
  @user.email_activation_token = true
  redirect_to root_url, :notice => "Email has been verified."
end

After reading comments

Yes, as @Frederick Cheung said in the comments, passing id instead of token would defeat the point of sending the email confrmation and would make it easy for people to confirm an email address without actually receiving the email.

So, please refer to @PriteshJ's answer. Apparently, you just added an extra line resources :users, in routes.rb and I made a fuss out of it :). Just remove the line and you will be ok.

Upvotes: 2

Pritesh Jain
Pritesh Jain

Reputation: 9146

there are two routes for users in routes.rb

remove resources :users

the first one resources users overrides the next users resource

so the application does not know there is a collection route for accept_invitation and treats it as a id for show actions as the url genreated for the action will be

/users/accept_invitation

which matches the signature of show /users/:id

removing the first resources :users should do the trick

also I don't see any use of email_activations_controller.rb

may be you can safely remove it

Upvotes: 2

user946611
user946611

Reputation:

You have called resources :users twice.

Remove the first call

Upvotes: 2

Harish Malik
Harish Malik

Reputation: 89

Try by changing the routes like this ..

    resources :users do
      collection do 
        get :accept_invitation
      end 
    end

    resources :users
    resources :sessions
    resources :password_resets
    resources :email_activations

Upvotes: 2

Related Questions