#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 )