Rails - создание экземпляра из модели в другой модели - PullRequest
0 голосов
/ 19 ноября 2018

Я совершенно новичок в Ruby и мне было интересно, как мне поступить, если я хочу, чтобы каждый раз, когда я создаю нового пользователя (при регистрации), он автоматически создавал экземпляр Исполнителя, так что новый Пользователь = Исполнитель.

Я совершенно заблудился, и было бы очень полезно получить помощь и объяснения.

Пользовательский контроллер

each_pair { |name, val|  }class UsersController < ApplicationController
  before_action :configure_permitted_parameters, if: :devise_controller?
  before_action :update_resource_params, if: :devise_controller?

  def new
    @user = User.new
  end

  def create
    @user = User.new(user.params)
    @contractor = Contractor.create(user: @user)
    if @user.save
      UserMailer.user_alert(@user).deliver_now
      redirect_to @user, notice: 'User was successfully created.'
    else
      render :new
    end
  end

Модель подрядчика

class Contractor < ApplicationRecord
  belongs_to :user
  has_many :construction_projects, dependent: :destroy
  has_many :clients, dependent: :destroy
  has_many :documents, through: :construction_projects
  has_many :resources
  mount_uploader :logo, LogoUploader

  # Model validations
  validates :user, presence: true
  validates_associated :construction_projects
  validates_associated :clients
  validates_associated :documents
  validates_associated :resources

Модель пользователя

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :contractor
  has_many :clients, through: :contractor
  has_many :construction_projects, through: :contractor

  # Model validations
  validates_associated :clients
  validates_associated :construction_projects

  validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }

  def option_projects
   projects = self.contractor.construction_projects.map{ |cp| [cp.name, cp.id] }
   projects << ["Add a new project", "Add a new project"]
   projects
  end
end

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Вам нужно начать с настройки связи между пользователем и подрядчиком:

class User < ApplicationRecord
  # ...
  has_one :contractor
  # or
  has_many :contractors
end

Затем можно вставить обе записи сразу, построив одну из связей:

irb(main):001:0> @user = User.new
=> #<User id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> @user.build_contractor
=> #<Contractor id: nil, user_id: nil, created_at: nil, updated_at: nil>
irb(main):003:0> @user.save
   (0.3ms)  BEGIN
  User Create (0.8ms)  INSERT INTO "users" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2018-11-19 17:43:37.730785"], ["updated_at", "2018-11-19 17:43:37.730785"]]
  Contractor Create (1.9ms)  INSERT INTO "contractors" ("user_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["user_id", 2], ["created_at", "2018-11-19 17:43:37.734395"], ["updated_at", "2018-11-19 17:43:37.734395"]]
   (1.2ms)  COMMIT

ActiveRecord достаточно умен, чтобы вставлять записи в правильном порядке, чтобы возвращаемый идентификатор использовался для contractors.user_id.

Если ассоциация has_many, вы можете сделать то же самое, позвонив по номеру .new:

@user.contractors.new

См .:

0 голосов
/ 19 ноября 2018

Вы определили, что пользователь has_one подрядчик, что означает, что у подрядчика есть внешний ключ (user_id).Вы создаете подрядчика следующим образом:

@user = User.new(user.params)
@contractor = Contractor.create(user: @user)

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

Вы не проверяете здесь какие-либо ошибки валидации, поэтому возможно, что это создаст подрядчика, ноне пользователь.

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

@user = User.new(user.params)   # should that be user_params?
if @user.save
  # now we have a saved user, so create its associated Contractor
  @user.create_contractor!
  ...

Метод create_contractor! автоматически определяется для вас, когда вы объявляете ассоциацию has_one.Версия метода ! вызовет исключение, если при создании подрядчика произошла ошибка.Это кажется разумным, если у вас нет какого-либо метода обработки такой ошибки здесь (и вы не ожидаете этого при нормальных обстоятельствах).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...