Как разрешить пользователю регистрировать учетную запись и идентификатор пользователя одновременно с rails 4 и devise

#ruby-on-rails-4 #devise #nested-forms #multi-tenant

#ruby-on-rails-4 #разработка #вложенные формы #многопользовательский

Вопрос:

Я пытаюсь создать многопользовательское приложение, используя rails 4 и devise. Дизайн, который я пытаюсь, заключается в том, что учетная запись имеет одного владельца (основного пользователя) и имеет много пользователей. У меня есть учетная запись, добавляемая вместе с вложенной формой, добавляющей пользователя. Я не уверен, есть ли у меня проблемы со схемой, которую я пытаюсь заполнить, или я пропускаю шаг, который позволил бы мне добавить учетную запись и пользователя одновременно, при этом запись учетной записи заполняется идентификатором owner_id (основного пользователя), а пользователь заполняется идентификатором account_id .

 class Account < ActiveRecord::Base
  cattr_accessor :current_id
  has_many :users
  has_one :owner, class_name: 'User'

  validates :owner, presence: true

  accepts_nested_attributes_for :owner
end

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  belongs_to :account
end

class AccountsController < ApplicationController
  def new
    @account = Account.new
    @account.build_owner
  end

  def create
    @account = Account.new(account_params)
    if @account.save
      redirect_to root_path, notice: 'Successfully Created Account!'
    else
      render action: 'new'
    end
  end

  private
    def account_params
      params.require(:account).permit(:subdomain, owner_attributes: [:email, :password, :password_confirmation])
    end
end
  

Просмотры / Учетные записи /new.html.erb

 <div class="col-md-6 col-md-offset-3 panel panel-default">
  <div class="panel-body">

    <h2>Create an Account</h2>

    <%= form_for @account do |f| %>
      <%= f.fields_for :owner do |o| %>
        <%= form_group_for o, :email do %>
          <%= o.text_field :email, class: 'form-control' %>
        <% end %>
        <%= form_group_for o, :password do %>
          <%= o.password_field :password, class: 'form-control' %>
        <% end %>
        <%= form_group_for o, :password_confirmation do %>
          <%= o.password_field :password_confirmation, class: 'form-control' %>
        <% end %>
      <% end %>

      <%= form_group_for f, :name, opts= {:label => "Company Name"} do %>
          <%= f.text_field :name, class: 'form-control' %>
      <% end %>

      <%= f.submit class: 'btn btn-primary' %>
    <% end %>
  </div>
</div>
  

Приложение / Помощник / Form_Helper (просмотр этого вызова)

 module FormHelper
  def errors_for(form, field)
    content_tag(:p, form.object.errors[field].try(:first), class: 'help-block')
  end

  def form_group_for(form, field, opts={}, amp;block)

    if opts.has_key?(:label)
       label = opts.fetch(:label)
    else
     label = field.to_s
    end

    has_errors = form.object.errors[field].present?

    content_tag :div, class: "form-group #{'has-error' if has_errors}" do
      concat form.label(label, class: 'control-label')
      concat capture(amp;block)
      concat errors_for(form, field)
    end
  end
end
  

DB / schema.rb

 ActiveRecord::Schema.define(version: 20140629124546) do

  create_table "accounts", force: true do |t|
    t.string   "name"
    t.integer  "owner_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "clients", force: true do |t|
    t.string   "name",       null: false
    t.text     "address"
    t.integer  "account_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "clients", ["account_id"], name: "index_clients_on_account_id"

  create_table "users", force: true do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "account_id"
  end

  add_index "users", ["account_id"], name: "index_users_on_account_id"
  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

end
  

В настоящее время дизайн создает как учетные, так и пользовательские записи. Запись пользователя заполняется идентификатором account_id, но идентификатор account_id не заполняется идентификатором owner_id (user_id).

Ответ №1:

Вероятно, это связано с вашими ассоциациями, которые в настоящее время являются неполными и немного неточными.

Если атрибут модели содержит внешний ключ, например атрибут owner_id в вашей модели учетной записи, то он принадлежит той модели, на которую он ссылается. Думайте об этом как о бренде крупного рогатого скота. Если у вас есть идентификаторы других моделей, вы принадлежите к этим моделям. У вас есть has_one, где вам нужен belongs_to.

Вам также необходимо будет настроить обратную ассоциацию, которой в настоящее время не хватает в вашей пользовательской модели.

Предполагая, что вы на самом деле хотите, чтобы пользователь был связан только с одной учетной записью (в отличие от пользователя, имеющего более одной учетной записи), вы можете изменить свои ассоциации следующим образом:

 #models/account.rb

class Account < ActiveRecord::Base
  has_many :users
  belongs_to :owner, class_name: 'User'

  accepts_nested_attributes_for :owner
end


#models/user.rb

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  belongs_to :account
  has_one :owned_account, class_name: 'Account', foreign_key: 'owner_id'
end
  

Мы надеемся, что правильная настройка ассоциации решит вашу проблему.

Комментарии:

1. Я внес изменения, но результат, похоже, был тем же, в записи учетной записи был указан owner_id, но в записи пользователя не был указан account_id. Кажется, что запись пользователя сохраняется до создания идентификатора учетной записи, поэтому account_id равен нулю в записи пользователя.

2. Я вижу. Ну, это не элегантное решение, но теперь, когда ваши ассоциации хорошо настроены, в действии Account#create после @account.save вы можете ввести строку типа: @account.owner.update(account_id: @account.id )