ActiveRecord: обновить запись, если существует, еще создать?

Я много боролся, и в конечном итоге метод, который позволил мне заставить его работать с Rails 4, был:

на вашем старом сервере

sudo su - postgres
pg_dump -c --inserts old_db_name > dump.sql

Мне пришлось использовать postgres linux для создания дампа. также мне пришлось использовать -c для создания базы данных на новом сервере. --inserts сообщает ему использовать синтаксис INSERT (), который в противном случае не работал бы для меня: (

, затем на новом сервере simpy:

sudo su - postgres
psql new_database_name < dump.sql

, чтобы передать Файл dump.sql между сервером Я просто использовал «cat» для печати содержимого, а не «nano», чтобы воссоздать его, копируя содержимое.

Кроме того, ROLE i использовал в обеих базе данных, я должен был найти - заменить все имя владельца в дампе.

29
задан Rubytastic 30 January 2013 в 07:59
поделиться

7 ответов

Возможно, вы ищете first_or_create или что-то похожее:

http://guides.rubyonrails.org/v3.2.17/active_record_querying.html#first_or_create

13
ответ дан sevenseacat 30 January 2013 в 07:59
поделиться

В рельсах 4

Student.
  find_or_initialize_by(:user_id => current_user.id).
  update_attributes!(:department => 1)
60
ответ дан fguillen 30 January 2013 в 07:59
поделиться

::first_or_create (доступно начиная с версии 3.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">

РЕДАКТИРОВАТЬ 2016-03-08: Согласно Дагу комментарий , если ваши проверки не выполняются между вызовами #create и #update, или вы хотите минимизировать вызовы базы данных, вы можете использовать вместо этого ::first_or_initialize, чтобы избежать сохранения записи в первый звонок Тем не менее, вы должны убедиться, что вы вызываете #save или #update впоследствии, чтобы сохранить запись (и я не уверен, что #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.)

15
ответ дан PJSCopeland 30 January 2013 в 07:59
поделиться

В Rails 5

Student.
  find_or_initialize_by(:user_id => current_user.id).
  update(:department => 1)

(все отзывы взяты из ответа @Zorayr).

1
ответ дан Jonathan Simonney 30 January 2013 в 07:59
поделиться
@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

РЕДАКТИРОВАТЬ:

Вы также можете использовать http://guides.rubyonrails.org/active_record_querying.html#first_or_create в ответ на это sevenseacat, но вам все еще приходится иметь дело с различными сценариями, такими как обновление идентификатора студенческого отделения.

ОБНОВЛЕНИЕ:

Вы можете использовать find_or_create_by

@student = Student.find_or_create_by(user_id: current_user.id) do |student|
  student.department_id = 1
end
4
ответ дан jvnill 30 January 2013 в 07:59
поделиться

К сожалению, я думаю, что самый чистый способ сделать это:

Student.where(user_id: id).first_or_create(age: 16).update_attribute(:age, 16)
0
ответ дан Blair Anderson 30 January 2013 в 07:59
поделиться

Это find_or_create_by , а не first_or_create .
Пример: Client.find_or_create_by (имя: «Энди»)

-5
ответ дан sevenseacat 30 January 2013 в 07:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: