2010-08-23 1 views
215

Ho aggiunto un campo al modulo di registrazione basato su un modello diverso, vedere How do I use nested attributes with the devise model per i dettagli sanguinosi. Questa parte sta funzionando bene.Sovrascrivi controller registrazioni elaborazioni

Il problema ora è quando salvi, non è in corso l'azione di creazione del controller di registrazioni che viene fornito da escogitare con un Activerecord::UnknownAttributeError su questo campo (società).

Suppongo di dover eseguire l'override del controller di registrazione o esiste un modo migliore/più semplice per affrontarlo?

risposta

331

Nel modulo si passa ad altri attributi, tramite l'assegnazione di massa che non appartiene al modello dell'utente o uno dei modelli annidati?

In tal caso, credo che ActiveRecord :: UnknownAttributeError venga attivato in questa istanza.

In caso contrario, penso che si può solo creare il proprio controllore, generando qualcosa di simile:

# app/controllers/registrations_controller.rb 
class RegistrationsController < Devise::RegistrationsController 
    def new 
    super 
    end 

    def create 
    # add custom create logic here 
    end 

    def update 
    super 
    end 
end 

e poi dire ideare utilizzare tale controller al posto del default con:

# app/config/routes.rb 
devise_for :users, :controllers => {:registrations => "registrations"} 
+3

Ma come si fa a fare in modo che escogiti gli sguardi nella directory di sviluppo per le viste? Sto provando questo, ma escogitare metodi come "sign_in_and_redirect (resource_name, resource)" stanno cercando nelle viste per il template. – AnApprentice

+7

Se si desidera personalizzare le proprie viste di visualizzazione, è necessario solo prima di generarle e escogitare controllerà la cartella delle visualizzazioni prima di caricare le viste dalla gemma. In Rails 3 è: 'rails generate devise: views' e in Rails 2 (penso) è:' script/generate devise: views' – theTRON

+2

l'hack sopra non funziona con devise 1.0.8 che è la versione che funziona per le rotaie 2. –

32

