Remplacer le contrôleur des enregistrements de devise

236

J'ai ajouté un champ au formulaire d'inscription qui est basé sur un modèle différent, voir Comment utiliser les attributs imbriqués avec le modèle de devise pour les détails sanglants. Cette partie fonctionne bien.

Le problème est maintenant que lorsque j'enregistre, il échoue dans l'action de création du contrôleur des inscriptions qui est fournie par devise avec un Activerecord::UnknownAttributeErrorsur ce champ (entreprise).

Je suppose que j'ai besoin de remplacer le contrôleur des enregistrements, ou y a-t-il un moyen meilleur / plus facile de l'aborder?

Craig McGuff
la source
1
J'ai en fait écrit un article de blog entier sur ce jacopretorius.net/2014/03/…
Jaco Pretorius

Réponses:

354

Dans votre formulaire, transmettez-vous d'autres attributs via une affectation en masse qui n'appartiennent pas à votre modèle utilisateur ou à l'un des modèles imbriqués?

Si c'est le cas, je crois que l'ActiveRecord :: UnknownAttributeError est déclenchée dans cette instance.

Sinon, je pense que vous pouvez simplement créer votre propre contrôleur, en générant quelque chose comme ceci:

# 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 

Et puis dites à devise d'utiliser ce contrôleur au lieu de la valeur par défaut avec:

# app/config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
theTRON
la source
3
Mais comment vous assurez-vous que l'apparence de l'appareil dans le répertoire de l'appareil pour les vues? J'essaye ceci mais conçois des méthodes comme "sign_in_and_redirect (nom_ressource, ressource)" cherchent dans les vues pour le modèle.
AnApprentice
7
Si vous souhaitez personnaliser vos vues de conception, il vous suffit de les générer d'abord et la conception vérifiera votre dossier de vues avant de charger les vues depuis la gemme. Dans Rails 3 c'est: rails generate devise:viewset dans Rails 2 (je pense) c'est:script/generate devise:views
theTRON
2
le hack ci-dessus ne fonctionne pas avec le devise 1.0.8 qui est la version qui fonctionne pour les rails 2.
William Yeung
18
Si vous remplacez un contrôleur Devise comme celui-ci, assurez-vous de copier toutes les vues de l'application / vues / concevoir / enregistrements dans l'application / vues / enregistrements / (changer pour le contrôleur que vous remplacez).
Jamie Cobbett
31
Sinon , vous pouvez laisser votre point de vue CONCEVOIR où ils sont et ajouter paths.app.views << "app/views/devise"dans votre config/application.rb.
theTRON
66

Une manière meilleure et plus organisée de remplacer les contrôleurs et les vues Devise à l'aide des espaces de noms:

Créez les dossiers suivants:

app/controllers/my_devise
app/views/my_devise

Placez tous les contrôleurs que vous souhaitez remplacer dans app / controllers / my_devise et ajoutez un MyDeviseespace de noms aux noms de classe de contrôleur. Registrationsexemple:

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

  ...

  def create
    # add custom create logic here
  end

  ...    

end 

Modifiez vos itinéraires en conséquence:

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

Copiez toutes les vues requises dans le app/views/my_devisedossier Devise gem ou utilisez rails generate devise:views, supprimez les vues que vous ne remplacez pas et renommez le devisedossier my_devise.

De cette façon, vous aurez tout bien organisé dans deux dossiers.

Vincent
la source
1
Ceci est similaire à l'approche que je prends, mais je ne sais pas quelle logique personnalisée mettre dans la createméthode de Devise que j'ai écrasé. Mon contrôleur créé par échafaudage que j'ai modifié fonctionne très bien, mais comment le faire fonctionner avec les resourceactivités de Devise ?
Kyle Carlson
@Vincent merci - si je veux remplacer une seule méthode, dois-je écrire uniquement la méthode que je veux remplacer - et tout le reste fonctionnera-t-il normalement? Votre aide très appréciée
BKSpurgeon
MyDevise::RegistrationsController < Devise::RegistrationsControllercrée une erreur de dépendance circulaire. Est-ce que je fais quelque chose de mal?
ianrandmckenzie
34

Je pense qu'il y a une meilleure solution que de réécrire le RegistrationsController. J'ai fait exactement la même chose (j'ai juste Organisation au lieu de Compagnie).

Si vous définissez correctement votre formulaire imbriqué, au niveau du modèle et de la vue, tout fonctionne comme un charme.

Mon modèle d'utilisateur:

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

Mon modèle d'organisation:

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

Mon point de vue: '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
la source
3
Déplacer la logique de construction de la vue vers le modèle serait plus propre, voir stackoverflow.com/questions/3544265#3764837
meleyal
J'ai généré les contrôleurs de devise et maintenant l'action de contrôleur est déclenchée lorsque l'utilisateur clique sur S'inscrire. Existe-t-il un moyen (comme le remplacement / un exemple de code) que je peux utiliser Devise pour crypter le mot de passe et faire des vérifications backend du mot de passe et d'autres champs? et l'enregistrer dans la base de données de modèles?
HP
Comment pouvez-vous accéder à la variable locale resourcedans la vue au lieu d'une variable d'instance de classe @resource?
Chloé du
12

Vous pouvez générer des vues et des contrôleurs pour personnaliser la conception.

Utilisation

rails g devise:controllers users -c=registrations

et

rails g devise:views 

Il copiera des contrôleurs et des vues particuliers de gem dans votre application.

Ensuite, dites au routeur d'utiliser ce contrôleur:

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

Méthodes très simples Il suffit d'aller dans le terminal et le type suivant

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

Suivant pour utiliser des vues personnalisées

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

maintenant dans votre fichier route.rb

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

Vous pouvez également ajouter d'autres contrôleurs. Cela permettra d'utiliser des contrôleurs dans le dossier des utilisateurs et des vues dans le dossier des utilisateurs.

Vous pouvez maintenant personnaliser vos vues selon vos désirs et ajouter votre logique aux contrôleurs dans le dossier contrôleurs / utilisateurs. Prendre plaisir !

Pradeep Sapkota
la source