2011-11-29 50 views
19

我正在使用Rails 3.1.0和Devise 1.4.8,这两者都是新的。同时使用帐户和用户表设计

我想允许多个用户的帐户。注册的第一个用户创建该帐户(可能为他们的公司),那么该用户可以添加更多的用户。用户始终链接到一个帐户。

我有用户和帐户表。缩写模型:

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 

问题是,当第一个用户注册时,如何创建帐户和用户?

  • 我是否需要修改/覆盖设计registrations_controller, 类似的答案here?我无法弄清楚如何 创建帐户,然后将其传递给Devise创建用户。

  • account_id已经在用户模型中。我是否应该将account_name 和account_type添加到用户模型中,并且如果account_id未被传递,则创建新的帐户 记录?在这种情况下,我试图将帐户创建从Devise隐藏起来,但不确定这会起作用,因为我仍然需要在注册页面上提示account_name和account_type。

回答

23

最后得到这个工作使用嵌套属性。正如肯顿答案的评论中所讨论的那样,这个例子是相反的。如果您想为每个帐户创建多个用户,则必须先创建帐户,然后再创建用户 - 即使您只创建一个用户开始。然后你编写自己的账户控制器和视图,绕过设计视图。发送确认电子邮件等的设计功能似乎仍然工作,如果你只是直接创建一个用户,即该功能必须是在Devise 模型中的自动化东西的一部分;它不需要使用Devise控制器。

摘录相关文件:

模式在app /型号

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 

规格/型号/ account_spec.rb 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 

配置/ routes.rb

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

控制器/ 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 

视图/帐户/ new.html.erb视图

<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是相当挑剔复数与单数。既然我们说的帐号的has_many用户:

  • ,预计在模型users_attributes(不user_attributes)和测试
  • 预计的阵列的哈希值进行测试,即使数组中只有一个元素是,因此{{用户属性}周围的[]。
  • 它期望在控制器中使用@ account.users.build。我无法使f.object.build_users语法直接在视图中工作。
+0

是“new.html.erb”设计视图(例如app/views/devise/registrations/new.html.erb)? – y0mbo

+0

@ y0mbo,no,new.html.erb在views/accounts下。我已经添加了解决问题的途径。另见关于“绕过Devise视图”的第一段以及它的工作原理。基本上我使用帐户#创建操作来创建帐户和用户,所以我不需要Devise视图。 –

+0

谢谢!这是一个很好的答案和明确的解决方案。 – y0mbo

1

你不能使用像什么的覆盖在这些RailsCasts?:

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

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

,你可以在那些截屏描述设置您的机型,采用accepts_nested_attributes_for。

然后,您的views/devise/registrations/new.html.erb表单将用于:像普通用户那样的用户,并且可以包含嵌入表单:account。

因此,像这样的是默认窗体中:

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

这是示例代码的应用程序我的工作和我使用simple_form宝石,让您的应用使用的助手可能不同,但你可能会明白。

因此,当用户创建时(他们注册时),他们也可以填写账户模型用来创建账户的信息,一旦他们点击“注册”按钮。

你也可能想为该用户设置一个属性,例如“admin”......听起来这个初始用户将是该公司的“admin”用户,尽管其他用户也可能有权访问该用户。

希望有所帮助。

+0

感谢肯顿,非常有帮助。看起来这仍然需要覆盖Devise registrations_controller中的“create”动作来构建帐户记录。参看“@ survey.questions.build”约5分钟到第一个截屏。或者,也许注册表格应该用于Account,但也可以调用Devise User的'create'动作。 Re。一个管理员属性,你是对的,但我认为我最好在我担心角色之前做好这个工作。 –

+0

马克,很高兴帮助。这听起来像我们正在做类似的事情。我的应用具有类似的功能。在再次查看我的代码时,我最终得到了注册表单所在的帐户#新操作和关联视图。在这种形式下,我使用form_for创建了一个帐户,并在该表单中设置:website和:user,类似于railscast中显示的内容。我的猜测是,当嵌套用户被创建时,它通过设计和它的注册表单,但我真的不是100%确定的。 –

+0

因此,为了澄清,您在帐户模型中拥有'accep_nested_attributes_for:user',并且您的帐户#新视图调用'f.fields_for:user do | user_form |'?换句话说,你首先创建账户,然后用户是下属的。我尝试了另一种方式,但没有成功 - 似乎accept_nested_attributes_for必须位于_parent_表中。一个帐户可以说,“添加我,然后添加一些用户给我”;用户不能说“在添加我之前添加父帐户”。 Devise Google小组的相关讨论:https://groups.google.com/d/topic/plataformatec-devise/7J3XB_RiHYs/discussion。 –