【问题标题】:Use both Account and User tables with Devise将 Account 和 User 表与 Devise 一起使用
【发布时间】:2017-01-22 19:21:10
【问题描述】:

我正在使用 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

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

  • 我是否需要修改/覆盖设计注册控制器, 类似于答案here?我不知道怎么做 创建帐户,然后将其传递给 Devise 以创建用户。

  • account_id 已经在用户模型中。我应该添加 account_name 和 account_type 到 User 模型,并创建一个新的 Account 记录account_id是否传入?在这种情况下,我试图对 Devise 隐藏帐户创建,但不确定这是否可行,因为我仍需要在注册页面上提示输入 account_name 和 account_type。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 authentication devise


    【解决方案1】:

    终于使用嵌套属性让它工作了。正如在肯顿回答的 cmets 中所讨论的那样,这个例子是相反的。如果您希望每个帐户有多个用户,则必须先创建帐户,然后再创建用户——即使您一开始只创建一个用户。然后你编写自己的 Accounts 控制器和视图,绕过 Devise 视图。如果您只是直接创建用户,则用于发送确认电子邮件等的设计功能似乎仍然有效,即该功能必须是 Devise model 中自动功能的一部分;它不需要使用设计控制器。

    相关文件的摘录:

    模型在应用/模型中

    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 模型测试

    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 视图

    <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)
    • 它需要一个 数组 哈希用于测试,即使数组中只有一个元素,因此 {user attributes} 周围有 []。
    • 它需要控制器中的@account.users.build。我无法让 f.object.build_users 语法直接在视图中工作。

    【讨论】:

    • “new.html.erb”是设计视图(例如 app/views/devise/registrations/new.html.erb)吗?
    • @y0mbo,不,new.html.erb 在视图/帐户下。我已经添加了答案的路径以进行澄清。另请参阅关于“绕过设计视图”及其工作原理的第一段。基本上我使用 accounts#create 操作来创建帐户和用户,所以我不需要设计视图。
    • 很好的解决方案!这正是我一直在寻找的。需要注意的一点是,如果帐户 has_one 用户,例如,在帐户控制器的新操作中它将是 @account.build_user。此外,您最后提到的部分将是单数,没有数组语法。
    • 真棒答案!除了创建帐户(和用户)时,我已经完成了所有工作,它似乎在重定向之前没有对用户进行身份验证。关于如何将这种行为置于其中的任何建议?
    • 对不起@Eric,我已经离开这个有一段时间了,所以很难记住。我以为 Devise 发送了一封电子邮件,要求用户在允许他们登录之前确认收到。我记得当管理员创建其他用户时必须做一些事情来禁止该电子邮件。
    【解决方案2】:

    您不能使用这些 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 表单将像正常一样用于 :user,并且可以包含用于 :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 gem,因此您的应用程序中使用的帮助程序可能不同,但您可能会明白。

    因此,在创建用户时(当他们注册时),他们还可以填写信息,一旦他们点击“注册”按钮,Account 模型将使用这些信息来创建他们的帐户。

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

    希望对您有所帮助。

    【讨论】:

    • 感谢肯顿,非常有帮助。看起来这仍然需要覆盖设计注册控制器中的create 操作才能构建帐户记录。参照。 @survey.questions.build 第一个截屏视频大约 5 分钟。或者注册表应该是帐户,但也可以调用设计用户create 操作。回覆。一个管理员属性,你是对的,但我想我最好在我担心角色之前让这个工作正常。
    • 马克,很高兴有帮助。听起来我们正在做类似的事情。我的应用程序具有类似的功能。再次查看我的代码时,我最终得到了一个 account#new 操作和注册表单所在的关联视图。在该表单中,我使用 form_for 创建了一个帐户,并在该表单中设置了 :website 和 :user 的设置,类似于 railscast 中显示的内容。我的猜测是,当创建嵌套用户时,它会通过设计和注册表单,但老实说,我对此不是 100% 确定的。
    • 所以澄清一下,您在 Account 模型中有 accepts_nested_attributes_for :user,而您的 account#new 视图调用 f.fields_for :user do |user_form|?换句话说,您首先创建帐户,然后用户是从属的。我以相反的方式尝试了它但没有成功——似乎accepts_nested_attributes_for 必须在 parent 表上。一个账号可以说,“加我,然后给我加一些用户”;用户不能说“在添加我之前添加父帐户”。 Devise Google 群中的相关讨论:groups.google.com/d/topic/plataformatec-devise/7J3XB_RiHYs/…
    • 是的,没错。您可能还需要在您的帐户模型中添加“attr_accessor :user_attributes”...以便可以在表单中设置用户属性。很容易忘记“_attributes”部分,因为您通常不必拥有它。有关详细信息,请参阅以下页面上描述接受嵌套属性的 cmets:apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/…
    • 感谢您将我指向嵌套属性解决方案。我希望将其标记为“有用”并发布更完整的示例作为答案是公平的。
    【解决方案3】:

    最好的解决方案是使用 gem。

    简单方法:milia gem

    子域方式:apartment gem

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多