2013-04-04 2 views
7

Ich muss die Passwort vergessen Anweisungen anpassen, um eine Subdomain zu behandeln. Ich habe die Anweisungen auf der devise Website folgte dem Mailer, Controller und fügen Sie einen Sub-Domain Helfer usw. aufgeführten außer Kraft zu setzen:Rails übergeben request_domain in ein benutzerdefiniertes Devise Mailer Layout

Controller/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" 

Mailer/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 

views/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> 

Helfer/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 

Jetzt, Dieser Code ist alles wor König, aber es kann einfach nicht den Wert von @subdomain in der Mailer-Ansicht erhalten. Wenn ich @subdomain durch eine fest codierte Zeichenfolge ersetze, wird die korrekte URL in der E-Mail übergeben, sodass ich weiß, dass der Code korrekt ist.

Wie bekomme ich die im Controller definierte Instanzvariable @subdomain in die Mailer-Ansicht?

Antwort

7

Ich habe einen Weg gefunden. Ich werde nachdenken, ob ich einen besseren Weg finden kann, ohne Patch-Zeug zu affizieren und es in die Subdomain zu integrieren.

Grundsätzlich ich die Steuerung außer Kraft setzen, dies zu tun:

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 

Auch ich Affen Patch auf meinem Benutzermodell dieses Verfahren hatte:

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 

Und schließlich musste ich Affen Patch devise_mail Methoden, die in Devise leben.

Dadurch erschien die @subdomain Variable auf der Mailer-Vorlage. Ich bin nicht glücklich mit dieser Lösung, aber das ist ein Ausgangspunkt. Ich werde über Verbesserungen nachdenken.

+1

Dies kann leichter erhalten, wenn diese zusammen erhalten: https://github.com/plataformatec/devise/pull/2207 –

+0

endlich eine Chance, diese heraus zu überprüfen - und es ist alles arbeiten, stimmen sie ein wenig fühlt unrein, aber ich kann hier wirklich keine einfache, saubere Lösung finden - danke, das ist eine massive Hilfe! –

1

Hier ist eine aktualisierte Antwort, die ich glaube, Ihre Frage gut löst - https://github.com/plataformatec/devise/wiki/How-To:-Send-emails-from-subdomains

In meinem Fall meiner Sub-Domain in meiner Tabelle Konten gespeichert wurde und hier ist das, was ich mich zu erlauben, tat @resource.subdomain in meiner devise Mailer Ansichten zu verwenden

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 
1

Für Gerät 3.1 kann das obige Affepatching im Benutzermodell wie unten sein. Dies ist in dem Fall, dass Ihre Subdomain in einem separaten Modell (sagen Mieter), die keine Beziehung zu anderen Modellen wie Konten, Benutzer, was immer es ist ..(Finden Sie wie 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 
0

Die oben genannten Lösungen werden nicht mit arbeiten, wenn Sie Sub-Domain übergeben möchten und auf „Bestätigungsmail“, weil es ganz in Modell behandelt wird.

Ich habe beide Szenarien (Passwort vergessen und Bestätigungsemail) gelöst, indem ich die Subdomain (oder einen anderen Kontext) mit dem request_store Juwel gespeichert habe und dann meinen eigenen Mailer eingerichtet habe, um diesen Wert zu verwenden.

class DeviseMailer < Devise::Mailer 
    include Devise::Controllers::UrlHelpers 
    default template_path: "devise/mailer" 

    protected 
    def devise_mail(record, action, opts={}) 
    @subdomain = opts.delete(:subdomain) 
    super 
    end 
end 

Das einzige, was benötigt in User Klasse außer Kraft zu setzen ist die send_devise_notification Methode, um die Intel im Anforderungsspeicher gespeichert sind.

class User < ActiveRecord::Base 
    # ... 
    protected 
    def send_devise_notification(notification, *args) 
    opts = args.extract_options! 
    opts[:subdomain] = RequestStore.store[:subdomain] 
    super(notification, *args, opts) 
    end 
end 

Natürlich haben Sie devise konfigurieren Ihr Mailer in config/initializers/devise.rb zu verwenden.

Devise.setup do |config| 
    # ... 
    config.mailer = 'DeviseMailer' 
    # ... 
end