Use both Account and User tables with Devise

后端 未结 3 1935
感动是毒
感动是毒 2020-12-02 08:52

I\'m working with Rails 3.1.0 and Devise 1.4.8, and am new to both.

I want to allow multiple users for an account. The first user to sign up creates the account (pr

相关标签:
3条回答
  • 2020-12-02 09:30

    The best solution would be to use a gem.

    Easy way: milia gem

    Subdomain way: apartment gem

    0 讨论(0)
  • 2020-12-02 09:37

    Couldn't you use something like what's covered in these RailsCasts?:

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

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

    You could setup your models as described in those screencasts, using accepts_nested_attributes_for.

    Then, your views/devise/registrations/new.html.erb form would be for :user like normal, and could include a nested form for :account.

    So something like this within that default form:

    <%= 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 %>
    

    This is sample code from an app I'm working on and I'm using the simple_form gem, so the helpers used in your app may be different, but you'll probably get the idea.

    So when a user is created (when they register), they can also fill in the info that'll be used by the Account model to create their account once they hit the "Sign Up" button.

    And you may want to set an attribute on that user like "admin" too...sounds like this initial user will be the "admin" user for the company, though other users may have access too.

    Hope that helps.

    0 讨论(0)
  • 2020-12-02 09:52

    Finally got this to work using nested attributes. As discussed in the comments on Kenton's answer, that example is reversed. If you want multiple users per account, you have to create the Account first, then the User--even if you only create one user to start with. Then you write your own Accounts controller and view, bypassing the Devise view. The Devise functionality for sending confirmation emails etc. still seems to work if you just create a user directly, i.e. that functionality must be part of automagical stuff in the Devise model; it doesn't require using the Devise controller.

    Excerpts from the relevant files:

    Models in app/models

    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
    

    spec/models/account_spec.rb RSpec model test

    it "should create account AND user through accepts_nested_attributes_for" do
      @AccountWithUser = { :name => "Test Account with User", 
                           :users_attributes => [ { :email => "user@example.com", 
                                                    :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]
    

    controllers/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
    

    views/accounts/new.html.erb view

    <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 is quite picky about plural vs. singular. Since we say Account has_many Users:

    • it expects users_attributes (not user_attributes) in the model and tests
    • it expects an array of hashes for the test, even if there is only one element in the array, hence the [] around the {user attributes}.
    • it expects @account.users.build in the controller. I was not able to get the f.object.build_users syntax to work directly in the view.
    0 讨论(0)
提交回复
热议问题