Ответ 1
Возможно, вы ищете first_or_create
или что-то подобное:
http://guides.rubyonrails.org/v3.2.17/active_record_querying.html#first_or_create
Попытка реализовать запись создания, если она не существует, в Active Record.
В настоящее время используется:
@student = Student.where(:user_id => current_user.id).first
if @student
Student.destroy_all(:user_id => current_user.id)
end
Student = Student.new(:user_id => current_user.id, :department => 1
)
Student.save!
Каким будет правильный способ обновления записи, если она существует, или создать ее?
Возможно, вы ищете first_or_create
или что-то подобное:
http://guides.rubyonrails.org/v3.2.17/active_record_querying.html#first_or_create
В Rails 4
Student.
find_or_initialize_by(:user_id => current_user.id).
update_attributes!(:department => 1)
::first_or_create
(доступный начиная с версии v.2.2.1) делает то, что он говорит в поле.
Model.where(find: 'find_value').
first_or_create(create: 'create_value')
# If a record with {find: 'find_value'} already exists:
before #=> #<Model id: 1, find: "find_value", create: nil>
after #=> #<Model id: 1, find: "find_value", create: nil>
# Otherwise:
before #=> nil
after #=> #<Model id: 2, find: "find_value", create: "create_value">
Если вы также хотите обновить уже существующую запись, попробуйте:
Model.where(find: 'find_value').
first_or_create(create: 'create_value').
update(update: 'update_value')
# If one already exists:
before #=> #<Model id: 1, find: "find_value", create: nil, update: nil>
after #=> #<Model id: 1, find: "find_value", create: nil, update: "update_value">
# If it already matches, no UPDATE statement will be run:
before #=> #<Model id: 1, find: "find_value", create: nil, update: "update_value">
after #=> #<Model id: 1, find: "find_value", create: nil, update: "update_value">
# Otherwise:
before #=> nil
after #=> #<Model id: 2, find: "find_value", create: 'create_value', update: "update_value">
EDIT 2016-03-08: согласно Doug comment, если ваши проверки сбой между вызовами #create
и #update
или вы хотите минимизировать вызовы базы данных, вместо этого вы можете использовать ::first_or_initialize
, чтобы избежать сохранения записи при первом вызове. Тем не менее, вы должны, чтобы впоследствии вы вызывали #save
или #update
, чтобы сохранить запись:
Model.validates :update, presence: true # The create call would fail this
Model.where(find: 'find_value').
first_or_initialize(create: 'create_value'). # doesn't call validations
update(update: 'update_value')
(NB. Существует метод под названием #create_or_update
, но не обманывайтесь какой-либо документацией, которую вы можете найти в Google; это только частный метод, используемый #save
.)
@student = Student.where(user_id: current_user.id).first
@student ||= Student.new(user_id: current_user.id)
@student.department_id = 1
@student.save
Это красивее, если у вас есть связь между пользователем и учеником. Что-то вдоль линий
@student = current_user.student || current_user.build_student
@student.department_id = 1
@student.save
EDIT:
Вы также можете использовать http://guides.rubyonrails.org/active_record_querying.html#first_or_create, как было указано семьсекатом, но вам все равно придется иметь дело с различными сценариями, такими как обновление идентификатора студенческого отдела.
UPDATE:
Вы можете использовать find_or_create_by
@student = Student.find_or_create_by(user_id: current_user.id) do |student|
student.department_id = 1
end
К сожалению, я думаю, что самый чистый способ сделать это:
Student.where(user_id: id).first_or_create(age: 16).update_attribute(:age, 16)
Это find_or_create_by не first_or_create.
Пример:
Client.find_or_create_by (first_name: 'Andy')