users
テーブルとテーブルを備えたアプリケーションがありuser_profiles
ます。ユーザーhas_one
ユーザープロファイルとユーザープロファイルbelongs_to
ユーザー。
アソシエーションシナリオが常に真であることを確認したいので、両方の外部キーの存在を検証しました。問題は、私が「鶏が先か卵が先か」という状況に陥ったことです。ユーザーを作成すると、ユーザープロファイルがまだ存在しないために機能しません。また、ユーザープロファイルを作成すると、ユーザーがまだ存在しないために機能しません。したがって、ユーザーの作成内にユーザープロファイルを作成する必要があります。複雑なことに、クライアントを作成するときに、after_create
コールバックでユーザーも作成します。十分に話す(または読む/書く)、ここにいくつかのコードがあります:
class User < ActiveRecord::Base
has_one :user_profile
validates :user_profile_id, presence: true
end
class UserProfile < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
class Client < ActiveRecord::Base
after_create :create_client_user
private
def create_client_user
User.create!(
email: "admin@example.com",
password: "admin",
password_confirmation: "admin",
client_id: self.id
# I need to create a user profile dynamically here
)
end
end
私がやりたいことをすることは可能ですか?
アップデート
@cdesrosiersが提案した解決策を試しましたが、仕様に合格できません。私は主に3つのエラーがあります。まず、更新されたモデルを紹介します。
class User < ActiveRecord::Base
has_one :user_profile, inverse_of: :user
before_create { build_user_profile }
validates :user_profile, presence: true
def client=(client)
self.client_id = client.id
end
def client
current_database = Apartment::Database.current_database
Apartment::Database.switch
client = Client.find(self.client_id)
Apartment::Database.switch(current_database)
client
end
end
class UserProfile < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
end
class Client < ActiveRecord::Base
attr_accessible :domain, :name
after_create :create_client_database
after_create :create_client_user
after_destroy :drop_client_database
# Create the client database (Apartment) for multi-tenancy
def create_client_database
Apartment::Database.create(self.domain)
end
# Create an admin user for the client
def create_client_user
Apartment::Database.switch(self.domain)
User.create!(
email: "admin@example.com",
password: "admin",
password_confirmation: "admin",
client: self
)
# Switch back to the public schema
Apartment::Database.switch
end
def drop_client_database
Apartment::Database.drop(self.domain)
end
end
FactoryGirlを使用してファクトリを作成しています。ファクトリファイルは次のとおりです。
FactoryGirl.define do
factory :client do
sequence(:domain) { |n| "client#{n}" }
name Faker::Company.name
end
factory :user do
sequence(:email) { |n| "user#{n}@example.com"}
password "password"
password_confirmation "password"
client
#user_profile
end
factory :credentials, class: User do
email "user@example.com"
password "password"
end
factory :user_profile do
forename Faker::Name.first_name
surname Faker::Name.last_name
birthday (5..90).to_a.sample.years.ago
#user
end
end
ユーザーファクトリとユーザープロファイルファクトリのそれぞれuser_profile
とアソシエーションのコメントを解除すると、が表示されます。user
WARNING: out of shared memory
これらのファクトリの1つを作成すると、次の3つのエラーのいずれかが発生します。
Failure/Error: @user = create(:user)
ActiveRecord::RecordInvalid:
Validation failed: User profile A user profile is required
# ./app/models/client.rb:41:in `create_client_user'
# ./spec/controllers/users_controller_spec.rb:150:in `block (4 levels) in <top (required)>'
Failure/Error: create(:user_profile).should respond_to :surname
ActiveRecord::RecordInvalid:
Validation failed: User A user is required
# ./spec/models/user_profile_spec.rb:29:in `block (4 levels) in <top (required)>'
Failure/Error: let(:client) { create(:client) }
ActiveRecord::RecordInvalid:
Validation failed: User profile A user profile is required
# ./app/models/client.rb:41:in `create_client_user'
# ./spec/controllers/sessions_controller_spec.rb:4:in `block (2 levels) in <top (required)>'
# ./spec/controllers/sessions_controller_spec.rb:7:in `block (2 levels) in <top (required)>'
したがって、ユーザーモデルの変更は機能しなかったと思います。user_profile_id
また、usersテーブルからを削除したことにも注意してください。