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

313

Есть ли альтернатива 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', но я хочу обновить их все на одной строке.

  • 0
    что значит "не сохранять запись"?
  • 0
    update_attributes сохраняет модель в БД. Мне интересно, есть ли подобный метод, который не делает.
Показать ещё 3 комментария
Теги:
activerecord
ruby-on-rails-4
ruby-on-rails-3

4 ответа

516
Лучший ответ

Я считаю, что вы ищете 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
  • 0
    Ваш пример немного вводит в заблуждение, поскольку вы не вставили эту строку из модели: attr_accessible :is_admin, :as => :admin ;)
  • 0
    @Robin Или просто: attr_protected :is_admin . Или: attr_accessible :name Дело в том, что в этом примере: is_admin защищен. Я также должен отметить, что попытка массового назначения защищенного атрибута с помощью .assign_attributes действительно ActiveModel::MassAssignmentSecurity::Error , даже если это не показано в примере.
Показать ещё 7 комментариев
121

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

Обновление обходных листов методов (для Rails 4):

  • update_attributes= assign_attributes + save
  • attributes== псевдоним assign_attributes
  • update= псевдоним update_attributes

Источник:
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
    Ясно и коротко. Благодарю.
  • 1
    в случае .attributes = val, если ваша модель has_one и accept_nested_attributes_for другой модели, передача that_model_attributes (без идентификатора) удалит существующую модель has_one, даже если вы не сохраняли ее (например, сохраняли). Но assign_attributes не ведет себя так.
Показать ещё 1 комментарий
57

Вы можете использовать метод 'attributes':

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

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

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

Если guard_protected_attributes является истинным (по умолчанию), тогда чувствительные атрибуты могут быть защищены от этой формы массового присвоения с помощью макроса 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
5

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

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

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

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

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

Рельсы 3

attributes= немного отличается от assign_attributes в Rails 3. attributes= проверяет, что переданный ему аргумент является Hash, и немедленно возвращается, если это не так; assign_attributes не имеет такой проверки хэша. См. Документацию по атрибуту атрибутов 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[] результаты final .map. Поддерживайте код выше 50 строк и 3 функции, удаленные из вашего назначения атрибутов, и у вас есть рецепт отказа.

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

Рельсы 4

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

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

Validations

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

valid? можно использовать следующим образом:

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню