我需要调整忘记密码说明来处理子域名。 我按照设备网站上的说明覆盖了邮件程序,控制器并添加了一个子域帮助程序等,如下所示:
控制器/ password_controller.rb
class PasswordsController < Devise::PasswordsController
def create
@subdomain = request.subdomain
super
end
end
的routes.rb
devise_for :users, controllers: { passwords: 'passwords' }
devise.rb
config.mailer = "UserMailer"
寄件人/ user_mailer.rb
class UserMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
def confirmation_instructions(record, opts={})
devise_mail(record, :confirmation_instructions, opts)
end
def reset_password_instructions(record, opts={})
devise_mail(record, :reset_password_instructions, opts)
end
def unlock_instructions(record, opts={})
devise_mail(record, :unlock_instructions, opts)
end
end
视图/ user_mailer文件/ reset_password_instructions.html.erb
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token, :subdomain => @subdomain) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
助手/ subdomain_helper.rb
module SubdomainHelper
def with_subdomain(subdomain)
subdomain = (subdomain || "")
subdomain += "." unless subdomain.empty?
host = Rails.application.config.action_mailer.default_url_options[:host]
[subdomain, host].join
end
def url_for(options = nil)
if options.kind_of?(Hash) && options.has_key?(:subdomain)
options[:host] = with_subdomain(options.delete(:subdomain))
end
super
end
end
application.rb中
config.to_prepare do
Devise::Mailer.class_eval do
helper :subdomain
end
end
现在,这段代码全部正常工作,但它无法在邮件程序视图中获取@subdomain的值。如果我用一个硬编码的字符串替换@subdomain,那么在电子邮件中传递正确的url,所以我知道代码是正确的。
如何将控制器中定义的实例变量@subdomain放入邮件程序视图?
答案 0 :(得分:7)
我找到了办法。我会想如果我能找到一个更好的方法而不必修补补丁并且必须将其链接到子域。
基本上,我覆盖控制器执行此操作:
class PasswordsController < Devise::PasswordsController
def create
subdomain = request.subdomain
@user = User.send_reset_password_instructions(params[:user].merge(subdomain: subdomain))
if successfully_sent?(@user)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(:user))
else
respond_with(@user)
end
end
end
另外,我不得不在我的用户模型上修补这些方法:
def send_reset_password_instructions(subdomain)
generate_reset_password_token! if should_generate_reset_token?
send_devise_notification(:reset_password_instructions, subdomain: subdomain)
end
def self.send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
recoverable.send_reset_password_instructions(attributes[:subdomain]) if recoverable.persisted?
recoverable
end
最后,我不得不使用补丁devise_mail
方法,它们存在于Devise中。
Devise::Mailer.class_eval do
def devise_mail(record, action, opts={})
initialize_from_record(record)
initialize_subdomain(opts.delete(:subdomain)) # do this only if the action is to recover a password.
mail headers_for(action, opts)
end
def initialize_subdomain(subdomain)
@subdomain = instance_variable_set("@subdomain", subdomain)
end
end
这样做,@subdomain
变量出现在邮件程序模板上。我对这个解决方案不满意,但这是一个起点。我会考虑对它的任何改进。
答案 1 :(得分:1)
这是一个更新的答案,我认为很好地解决了您的问题 - https://github.com/plataformatec/devise/wiki/How-To:-Send-emails-from-subdomains
在我的情况下,我的子域存储在我的Accounts表中,这就是我允许我在我的设计邮件视图中使用@resource.subdomain
所做的事情
class User < ActiveRecord::Base
belongs_to :account
# This allows me to do something like @user.subdomain
def subdomain
account.subdomain
end
end
class Account < ActiveRecord::Base
has_many :users
end
答案 2 :(得分:1)
对于设计3.1,用户模型中的上述猴子修补可以如下所示。如果您的子域存储在一个单独的模型(比如租户)中,这个模型与其他模型(如帐户,用户)无关,那就是它。(找到类似current_tenant.subdomain)
def send_reset_password_instructions(subdomain)
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
self.reset_password_token = enc
self.reset_password_sent_at = Time.now.utc
self.save(:validate => false)
send_devise_notification(:reset_password_instructions, raw, {subdomain: subdomain})
raw
end
def self.send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
recoverable.send_reset_password_instructions(attributes[:subdomain]) if recoverable.persisted?
recoverable
end