Rails通过区域设置发送用户激活链接

时间:2016-05-18 09:21:20

标签: ruby-on-rails ruby email locale

我创建了一个用户模型,当用户注册时,会发送电子邮件确认邮件。但是当我将locale添加到我的rails应用程序时,它开始出错。

这是user#create action;

def create
  @user = User.new(user_params)
  respond_to do |format|
    if @user.save
      flash[:notice] = '..'
      format.html  { redirect_to root_url }        
       format.js   { render action: 'new', status: :created }  
        @user.send_activation_email
    else    
     format.html { render action: 'new' }
     format.js   { render json: @user.errors, status: 404 }
      end
    end
  end

帐户激活控制器;

class AccountActivationsController < ApplicationController



     def edit
        user = User.find_by(email: params[:email])
        if user && !user.activated? && user.authenticated?(:activation, params[:id])
          user.activate
          log_in user
          flash[:success] = "activated!"
          redirect_to user
        else
          flash[:alert] = "Invalid link"
          redirect_to root_url
        end
      end
    end

user.rb的一部分

 # 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?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end


  # Forgets a user.
  def forget
    update_attribute(:remember_digest, nil)
  end

  # Activates an account.
  def activate
    update_attribute(:activated,    true)
    update_attribute(:activated_at, Time.zone.now)
  end

  # Sends activation email.
  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end

  # Sets the password reset attributes.
  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest,  User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  # Sends password reset email.
  def send_password_reset_email
    UserMailer.password_reset(self).deliver_now
  end

  # Returns true if a password reset has expired.
  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  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

最后,account_activation.html.erb

<h1>Sample</h1>

<p>Hi <%= @user.name %>,</p>

<p>
Welcome to ...! Click on the link below to activate your account:
</p>

<%= link_to "Activate", edit_account_activation_url(@user.activation_token,
                                                    email: @user.email, locale: @locale) %>

最后,来自控制台的错误;

Started POST "/tr/users" for ::1 at 2016-05-18 12:01:24 +0300
I, [2016-05-18T12:01:24.453564 #454]  INFO -- : Processing by UsersController#create as JS
I, [2016-05-18T12:01:24.453779 #454]  INFO -- :   Parameters: {"utf8"=>"✓", "user"=>{"name"=>"234234", "username"=>"234234", "email"=>"234@sdf.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "user_type"=>"Personal Account", "terms_of_service"=>"1"}, "commit"=>"Hesap Oluştur", "locale"=>"tr"}
D, [2016-05-18T12:01:24.546048 #454] DEBUG -- :    (0.2ms)  begin transaction
D, [2016-05-18T12:01:24.547422 #454] DEBUG -- :   User Exists (0.2ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('234@sdf.com') LIMIT 1
D, [2016-05-18T12:01:24.548145 #454] DEBUG -- :   User Exists (0.1ms)  SELECT  1 AS one FROM "users" WHERE "users"."username" = '234234' LIMIT 1
D, [2016-05-18T12:01:24.725087 #454] DEBUG -- :   SQL (0.4ms)  INSERT INTO "users" ("name", "email", "password_digest", "username", "user_type", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?, ?, ?, ?, ?)  [["name", "234234"], ["email", "234@sdf.com"], ["password_digest", "$2a$10$l3JDATUxIMIKvMIYYtRhQ.AR8GSC3C9ybwXIFjGgU3ORCeUDjtpra"], ["username", "234234"], ["user_type", "Personal Account"], ["created_at", "2016-05-18 09:01:24.549035"], ["updated_at", "2016-05-18 09:01:24.549035"], ["activation_digest", "$2a$10$STp22TuKMbPbn14XXgVJa.yGYd3h9o31xMeEZxcNDsvAJQM4lpQ0."]]
D, [2016-05-18T12:01:24.729336 #454] DEBUG -- :    (2.7ms)  commit transaction
I, [2016-05-18T12:01:24.751436 #454]  INFO -- :   Rendered user_mailer/account_activation.html.erb within layouts/mailer (4.2ms)
D, [2016-05-18T12:01:24.751639 #454] DEBUG -- : 
UserMailer#account_activation: processed outbound mail in 21.0ms
I, [2016-05-18T12:01:24.751911 #454]  INFO -- : Completed 500 Internal Server Error in 296ms
F, [2016-05-18T12:01:24.801486 #454] FATAL -- : 
ActionController::UrlGenerationError (No route matches {:action=>"edit", :controller=>"account_activations", :email=>"234@sdf.com", :format=>nil, :id=>nil, :locale=>nil} missing required keys: [:id]):
  app/views/user_mailer/account_activation.html.erb:9:in `_app_views_user_mailer_account_activation_html_erb___3249946951177976060_70255610070180'
  app/mailers/user_mailer.rb:10:in `account_activation'
  app/models/user.rb:95:in `send_activation_email'

它为id params帐户激活控制器提供的错误,因为该链接是编辑链接查找ID。问题是,在将区域设置放置到路径

之前,此结构正在运行

路线;

scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do  
...
resources :account_activations, only: [:edit]
...
end   

所以当我在帐户激活html中发送用户的id为;

<%= link_to "Activate", edit_account_activation_url(@user.activation_token,
                                                    email: @user.email, id: user.id ) %>

链接生成;

localhost:3000/78y5fzxrFtGzwpr5RHlnCQ/account_activations/7/edit?email=....%40.....com

所以我在这里看到的是,而不是令牌应该有locale变量,让我们说fr,而不是id应该有像这样的令牌;

localhost:3000/fr/account_activations/78y5fzxrFtGzwpr5RHlnCQ/edit?email=....%40.....com

谢谢

修改

我已经抱歉了;

class ApplicationController < ActionController::Base
before_filter :set_locale

 def set_locale
      I18n.locale = params[:locale] || I18n.default_locale
      @locale = params[:locale] || I18n.default_locale
    end

    def default_url_options(options = {})
      {locale: I18n.locale}

    end

end

因此,如果我将电子邮件中的链接更改为;

<%= link_to "Activate", edit_account_activation_url(id: @user.activation_token, email: @user.email, locale: "fr") %>

它的工作正常但是,如何将locale变量传递给电子邮件?

修改

我已经传递了一个变量: usermailer

def account_activation(user)
    @user = user
    @locale = I18n.locale
    mail to: user.email, subject: "Account activation"
  end

然后在链接中调用:

<%= link_to "Activate", edit_account_activation_url(id: @user.activation_token,
email: @user.email, locale: @locale) %>

希望帮助别人。

1 个答案:

答案 0 :(得分:1)

您仍然需要在路由中明确设置区域设置,请参阅此question,因此在ApplicationController中包含类似的内容:

   def set_locale
     I18n.locale = params[:locale] || session[:locale] || I18n.default_locale
     session[:locale] = I18n.locale
   end

   def default_url_options(options={})
     logger.debug "default_url_options is passed options: #{options.inspect}\n"
     { locale: I18n.locale }
   end

现在,当您使用url helpers时,将自动合并locale选项。