Überschreiben Sie den Registrierungscontroller

236

Ich habe dem Anmeldeformular ein Feld hinzugefügt, das auf einem anderen Modell basiert. Weitere Informationen finden Sie unter Wie verwende ich verschachtelte Attribute mit dem Gerätemodell für die wichtigsten Details. Dieser Teil funktioniert gut.

Das Problem ist jetzt, wenn ich speichere, dass die Erstellungsaktion des Registrierungscontrollers fehlschlägt, der von devise mit einem Activerecord::UnknownAttributeErrorin diesem Feld (Unternehmen) bereitgestellten Feld geliefert wird .

Ich gehe davon aus, dass ich den Registrierungs-Controller überschreiben muss, oder gibt es eine bessere / einfachere Möglichkeit, dies zu erreichen?

Craig McGuff
quelle
1
Ich schrieb tatsächlich einen ganzen Blog-Beitrag auf diesem jacopretorius.net/2014/03/…
Jaco Pretorius

Antworten:

354

Übergeben Sie in Ihrem Formular andere Attribute über eine Massenzuweisung, die nicht zu Ihrem Benutzermodell gehört, oder eines der verschachtelten Modelle?

Wenn ja, glaube ich, dass der ActiveRecord :: UnknownAttributeError in dieser Instanz ausgelöst wird.

Ansonsten können Sie einfach Ihren eigenen Controller erstellen, indem Sie Folgendes generieren:

# 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 

Und dann sagen Sie devise, dass dieser Controller anstelle des Standardcontrollers verwendet werden soll mit:

# app/config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
theTRON
quelle
3
Aber wie stellen Sie sicher, dass das Gerät im Entwurfsverzeichnis für die Ansichten aussieht? Ich versuche dies, aber Methoden wie "sign_in_and_redirect (Ressourcenname, Ressource)" suchen in Ansichten nach der Vorlage.
AnApprentice
7
Wenn Sie Ihre Entwurfsansichten anpassen möchten, müssen Sie sie nur zuerst generieren, und das Gerät überprüft Ihren Ansichtsordner, bevor Sie die Ansichten aus dem Edelstein laden. In Rails 3 ist es: rails generate devise:viewsund in Rails 2 (glaube ich) ist es:script/generate devise:views
theTRON
2
Der obige Hack funktioniert nicht mit Devise 1.0.8, der Version, die für Rails 2 funktioniert.
William Yeung
18
Wenn Sie einen Devise-Controller wie diesen überschreiben, stellen Sie sicher, dass Sie alle Ansichten von app / views / devise / registrations in app / views / registrations / kopieren (ändern Sie den Controller, den Sie überschreiben).
Jamie Cobbett
31
Alternativ können Sie Ihre Entwurfsansichten dort belassen, wo sie sich befinden, und paths.app.views << "app/views/devise"Ihre hinzufügen config/application.rb.
TheTRON
66

Eine bessere und besser organisierte Methode zum Überschreiben von Devise-Controllern und -Ansichten mithilfe von Namespaces:

Erstellen Sie die folgenden Ordner:

app/controllers/my_devise
app/views/my_devise

Fügen Sie alle Controller, die Sie überschreiben möchten, in app / controller / my_devise ein und fügen Sie den MyDeviseNamen der Controller-Klassen einen Namespace hinzu . RegistrationsBeispiel:

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

  ...

  def create
    # add custom create logic here
  end

  ...    

end 

Ändern Sie Ihre Routen entsprechend:

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

Kopieren Sie alle erforderlichen Ansichten app/views/my_deviseaus dem Devise Gem-Ordner oder verwenden Sie rails generate devise:views, löschen Sie die Ansichten, die Sie nicht überschreiben, und benennen Sie den deviseOrdner in um my_devise.

Auf diese Weise haben Sie alles ordentlich in zwei Ordnern organisiert.

Vincent
quelle
1
Dies ähnelt dem Ansatz, den ich verfolge, aber ich weiß nicht, welche benutzerdefinierte Logik in die createvon mir überschriebene Methode von Devise eingefügt werden soll. Mein von einem Gerüst erstellter Controller, den ich geändert habe, funktioniert hervorragend, aber wie funktioniert er mit dem resourceGeschäft von Devise ?
Kyle Carlson
@ Vincent danke - wenn ich nur eine Methode überschreiben möchte, schreibe ich nur die Methode, die ich überschreiben möchte - und funktioniert alles andere wie gewohnt? Ihre Hilfe sehr geschätzt
BKSpurgeon
MyDevise::RegistrationsController < Devise::RegistrationsControllererzeugt einen zirkulären Abhängigkeitsfehler. Mache ich etwas falsch?
Ianrandmckenzie
34

Ich glaube, es gibt eine bessere Lösung, als den RegistrationsController neu zu schreiben. Ich habe genau das Gleiche getan (ich habe nur Organisation statt Firma).

Wenn Sie Ihr verschachteltes Formular auf Modell- und Ansichtsebene richtig einstellen, funktioniert alles wie ein Zauber.

Mein Benutzermodell:

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

Mein Organisationsmodell:

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

Meine Ansicht: 'devise / registrations / 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" %>
thb
quelle
3
Das Verschieben der Erstellungslogik von der Ansicht zum Modell wäre sauberer, siehe stackoverflow.com/questions/3544265#3764837
meleyal
Ich habe die Geräte-Controller generiert und jetzt die Controller-Aktion erstellen lassen, wenn der Benutzer auf Anmelden klickt. Gibt es eine Möglichkeit (z. B. Überschreiben / Beispielcode), mit Devise das Kennwort zu verschlüsseln und das Kennwort und andere Felder im Backend zu überprüfen? und in der Modelldatenbank speichern?
HP
Wie können Sie auf die lokale Variable resourcein der Ansicht anstatt auf eine Klasseninstanzvariable zugreifen @resource?
Chloe
11

Sie können Ansichten und Controller für die Anpassung von Geräten generieren.

Verwenden

rails g devise:controllers users -c=registrations

und

rails g devise:views 

Es werden bestimmte Controller und Ansichten von gem in Ihre Anwendung kopiert.

Weisen Sie den Router als Nächstes an, diesen Controller zu verwenden:

devise_for :users, :controllers => {:registrations => "users/registrations"}
user1201917
quelle
11

Sehr einfache Methoden Gehen Sie einfach zum Terminal und geben Sie den folgenden Typ ein

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

Weiter, um benutzerdefinierte Ansichten zu verwenden

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

jetzt in Ihrer route.rb Datei

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

Sie können auch andere Controller hinzufügen. Auf diese Weise können Controller im Benutzerordner und Ansichten im Benutzerordner verwendet werden.

Jetzt können Sie Ihre Ansichten nach Ihren Wünschen anpassen und Ihre Logik den Controllern im Ordner "Controller / Benutzer" hinzufügen. Genießen !

Pradeep Sapkota
quelle