2011-11-29 11 views
19

Estoy trabajando con Rails 3.1.0 y Devise 1.4.8, y soy nuevo en ambos.Use las tablas de cuenta y de usuario con Devise

Quiero permitir varios usuarios para una cuenta. El primer usuario que se registra crea la cuenta (probablemente para su empresa), luego ese usuario puede agregar más usuarios. Un usuario siempre está vinculado a exactamente una cuenta.

Tengo tablas de Usuarios y Cuentas. modelos abreviados:

class User < ActiveRecord::Base 
    belongs_to :account 
    devise :database_authenticatable, :registerable, 
    :recoverable, :rememberable, :trackable, :validatable, 
    :confirmable, :lockable, :timeoutable 
    attr_accessible :email, :password, :password_confirmation, :remember_me 
end 

class Account < ActiveRecord::Base 
    has_many :users, :dependent => :destroy 
    attr_accessible :name, :account_type 
end 

La pregunta es, cuando los signos primera usuario se registra, ¿Cómo se crea la cuenta y del usuario?

  • ¿Es necesario modificar/anular el registrations_controller Diseñar, algo así como la respuesta here? No pude averiguar cómo crear la Cuenta y luego pasarla a Diseñar para crear el Usuario.

  • account_id ya se encuentra en el modelo de Usuario. ¿Debo agregar account_name y account_type al modelo de usuario y crear un nuevo registro de cuenta si account_id no se transfiere? En este caso, estoy tratando de ocultar la creación de la cuenta de Devise, pero no estoy seguro de que funcione, ya que aún necesito solicitar el nombre de la cuenta y el tipo de cuenta en la página de registro.

Respuesta

23

Finalmente, esto funcionó utilizando atributos anidados. Como se discutió en los comentarios sobre la respuesta de Kenton, ese ejemplo se invierte. Si desea varios usuarios por cuenta, primero debe crear la Cuenta y luego el Usuario, incluso si solo crea un usuario para comenzar. Luego, escribe su propio controlador y vista de Cuentas, sin pasar por la vista Devise. La funcionalidad Diseñar para enviar correos electrónicos de confirmación, etc. parece funcionar aún si solo crea un usuario directamente, es deciresa funcionalidad debe ser parte de las cosas automági- cas en el modelo ; no requiere el uso del controlador Devise.

extractos de los archivos relevantes:

Modelos en app/modelos

class Account < ActiveRecord::Base 
    has_many :users, :inverse_of => :account, :dependent => :destroy 
    accepts_nested_attributes_for :users 
    attr_accessible :name, :users_attributes 
end 

class User < ActiveRecord::Base 
    belongs_to :account, :inverse_of => :users 
    validates :account, :presence => true 
    devise :database_authenticatable, :registerable, 
     :recoverable, :rememberable, :trackable, :validatable, 
     :confirmable, :lockable, :timeoutable 
    attr_accessible :email, :password, :password_confirmation, :remember_me 
end 

especificación/modelos/account_spec.rb prueba de modelo RSpec

it "should create account AND user through accepts_nested_attributes_for" do 
    @AccountWithUser = { :name => "Test Account with User", 
         :users_attributes => [ { :email => "[email protected]", 
               :password => "testpass", 
               :password_confirmation => "testpass" } ] } 
    au = Account.create!(@AccountWithUser) 
    au.id.should_not be_nil 
    au.users[0].id.should_not be_nil 
    au.users[0].account.should == au 
    au.users[0].account_id.should == au.id 
end 

config/routes.rb

resources :accounts, :only => [:index, :new, :create, :destroy] 

controladores/accounts_controller.rb

class AccountsController < ApplicationController 

    def new 
    @account = Account.new 
    @account.users.build # build a blank user or the child form won't display 
    end 

    def create 
    @account = Account.new(params[:account]) 
    if @account.save 
     flash[:success] = "Account created" 
     redirect_to accounts_path 
    else 
     render 'new' 
    end 
    end 

end 

vistas/cuentas/new.html.erb vista

<h2>Create Account</h2> 

<%= form_for(@account) do |f| %> 
    <%= render 'shared/error_messages', :object => f.object %> 
    <div class="field"> 
    <%= f.label :name %><br /> 
    <%= f.text_field :name %> 
    </div> 

    <%= f.fields_for :users do |user_form| %> 
    <div class="field"><%= user_form.label :email %><br /> 
    <%= user_form.email_field :email %></div> 
    <div class="field"><%= user_form.label :password %><br /> 
    <%= user_form.password_field :password %></div> 
    <div class="field"><%= user_form.label :password_confirmation %><br /> 
    <%= user_form.password_field :password_confirmation %></div> 
    <% end %> 

    <div class="actions"> 
    <%= f.submit "Create account" %> 
    </div> 
