Ассоциация модели has_one не обеспечивает «один» в связанной модели?

у меня есть следующее

class User < ApplicationRecord

  has_one :physician

end

а также

class Physician < ApplicationRecord

  belongs_to :user

end

Поскольку у пользователя может быть только один врач, меня удивило, что с одним и тем же идентификатором пользователя можно создать несколько записей о врачах.

Почему это? И как мне это предотвратить?


person stevec    schedule 29.08.2020    source источник
comment
Да, рельсы не обновляют одну запись, она просто использует последнюю. В этом ответе используется ограничение уровня БД... stackoverflow.com/questions/43783347/   -  person dbugger    schedule 29.08.2020
comment
Как вы создаете врачей?   -  person Maxence    schedule 29.08.2020
comment
@Maxence идея состоит в том, что каждый пользователь, который регистрируется, автоматически считается пациентом, и небольшая часть этих пациентов будет врачами в реальной жизни, и они могут стать врачами. Предположим, я врач в реальной жизни, и я регистрируюсь, затем я становлюсь Пользователем и Пациентом, и как только я подаю заявку внутри приложения, я тоже становлюсь Врачом. Но пользователь steve, безусловно, может быть только одним врачом. Я надеюсь это имеет смысл?   -  person stevec    schedule 30.08.2020


Ответы (2)


Ассоциация belongs_to никоим образом не гарантирует уникальность значений. Он только предусматривает, что ассоциация хранится во внешнем ключе в этой таблице моделей и, следовательно, может иметь только одно значение.

has_one тоже не дает никаких гарантий. Он просто указывает, что на эту таблицу ссылается другая таблица. Если в другой таблице есть несколько совпадающих строк, будет выбрана последняя.

Если вы хотите обеспечить уникальность для каждой таблицы, вам нужна проверка:

class Physician < ApplicationRecord
  belongs_to :user
  validates_uniqueness_of :user_id
end

А индекс базы данных фактически гарантирует уникальность на уровне базы данных:

class AddUniqueIndexToPhysicians < ActiveRecord::Migration[6.0]
  def change
    add_index :physicians, :user_id, unique: true
  end
end
person max    schedule 03.09.2020
comment
Спасибо Макс! Случайный вопрос. Зачем нужна миграция? (Я бы предположил, что проверки будет достаточно)? - person stevec; 03.09.2020
comment
Из-за условий гонки. Связанная статья объясняет это намного лучше, чем я могу. - person max; 03.09.2020
comment
У меня ушло некоторое время, но я только что прочитал статью. Отличное объяснение - person stevec; 05.09.2020
comment
Почему-то ArgumentError: Index name 'index_physicians_on_user_id' on table 'physicians' already exists. Может, одного validates_uniqueness_of :user_id достаточно? - person stevec; 09.09.2020

Physician, вероятно, не должен иметь связанного с ним user_id:

class User
  belongs_to :physician # has a physician_id column
end

class Physician
  has_many :users # has no mention of user_id in its schema
end

belongs_to требуется по умолчанию для Rails 5 и более поздних версий. Если пользователи могут войти на борт без врача, и вам нужно отключить это:

class User
  belongs_to :physician, optional: true 
end 

А потом подтвердите наличие physician только после некоторого условия.

person Josh Brody    schedule 29.08.2020
comment
Спасибо за помощь! Идея состоит в том, что каждый пользователь, который зарегистрируется, будет пользователем, а некоторые (которые в реальной жизни являются врачами) могут подать заявку, чтобы стать врачом. Таким образом, 99% пользователей не будут врачами, но ~1% будут, и у них также будет учетная запись пользователя. Например. Предположим, что я врач в реальной жизни, и я зарегистрируюсь, у меня будет учетная запись пользователя, затем я подам заявку на роль врача и получу запись врача. В настоящее время база данных не мешает мне делать несколько записей о врачах (но должна, и с этой частью у меня проблемы) - person stevec; 30.08.2020