3

Possible Duplicate:
Rails update_attributes without save?

Fundamentally, I want to do an ActiveRecord "update_attributes" while leaving the ActiveRecord changes pending. Is there a way to accomplish this? Read on if you are wondering why I would want this.

I have a form consisting of three parts: a static portion (text fields independent of each other), a set of selections (grows as entries are filled in), and a section showing the effects of the selections upon a group of dependent objects. Changing the selections requires a round trip to the server to determine the effects and some of the selections affect the choices for future selections. The selections are modeled as a has_many association from the basic model. E.g. (note that the [] entries designate HTML-SELECTs)

Include [section]
  Exclude [subsection]
  Exclude [subsection]
Include [section]
  Exclude [subsection]
...

I have set the form up as a typical nested-attributes form. When a selection is changed, I post back the fields with AJAX such that I'm getting the typical params hash (e.g. params[:basemodel][associated_models_attributes][0][:field_name]). I'd like to get this into an unsaved ActiveRecord so that the partials I'm already using to generate parts of the original page can be used to generate the JS response (I'm using a js.erb file for this). Using Basemodel.new(params[:basemodel]) gives the error

"ActiveRecord::RecordNotFound (Couldn't find AssociatedModel with ID=1 for Basemodel with ID=)

This is happening (I think) because the IDs from the existing associated records (which have non-blank IDs in the current record) do not match up with the blank IDs that would be generated from the "new" call.

I could do something really kludgy and create something that looks like an ActiveRecord (at least enough like it to satisfy my partials) but I have to think that this is a problem that is common enough that there's a good solution for it.

Community
  • 1
  • 1
Jack R-G
  • 1,778
  • 2
  • 19
  • 25
  • For 3.1+, use `assign_attributes` http://apidock.com/rails/ActiveRecord/Base/assign_attributes – elado Jun 13 '12 at 08:34
  • You can use update_column(name, value) Updates a single attribute of an object, without calling save. 1. Validation is skipped. 2. Callbacks are skipped. 3. updated_at/updated_on column is not updated if that column is available. http://apidock.com/rails/ActiveRecord/Persistence/update_column – Alpha Beta Charlie May 09 '12 at 22:39

2 Answers2

7

Depending on the source of ActiveRecord::Persistence#update_attributes

# File activerecord/lib/active_record/persistence.rb, line 127
def update_attributes(attributes)
  # The following transaction covers any possible database side-effects of the
  # attributes assignment. For example, setting the IDs of a child collection.
  with_transaction_returning_status do
    self.attributes = attributes
    save
  end
end

you can assign attributes to your model by using

model.attributes = attributes

where attributes is a hash of model fields etc.

Hck
  • 9,087
  • 2
  • 30
  • 25
4

The following should, like update_attributes, allow you to pass a subset of the model's attributes without clearing the other attributes as well as silently ignore any unknown attributes in your hash. It also shouldn't care if you use strings or symbols as your hash keys.

def set_attributes (attributes)
  attributes.each do |key, value|
    self.send("#{key}=", value) if self.respond_to?("#{key}=")
  end
end
Jeremy Weathers
  • 2,556
  • 1
  • 16
  • 24
  • I think this would probably have worked, but see the next answer for a more elegant solution. Thanks for your response. – Jack R-G Jul 01 '11 at 17:22