<% end %> 

Rails es bastante exigente con plural vs. singular. Como nos dicen los usuarios has_many cuenta:

  • que espera users_attributes (no user_attributes) en el modelo y las pruebas
  • se espera una matriz de hashes para la prueba, incluso si sólo hay un elemento de la matriz , de ahí el [] alrededor de los {atributos del usuario}.
  • espera @ account.users.build en el controlador. No pude obtener la sintaxis f.object.build_users para que funcione directamente en la vista.
+0

es "new.html.erb" una vista de diseño (por ejemplo, app/views/devise/registrations/new.html.erb)? – y0mbo

+0

@ y0mbo, no, new.html.erb está en vistas/cuentas. He agregado caminos a la respuesta para aclararme. Ver también el primer párrafo sobre "pasar por alto la vista de Devise" y cómo funciona eso. Básicamente estoy usando las cuentas # create action para crear tanto una cuenta como un usuario, por lo que no necesito la vista Devise. –

+0

Gracias! Esta es una gran respuesta y una solución clara. – y0mbo

1

no podría usar algo así como lo que está cubierto en estos Railscasts ?:

http://railscasts.com/episodes/196-nested-model-form-part-1

http://railscasts.com/episodes/197-nested-model-form-part-2

usted puede configurar sus modelos como se describe en las grabaciones de pantalla, usando accepts_nested_attributes_for.

A continuación, su vista/idear/registros/new.html.erb formulario sería para: usuario como normal, y podría incluir un formulario anidado para: cuenta.

Así que algo como esto dentro de ese formulario predeterminado:

<%= f.fields_for :account do |account_form| %> 
<div> 
    <p> 
    <%= account_form.label :name, "Account Name", :class => "label" %> 
    <%= account_form.text_field :name, :class => "text_field" %> 
    <span class="description">(e.g., enter your account name here)</span> 
    </p> 
</div> 

<div> 
    <p> 
    <%= account_form.label :company, "Company Name", :class => "label" %> 
    <%= account_form.text_field :company, :class => "text_field" %> 
    </p> 
</div> 
<% end %> 

Esto es código de ejemplo de una aplicación que estoy trabajando y estoy usando la gema simple_form, por lo que los ayudantes utilizados en su aplicación puede ser diferente, pero probablemente tendrás la idea.

De modo que cuando se crea un usuario (cuando se registran), también pueden completar la información que usará el modelo de Cuenta para crear su cuenta una vez que presionen el botón "Registrarse".

Y es posible que desee establecer un atributo en ese usuario como "admin" también ... parece que este usuario inicial será el usuario "administrador" de la empresa, aunque otros usuarios también pueden tener acceso.

Espero que ayude.

+0

Gracias Kenton, muy útil. Parece que esto aún requerirá anular la acción 'create' en el Devise registration_controller para construir el registro de la cuenta. Cf. '@ survey.questions.build' unos 5 minutos después del primer screencast. O tal vez el formulario de registro debe ser para Cuenta, pero también debe llamar a la acción 'crear' del Usuario de Devise. Re. un atributo de administrador, tienes razón, pero pensé que sería mejor hacerlo funcionar antes de preocuparme por los roles. –

+0

Mark, me alegro de que haya ayudado. Parece que estamos haciendo algo similar. Mi aplicación tiene una funcionalidad similar. Al mirar mi código nuevamente, terminé teniendo una cuenta # acción nueva y una vista asociada donde está el formulario de registro. En esa forma, creo una cuenta usando form_for y dentro de ese formulario, tengo las configuraciones para: sitio web y: usuario, similar a lo que se muestra en la transmisión de rieles. Supongo que cuando se crea ese usuario anidado, pasa por el diseño y es el formulario de registro, pero honestamente no estoy 100% seguro de eso. –

+0

Para aclarar, tiene 'accept_nested_attributes_for: user' en el modelo de Cuenta, y su cuenta # nueva vista llama' f.fields_for: user do | user_form | '? En otras palabras, primero está creando la cuenta, luego el usuario está subordinado. Lo intenté al revés sin éxito, parece que accept_nested_attributes_for debe estar en la tabla _parent_.Una cuenta puede decir "agrégame y luego agrégame algunos usuarios"; un usuario no puede decir "agregar una cuenta principal antes de agregarme". Discusión relevante en el grupo Devise Google: https://groups.google.com/d/topic/plataformatec-devise/7J3XB_RiHYs/discussion. –

Cuestiones relacionadas