Credo che ci sia una soluzione migliore di riscrivere il RegistrationsController. Ho fatto esattamente la stessa cosa (ho solo un'organizzazione al posto della compagnia).

Se si imposta correttamente il modulo nidificato, a livello di modello e vista, tutto funziona come un fascino.

mio modello User:

class User < ActiveRecord::Base 
    # Include default devise modules. Others available are: 
    # :token_authenticatable, :confirmable, :lockable and :timeoutable 
    devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable 

    has_many :owned_organizations, :class_name => 'Organization', :foreign_key => :owner_id 

    has_many :organization_memberships 
    has_many :organizations, :through => :organization_memberships 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :username, :owned_organizations_attributes 

    accepts_nested_attributes_for :owned_organizations 
    ... 
end 

mia organizzazione Modello:

class Organization < ActiveRecord::Base 
    belongs_to :owner, :class_name => 'User' 
    has_many :organization_memberships 
    has_many :users, :through => :organization_memberships 
    has_many :contracts 

    attr_accessor :plan_name 

    after_create :set_owner_membership, :set_contract 
    ... 
end 

mio punto di vista: 'ideare/iscrizioni/new.html.erb'

<h2>Sign up</h2> 

<% resource.owned_organizations.build if resource.owned_organizations.empty? %> 
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %> 
    <%= devise_error_messages! %> 

    <p><%= f.label :name %><br /> 
    <%= f.text_field :name %></p> 

    <p><%= f.label :email %><br /> 
    <%= f.text_field :email %></p> 

    <p><%= f.label :username %><br /> 
    <%= f.text_field :username %></p> 

    <p><%= f.label :password %><br /> 
    <%= f.password_field :password %></p> 

    <p><%= f.label :password_confirmation %><br /> 
    <%= f.password_field :password_confirmation %></p> 

    <%= f.fields_for :owned_organizations do |organization_form| %> 

    <p><%= organization_form.label :name %><br /> 
     <%= organization_form.text_field :name %></p> 

    <p><%= organization_form.label :subdomain %><br /> 
     <%= organization_form.text_field :subdomain %></p> 

    <%= organization_form.hidden_field :plan_name, :value => params[:plan] %> 

    <% end %> 

    <p><%= f.submit "Sign up" %></p> 
<% end %> 

<%= render :partial => "devise/shared/links" %> 
+2

Spostare la logica di creazione dalla vista al modello sarebbe più pulito, vedere http://stackoverflow.com/questions/3544265#3764837 – meleyal

+0

Ho generato i controller di elaborazione e ora ho creato un'azione di controllo del controller quando l'utente fa clic su Iscriviti. C'è un modo (come sovrascrivere/qualche codice di esempio) Posso usare Devise per crittografare la password e fare i controlli di back-end della password e di altri campi? e salvandolo nel database del modello? –

+0

Come si può accedere alla variabile locale 'resource' nella vista anziché a una variabile di istanza di classe' @ resource'? – Chloe

62

una migliore e modo più organizzato di sovrascrivere controllori e viste Devise utilizzando gli spazi dei nomi:

creare le seguenti cartelle:

app/controllers/my_devise 
app/views/my_devise 

Metti tutti i controller che si desidera sovrascrivere in app/controllers/my_devise e aggiungere MyDevise namespace al controller nomi di classe. Registrations esempio:

# app/controllers/my_devise/registrations_controller.rb 
class MyDevise::RegistrationsController < Devise::RegistrationsController 

    ... 

    def create 
    # add custom create logic here 
    end 

    ...  

end 

Cambia i tuoi percorsi di conseguenza:

devise_for :users, 
      :controllers => { 
      :registrations => 'my_devise/registrations', 
      # ... 
      } 

Copia tutte le viste necessarie in app/views/my_devise dalla cartella gemma Devise o utilizzare rails generate devise:views, eliminare i punti di vista non sono imperativi e rinominare la cartella devise a my_devise.

In questo modo avrete tutto perfettamente organizzato in due cartelle.

+1

Questo è simile all'approccio che sto prendendo, ma non so quale logica personalizzata inserire nel metodo 'create' di Devise's ho sovrascritto. Il mio controller creato da scaffold che ho modificato funziona alla grande, ma come si fa a farlo funzionare con il business 'resource' di Devise? –

+0

@Vincent grazie - se voglio scavalcare un solo metodo, scrivo solo il metodo che voglio sovrascrivere - e tutto il resto funzionerà normalmente? La tua assistenza è stata molto apprezzata – BKSpurgeon

1

È anche possibile creare la cartella devise nel percorso del controller e copiare/incollare l'intero controller di dispositivo in esso. Ciò non richiede alcuna configurazione aggiuntiva.

Quindi, per il controller delle registrazioni, sarebbe app/controllers/devise/registrations_controller.rb e quindi copiare il codice sorgente registrations_controller.rb. Puoi ottenerlo da github https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb, o puoi rintracciarlo nella tua fonte gemma, o se usi RubyMine quando digiti nella riga di classe class Devise::RegistrationsController un simbolo simile a un globo appare a sinistra ... cliccaci sopra e si apre il Crea il file del controller di registrazione per te. Quindi copia/incolla.

+9

-1 per promuovere le pratiche di copia/incolla, specialmente in un contesto sensibile alla sicurezza. Se viene applicata una patch a Devise per motivi di sicurezza, il tuo codice non ne trarrà vantaggio anche se aggiorni la versione gem. Meglio usare la soluzione di Vincent ed ereditare da 'Devise :: RegistrationsController' –

+0

Più uno perché hai ragione e la mia risposta mostra come le persone possono trovare il codice sorgente. –

0

creare le registrazioni del controller e sovrascrivere la sua classe ereditata da Devise predefinito :: classe RegistrationsController

# app/controllers/registrations_controller.rb 
class RegistrationsController < Devise::RegistrationsController 
    def new 
    super 
    end 

    def create 
    # add custom create logic here 
    end 

    def update 
    super 
    end 
end 

dopo questa itinerari dell'insieme a:

# app/config/routes.rb 
devise_for :users, :controllers => {:registrations => "registrations"} 
+2

Va bene! Fatto. –

9

È possibile generare viste e controller per la personalizzazione escogitare.

Usa

rails g devise:controllers users -c=registrations 

e

rails g devise:views 

Sarà copiare particolari controller e viste dal gioiello alla vostra applicazione.

Avanti, dire al router per utilizzare questo controller:

devise_for :users, :controllers => {:registrations => "users/registrations"} 
7

metodi molto semplici Basta andare al terminale e il tipo seguente

rails g devise:controllers users //This will create devise controllers in controllers/users folder 

Avanti per utilizzare le visualizzazioni personalizzate

rails g devise:views users //This will create devise views in views/users folder 

ora nel tuo percorso.rb file

devise_for :users, controllers: { 
      :sessions => "users/sessions", 
      :registrations => "users/registrations" } 

È possibile aggiungere anche altri controller. Questo renderà necessario utilizzare i controller nella cartella e nelle viste degli utenti nella cartella degli utenti.

Ora è possibile personalizzare le visualizzazioni come desiderato e aggiungere la logica ai controller nella cartella dei controller/utenti. Divertiti!