Rails - 电子邮件确认链接给出“未知操作”错误

Posted

技术标签:

【中文标题】Rails - 电子邮件确认链接给出“未知操作”错误【英文标题】:Rails - Email confirmation link giving 'Unknown Action' error 【发布时间】:2013-04-22 18:51:53 【问题描述】:

我需要一点帮助。我正在尝试:

    发送带有链接的电子邮件。 让链接设置 user.email_activation_token = true 然后重定向到主页。

目前我有一个指向电子邮件的链接,但它给了我这个错误。 (顺便说一句,我正在使用 HAML。)

编辑:目前没有视图。

未知操作

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(用户模型)

    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

【问题讨论】:

【参考方案1】:

你为什么在 accept_invitation_users_url 中传递激活令牌而不是 id?当你有这个代码时:

resources :users do
  member do 
    get :accept_invitation
  end 
end

在路由中,我们假设accept_invitation 是一个Restful 路由并且会在它的url 中给出id。见http://guides.rubyonrails.org/routing.html#adding-more-restful-actions

所以,我认为你应该这样做:

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

看完cmets

是的,正如@Frederick Cheung 在 cmets 中所说,传递 id 而不是令牌会破坏发送电子邮件确认的意义,并使人们可以轻松地确认电子邮件地址而无需实际接收电子邮件。

所以,请参考@PriteshJ 的回答。显然,您刚刚在routes.rb 中添加了一个额外的行resources :users,我对此大惊小怪:)。只需删除该行就可以了。

【讨论】:

传递令牌应该没问题。如果不通过,我会失败,并且会让人们在没有实际收到电子邮件的情况下轻松确认电子邮件地址。 嘿,我试过了,但后来我在 UsersController#accept_invitation 中得到 ActiveRecord::RecordNotFound ---找不到没有 ID 的用户 @AlainGoldman..我在前面的答案中使用了collection 而不是member。现在必须修复它。【参考方案2】:

试着改变这样的路线..

    resources :users do
      collection do 
        get :accept_invitation
      end 
    end

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

【讨论】:

【参考方案3】:

您已调用资源 :users 两次。

删除第一个调用

【讨论】:

【参考方案4】:

routes.rb中有两条用户路由

删除resources :users

第一个 resources users 覆盖下一个用户资源

所以应用程序不知道 collection 路由 accept_invitation 和 将其视为 id 用于显示操作,因为该操作的 url 将是

/users/accept_invitation

与show /users/:id的签名相匹配

删除第一个 resources :users 应该可以解决问题

我也没有看到 email_activations_controller.rb 的任何用途

也许你可以安全地删除它

【讨论】:

以上是关于Rails - 电子邮件确认链接给出“未知操作”错误的主要内容,如果未能解决你的问题,请参考以下文章

Rails 中的电子邮件确认,无需使用任何现有的身份验证 gem/插件

rails - Gibbon mailchimp gem 将订阅者添加到列表中,但不发送确认电子邮件

从 cakePHP 中的控制器输出超链接

用户确认电子邮件不发送到生产中。 Rails,Heroku,Gmail

用户注册时设计“确认令牌无效”

Ruby on Rails:延迟的作业无法使用邮件程序并给出路由错误