Rails update_attributes без сохранения?

386

Есть ли альтернатива update_attributes, которая не сохраняет запись?

Так что я мог сделать что-то вроде:

@car = Car.new(:make => 'GMC')
#other processing
@car.update_attributes(:model => 'Sierra', :year => "2012", :looks => "Super Sexy, wanna make love to it")
#other processing
@car.save

Кстати, я знаю, что могу @car.model = 'Sierra', но я хочу обновить их все в одной строке.

tybro0103
источник
что вы имеете в виду "не сохранить запись"?
Анатолий
update_attributes сохраняет модель в БД. Мне интересно, есть ли подобный метод, который не делает.
tybro0103
3
Атрибуты неразрушающего метода. Смотрите API для деталей
Анатолий
3
Вы можете использовать update_column (name, value) Обновляет отдельный атрибут объекта, не вызывая save. 1. Проверка пропущена. 2. Обратные вызовы пропускаются. 3. Столбец updated_at / updated_on не обновляется, если этот столбец доступен. apidock.com/rails/ActiveRecord/Persistence/update_column
Антуан,
10
Для версии 3.1+ используйте assign_attributes apidock.com/rails/ActiveRecord/Base/assign_attributes
elado

Ответы:

597

Я верю в то, что вы ищете assign_attributes.

Он в основном такой же, как update_attributes, но не сохраняет запись:

class User < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :name, :is_admin, :as => :admin
end

user = User.new
user.assign_attributes({ :name => 'Josh', :is_admin => true }) # Raises an ActiveModel::MassAssignmentSecurity::Error
user.assign_attributes({ :name => 'Bob'})
user.name        # => "Bob"
user.is_admin?   # => false
user.new_record? # => true
Ajedi32
источник
Ваш пример немного вводит в заблуждение, поскольку вы не вставили эту строку из модели attr_accessible :is_admin, :as => :admin:;)
Робин
@Robin Или просто: attr_protected :is_admin. Или: attr_accessible :nameДело в том, что в этом примере: is_admin защищен. Следует также отметить, что попытка массового присвоения защищенного атрибута .assign_attributesдействительно вызывает ActiveModel::MassAssignmentSecurity::Error, хотя это не показано в примере.
Ajedi32
Да, но моя линия от документа, с которым вы связаны. Я просто говорю, что вы должны были скопировать / вставить весь пример. Но да, вы можете просто сказать, что он защищен.
Робин
@Robin Я обновлю пример, чтобы он был более конкретным. Пример в документации также немного вводит в заблуждение, поскольку в нем не упоминается, что user.assign_attributes({ :name => 'Josh', :is_admin => true })возникает сообщение об ошибке и фактически не устанавливается свойство имени пользователя.
Ajedi32
7
Аргумент assign_attributes доступен начиная с Rails 3.1 и выше, поэтому его нельзя использовать, если вы все еще используете старую версию Rails.
Хаегин
174

Вы можете использовать assign_attributesили attributes=(они одинаковы)

Способы обновления шпаргалки (для Rails 6):

  • update= assign_attributes+save
  • attributes= = псевдоним assign_attributes
  • update_attributes = устарело, псевдоним update

Источник:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment .rb

Другая шпаргалка:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet

Ярина
источник
1
Ясно и коротко. Спасибо.
freemanoid
1
в случае .attributes = val, если ваша модель has_one и accept_nested_attributes_for другой модели, передача that_model_attributes (без идентификатора) удалит существующую модель has_one, даже если вы не сохраняли ее (например, сохраняли). Но assign_attributes не ведет себя так.
ClassyPimp
65

Вы можете использовать метод «атрибутов»:

@car.attributes = {:model => 'Sierra', :years => '1990', :looks => 'Sexy'}

Источник: http://api.rubyonrails.org/classes/ActiveRecord/Base.html

attribute = (new_attributes, guard_protected_attributes = true) Позволяет установить все атрибуты одновременно, передав хеш с ключами, совпадающими с именами атрибутов (что снова совпадает с именами столбцов).

Если guard_protected_attributes имеет значение true (по умолчанию), то конфиденциальные атрибуты могут быть защищены от этой формы массового назначения с помощью макроса attr_protected. Или вы можете указать, какие атрибуты доступны с помощью макроса attr_accessible. Тогда все атрибуты, не включенные в это, не смогут быть назначены по массе.

class User < ActiveRecord::Base
  attr_protected :is_admin
end

user = User.new
user.attributes = { :username => 'Phusion', :is_admin => true }
user.username   # => "Phusion"
user.is_admin?  # => false

user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
user.is_admin?  # => true
bruno077
источник
7

Для массового присвоения значений модели ActiveRecord без сохранения используйте методы assign_attributesлибо attributes=. Эти методы доступны в Rails 3 и новее. Тем не менее, есть небольшие различия и связанные с версией ошибки, о которых следует знать.

Оба метода следуют этому использованию:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }

@user.attributes = { model: "Sierra", year: "2012", looks: "Sexy" }

Обратите внимание, что ни один из методов не будет выполнять проверки или выполнять обратные вызовы; обратные вызовы и проверка будут происходить при saveвызове.

Рельсы 3

attributes=немного отличается от assign_attributesRails 3. attributes=проверит, что переданный ему аргумент является Hash, и немедленно возвращает, если это не так; assign_attributesне имеет такой проверки хэша. См. Документацию API Назначения атрибутов ActiveRecord дляattributes= .

Следующий неверный код молча завершится ошибкой, просто вернувшись без установки атрибутов:

@user.attributes = [ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ]

attributes= будет молча вести себя так, как будто назначения были выполнены успешно, тогда как на самом деле они не были.

Этот неверный код вызовет исключение, когда assign_attributesпопытается преобразовать ключи хеша в массив:

@user.assign_attributes([ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ])

assign_attributesвызовет NoMethodErrorисключение для stringify_keys, указывая, что первый аргумент не является хешем. Само исключение не очень информативно о фактической причине, но тот факт, что исключение действительно имеет место, очень важен.

Единственное различие между этими случаями заключается в методе, используемом для массового присваивания: attributes=молча завершается успешно и assign_attributesвыдает исключение, чтобы сообщить, что произошла ошибка.

Эти примеры могут показаться надуманными, и они в некоторой степени, но этот тип ошибки может легко возникнуть при преобразовании данных из API или даже просто при использовании серии преобразований данных и забыв Hash[]о результатах финала .map. Оставьте код на 50 строк выше и удалите 3 функции из вашего назначения атрибутов, и вы получите рецепт ошибки.

Урок с Rails 3 таков: всегда используйте assign_attributesвместо attributes=.

Рельсы 4

В Rails 4 attributes=это просто псевдоним assign_attributes. См. Документацию API Назначения атрибутов ActiveRecord дляattributes= .

В Rails 4 любой метод может использоваться взаимозаменяемо. Неспособность передать Hash в качестве первого аргумента приведет к очень полезному исключению:ArgumentError: When assigning attributes, you must pass a hash as an argument.

Validations

Если вы выполняете предварительные проверки заданий при подготовке к a save, возможно, вас заинтересует проверка перед сохранением. Вы можете использовать valid?и invalid?методы для этого. Оба возвращают логические значения. valid?возвращает true, если несохраненная модель прошла все проверки, или false, если нет. invalid?просто обратная сторонаvalid?

valid? можно использовать так:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid?

Это даст вам возможность обрабатывать любые вопросы проверки до звонка save.

Майкл Гаскилл
источник