2010-08-23 18 views
215

Dodałem pole do formularza rejestracji opartego na innym modelu, patrz How do I use nested attributes with the devise model, aby uzyskać szczegółowe informacje. Ta część działa dobrze.Zastępowanie kontrolera rejestrowania opracowań

Problem polega na tym, że kiedy zapisuję, nie działa to w akcji tworzenia kontrolera rejestracji, który jest dostarczany przez program z numerem Activerecord::UnknownAttributeError na tym polu (firma).

Zakładam, że muszę zastąpić kontroler rejestracji, czy jest lepszy/łatwiejszy sposób powinienem się do tego zbliżyć?

Odpowiedz

331

W formularzu przekazujesz inne atrybuty, poprzez przypisanie masy, które nie należą do Twojego modelu użytkownika lub modelu zagnieżdżonego?

Jeśli tak, sądzę, że w tym wystąpieniu wyzwalana jest funkcja ActiveRecord :: UnknownAttributeError.

W przeciwnym razie, myślę, że można po prostu stworzyć swój własny kontroler, generując coś takiego:

# 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 

A potem powiedz opracować używać tego kontrolera zamiast domyślnego z:

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

Ale jak sprawić, by wygląd urządzenia wyglądał w widoku urządzenia? Próbuję tego, ale opracowuję metody takie jak "sign_in_and_redirect (resource_name, resource)" szukają widoków dla szablonu. – AnApprentice

+7

Jeśli chcesz dostosować swoje widoki, musisz je najpierw wygenerować, a program wyświetli folder z widokami, zanim załadujesz widoki z klejnotu. W Railsach 3 jest to: 'szyny generują devise: views' oraz Rails 2 (myślę) to:' script/generate devise: views' – theTRON

+2

Powyższy hack nie działa z wersją 1.0.8, która jest wersją działającą na szynach 2. –

32

Uważam, że istnieje lepsze rozwiązanie niż przepisanie RegistrationsController. Zrobiłem dokładnie to samo (po prostu mam organizację zamiast firmy).

Jeśli prawidłowo ustawisz zagnieżdżoną formę, na poziomie modelu i widoku wszystko działa jak czar.

Mój model użytkownika:

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 

moja organizacja Model:

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 

Mój pogląd: 'opracowanie/rejestracje/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

Przeniesienie logiki kompilacji z widoku do modelu byłoby czystsze, zobacz http://stackoverflow.com/questions/3544265#3764837 – meleyal

+0

Generowałem kontrolery devise i teraz mam uruchomione działanie kontrolera, gdy użytkownik kliknie Sign up. Czy istnieje sposób (jak przesłonięcie/jakiś przykładowy kod) Czy mogę użyć Devise do zaszyfrowania hasła i do sprawdzenia backendu hasła i innych pól? i zapisanie go w modelowej bazie danych? –

+0

W jaki sposób można uzyskać dostęp do lokalnej zmiennej 'resource' w widoku zamiast zmiennej instancji klasy' @ resource'? – Chloe

62

Lepszym i bardziej zorganizowany sposób nadpisywania kontrolerów i widoków Devise przy użyciu przestrzeni nazw:

Utwórz następujące foldery:

app/controllers/my_devise 
app/views/my_devise 

Umieść wszystkie sterowniki, które mają zastąpić w app/controllers/my_devise i dodać MyDevise nazw do kontrolera nazwy klas. Registrations przykład:

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

    ... 

    def create 
    # add custom create logic here 
    end 

    ...  

end 

Zmień swoje trasy odpowiednio:

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

skopiować wszystkie wymagane poglądy na język app/views/my_devise z folderu gem opracowywać i wykorzystywać rails generate devise:views, usuń poglądy nie są nadrzędne i zmienić devise folder my_devise.

W ten sposób wszystko będzie uporządkowane w dwóch folderach.

+1

Jest to podejście podobne do podejścia, które stosuję, ale nie wiem, jaką niestandardową logikę umieścić w metodzie "create" w Devise's I overwrote. Mój zmodyfikowany przez szafot kontroler działa wspaniale, ale jak sprawić, by działał z firmą 'zasobów 'Devise? –

+0

@Vincent dziękuję - jeśli chcę zastąpić tylko jedną metodę, czy piszę tylko metodę, którą chcę zastąpić - i czy wszystko inne będzie działało normalnie? Twoja pomoc bardzo doceniła – BKSpurgeon

1

Możesz również utworzyć folder devise w ścieżce kontrolerów i skopiować/wkleić do niego cały kontroler devisera. Nie wymaga to dodatkowej konfiguracji.

Tak więc dla kontrolera rejestracji byłby to app/controllers/devise/registrations_controller.rb, a następnie skopiowałby do niego źródło kodu źródłowego registrations_controller.rb. Możesz pobrać go z github https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb lub możesz go znaleźć w swoim źródle klejnotów lub jeśli użyjesz RubyMine po wpisaniu linii klasy class Devise::RegistrationsController, symbol globu pojawi się po lewej stronie ... kliknij na niego i otworzy się Wymyśl plik kontrolera rejestracji. Następnie skopiuj/wklej.

+9

-1 za promowanie praktyk kopiowania/wklejania, szczególnie w takim kontekście wrażliwym na bezpieczeństwo. Jeśli łatka zostanie zastosowana do Devise ze względów bezpieczeństwa, twój kod nie będzie z niej korzystał, nawet jeśli uaktualnisz wersję gem. Lepsze wykorzystanie rozwiązania @ Vincent i dziedziczenie z 'Devise :: RegistrationsController' –

+0

Plus jeden, ponieważ masz rację, a moja odpowiedź pokazuje, w jaki sposób ludzie mogą znaleźć kod źródłowy. –

0

tworzyć rejestracje kontrolera i zastąpić swoją klasę dziedziczone przez predefiniowanym opracować :: RegistrationsController klasa

# 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 

po ten zestaw tras:

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

Jest w porządku! Gotowe. –

9

Można generować widoki i kontrolery do opracowują dostosowywania.

Zastosowanie

rails g devise:controllers users -c=registrations 

i

rails g devise:views 

będzie kopiować poszczególne kontrolery i widoki z gem do aplikacji.

Następnie powiedzieć router do korzystania z tego kontrolera:

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

Bardzo proste metody Wystarczy przejść do terminala oraz rodzaju następujący

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

Następny używać widoków niestandardowych

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

teraz w pliku route.rb

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

Można również dodać inne kontrolery. Spowoduje to, że będziesz używał kontrolerów w folderze użytkowników i widoków w folderze użytkowników.

Teraz możesz dostosować swoje widoki jako swoje pragnienie i dodać swoją logikę do kontrolerów w folderze kontrolerów/użytkowników. Ciesz się!