Non-dirty serialized columns are being saved anyway #8328

Closed
elado opened this Issue Nov 26, 2012 · 63 comments

Projects

None yet
@elado
elado commented Nov 26, 2012

New Rails 3.2.9 app with one model that has a serialized column:

rails new ar_serialized_dirty_test
cd ar_serialized_dirty_test

rails g model Product name:string data:text
rake db:migrate

# product.rb

class Product < ActiveRecord::Base
  serialize :data
end

On every save, this column is being updated, regardless if it was changed or not.

> p = Product.create(name: "A")
  SQL (0.6ms)  INSERT INTO "products" ("created_at", "data", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Mon, 26 Nov 2012 23:08:26 UTC +00:00], ["data", nil], ["name", "A"], ["updated_at", Mon, 26 Nov 2012 23:08:26 UTC +00:00]]
 => #<Product id: 1, name: "A", data: nil, created_at: "2012-11-26 23:08:26", updated_at: "2012-11-26 23:08:26"> 
> p.save!
   (0.3ms)  UPDATE "products" SET "updated_at" = '2012-11-26 23:08:34.660484', "data" = '---\n...\n' WHERE "products"."id" = 1
 => true 
> p.save!
   (0.3ms)  UPDATE "products" SET "updated_at" = '2012-11-26 23:08:45.777419', "data" = '---\n...\n' WHERE "products"."id" = 1
 => true 
> p.data_changed?
 => false 
> p.save!
   (0.3ms)  UPDATE "products" SET "updated_at" = '2012-11-26 23:13:20.839794', "data" = '---\n...\n' WHERE "products"."id" = 1
@felipecsl

+1 for that

@senny
Member
senny commented Nov 27, 2012

This is the intended behavior. It was added with this commit 144e869 by @jonleighton . There is even an explantation why it behaves the way it does:

# Serialized attributes should always be written in case they've been
# changed in place.
def keys_for_partial_write
  changed | (attributes.keys & self.class.serialized_attributes.keys)
end

The problem is that serialized data-structures can be changed without using the ActiveRecord setters. Then there is no way to detect that a change actually happend. To work around this problem serialized attributes are written all the time.

@rafaelfranca
Member

@senny right. Closing it.

@elado thank you for reporting.

@elado
elado commented Nov 28, 2012

Thanks.
Indeed, looks like _changed? method doesn't return true if I change a value within a value, p.data[:x] = 1

What about keeping the original serialized value after fetching and compare it to the current serialized value before saving?

@rafaelfranca
Member

@elado I think this is a unnecessary overhead, much more than writing the serialized attribute every time.

@unorthodoxgeek

@rafaelfranca think large scale, 1M+ writes per minute to the RDB. on the ruby side, that wouldn't take too much time, but it can bring a really strong SQL machine down on its knees.

there are less expensive ways of doing this than comparing, for instance, extend the serialized object to have a changed attribute accessor and when a setter method is called on it, it will also set that value to true.

@elado
elado commented Nov 28, 2012

@rafaelfranca, as @unorthodoxgeek said, it's definitely a performance issue.

Instead of an expensive DB access for no reason, Rails could either serialize the initial value after fetching and compare to it to the current serialized value for dirty check, or have #eql? method in the serializer class (the one that has #load/#dump) that'll compare things by content.

I believe usually the serialized attribute is a Hash or an Array, so #eql? shouldn't be that expensive.

Let's remember this code overhead (not performance overhead) only happens when there are serialized attributes, and current state is that a query is executed every time and this is far longer operation.

Thanks

@senny
Member
senny commented Nov 28, 2012

@elado If you can come up with a good PR I think there is nothing that will prevent it from getting merged. As the current behavior is known and expected we don't treat this as a bug though. Feel free to use the Rails Core GoogleGroup to discuss the idea and the change you want to make. Of course you can also just hack up the PR and start a discussion with it.

@rafaelfranca
Member

@elado @unorthodoxgeek I see. It make sense.

Mind to open a pull request?

I'm reopening this issue.

@rafaelfranca rafaelfranca reopened this Nov 30, 2012
@jonleighton
Member

@tenderlove has talked to me about using Object#hash to determine which attributes have changed. That seems like to way to go to me. Then we don't need special handling for serialized attributes.

@al2o3cr
Contributor
al2o3cr commented Dec 2, 2012

The challenge here is how to "save the original" for comparison purposes - just stashing it someplace isn't sufficient. For instance, if you've got a Hash with Array values:

irb: h = { a: [1,2,3], b: [4,5,6] }
===> {:a=>[1, 2, 3], :b=>[4, 5, 6]}
irb: h2 = h.deep_dup
===> {:a=>[1, 2, 3], :b=>[4, 5, 6]}
irb: h2[:a][0] = -1
===> -1
irb: h
===> {:a=>[-1, 2, 3], :b=>[4, 5, 6]}

Neither dup nor clone will do the right thing here either - there is one reliable way to do it, but it's (somewhat) expensive and fails if an object can't be Marshalled:

irb: h = { a: [1,2,3], b: [4,5,6] }
===> {:a=>[1, 2, 3], :b=>[4, 5, 6]}
irb: h_copy = Marshal.load(Marshal.dump(h))
===> {:a=>[1, 2, 3], :b=>[4, 5, 6]}
irb: h_copy[:a][0] = -1
===> -1
irb: h
===> {:a=>[1, 2, 3], :b=>[4, 5, 6]}

There's also the side-issue that such copying would have to be done pessimistically (every time an object is loaded from the DB) or users would likely encounter bugs if they mutate the serialized attribute in-place (since calling some_serialized_attribute_will_change! isn't currently required by the "save serialized things every time" strategy). In particular, users may wind up with silent data loss...

@unorthodoxgeek

what about marshalling it and saving an md5 of the output string? should be
a fairly good way of comparing two hard-to-compare objects...

@ragalie
ragalie commented Dec 3, 2012

This isn't the ideal solution, but why not note when the serialized attribute is read/written to and only save it in that case. If the attribute hasn't been read it couldn't have been modified.

For applications where the serialized attribute is rarely accessed this would cut down on extraneous SQL calls while avoiding some of complexities in the proposals that try to compare versions of the serialized attribute.

@ndbroadbent
Contributor

I agree with @elado's initial suggestion of storing the original unserialized string, but maybe as a MD5 hash. If you have:

class Product < ActiveRecord::Base
  serialize :categories, Array
end

then the original string's MD5 hash could be stored somewhere like @product.unserialized_categories_hash or @product.unserialized_attribute_hashes['categories'], before being parsed.

That would make it easy to detect changes properly, even if the attribute is modified in place.

@darthdeus

+1

@njakobsen
Contributor

+1

@tenderlove via @jonleighton had the answer. Every object has a .hash method. Call that to see if the serialized hash is different. If so, mark as dirty.

@neerajdotname
Member

@jonleighton any thoughts on how to retrieve old value so that when p.data_changed? is invoked we can do the Object#hash matching. Looking at the code I could not find any clean way to retrieve the old value when the value is changed in-memory.

@venkatesanmurali

So how do we handle the following scenario?

  1. I modify some data on a serialized data. (say, i delete some values in the data array).
  2. I would want to save the data only if its changed. Why should i unnecessarily update a row if there is no value changed. (i m on a loop and only some data will be changed based on condition)
@letronje

Is there a way to disable this at a per-model level ?

@njakobsen
Contributor

@senny Referring back to your code quote from @jonleighton, I'm not sure why serialized data is so special just because it can be changed in-place. A string can also be changed in place without the changes being detected.

user = User.first
user.first_name.replace('Changed')
user.first_name #=> "Changed"
user.changes #=> {}
@al2o3cr
Contributor
al2o3cr commented Aug 22, 2013

@njakobsen - sure, but the situation with serialized fields is different (IMO) for two reasons:

  • in-place modifications are far more likely for serialized data; the first_name.replace example is far less common than something like user.some_serialized_field[:foo] = 'bar'
  • users who are performing in-place modifications on String columns are either already calling user.first_name_will_change! (in the example above) beforehand or are already experiencing bugs. Users who are modifying serialized data in-place are not, since that data is always saved.
@myitcv
myitcv commented Aug 22, 2013

Supporting in-place changes feels like it is beyond the scope of this discussion, no? Not least because trying to support it (and being consistent) would require that a shadow .clone always be held for every attribute, serializable or not. There's a clear cost associated with that. Or the ambiguity that is created around saying 'you can modify some attributes in place but not others' if you only support it for serializable attributes - a recipe for more bugs perhaps?

As @jonleighton pointed out, using the .hash 'interface' at least gives a clean, standardised way for comparing equality when it comes to setting an attribute. It would also push the task of .clone (or similar) onto the caller, but this seems like a fair compromise if speed/efficiency is the goal.

So +1 for the use of .hash in determining whether an attribute has changed when it is set via = etc. This would then allow accurate tracking of whether the attribute is dirty or not and therefore short-circuiting of database writes if the attribute hasn't changed.

And then another +1 for spelling out in the docs that in-place changes won't be picked up (particularly here) - I got bitten by this because I (wrongly?) wrapped my obj.save with if obj.changed?

@njakobsen
Contributor

@myitcv If the .hash implementation is used, there will be no need to document gotchas with in-place changes since they would be detected.

@myitcv
myitcv commented Aug 23, 2013

@njakobsen - true, but I think the only way to 'detect' all in-place updates would be to store a hash for every attribute at the persistence layer. Loading from the DB would trigger a hash calculation on each attribute for the pre value, then persisting would need to compute a hash value for each attribute.... Seems like a big overhead (in terms of processing and memory), no? (I realise this retreats slightly on my earlier comment about needing to keep a shadow .clone - a hash would suffice)

@njakobsen
Contributor

@myitcv Yes it probably would, though I imagine it would be worth looking into as most attributes would have simple integer or string values anyway. However, I think the overhead of always saving a record simply because it has a serialized column is what is really the issue here. My previous comment (probably unnecessary) was not to suggest a course of action, just to point out that the documentation was unnecessary if all columns used the hash method of dirty checking.

+1 for hash checking of serialized attributes because it would definitely be faster than serializing them and saving them just in case they change.

@samg
Contributor
samg commented Aug 28, 2013

I just hit this issue myself.

One thing I was wishing for was a way to mark a serialized attribute as unchanged (e.g. #some_attribute_will_not_change!). In my use case it would be pretty easy for me to compare the attribute value myself and mark it unchanged when appropriate. This isn't an ideal solution, but might be a reasonable extension of the current api and give users the ability to work around these types of issues to meet their specific needs.

In our case we're using the paper_trail gem to track changes to a model. Since that model contains a serialized attribute we record a change even if users just open the form and hit submit, but don't make a change. This is undesirable, but trivial enough that I'm just going to live with it. If I had the ability to explicitly tell the model that the attribute has not changed I'd just do that.

Thanks!

@schmurfy

That is damn annoying, why consider serialized attributes differently than any others ? After all there is a will_change! method when updating an attribute in place, how is it different here ?

@schmurfy

another way to fix the issue, in your model:

class MyModel < ActiveRecord::Base
    serialize :something

    def keys_for_partial_write
      changed
    end

    def should_record_timestamps?
      self.record_timestamps && (!partial_writes? || changed?)
    end

end

This "patch" redefine the methods to NOT check for serialized attributes.

@schmurfy

In my case a save on a Contact activerecord object triggered a useless update without reason which in turn triggered a rebuild of the cached versions served to multiple clients which caused each of these clients to refresh this contact... (obviously the problem was not only with one contact or I wouldn't have had to spent an hour trying to figure out what was happening).

I am sure I already stumbled on this one but that's the first time it annoys me enough to have to dig it out, I would to see those completely random decisions removed from activerecord... At least there should be a big warning on the serialize documentation on this behavior.

I could try to provide a patch but I am fairly sure it would be ignored like my other attempts so I prefer doing something useful with my time.

@dmathieu
Contributor

@schmurfy: we should indeed aim for a fix on this.
For the time being though, I just added a warning in the documentation: 976e77

@samg
Contributor
samg commented Oct 24, 2013

@dmathieu any thoughts on what the expected behavior of a fix should be?

@schmurfy

I think the most sensible way to fix this is just to remove any particular behavior associated with serialized attributes and tell users to use will_change! , what do you think ?
The only problem is that it will change the current behavior...

Another way could be adding an option to serialize to disable this forced save.

@al2o3cr
Contributor
al2o3cr commented Oct 24, 2013

-1 for removing the behavior - that WILL cause silent data loss for somebody who's assuming the current behavior and isn't calling _will_change!.

Maybe an option to serialize that disables this behavior for specific fields, so that developers who are aware of the change can get the benefits?

@njakobsen
Contributor

@al2o3cr The rule of least surprise should apply and they should not save unless modified (people are being surprised by the current behaviour). However, your concern about backwards compatibility is valid. There have been several suggestions about how to track changes to serialized data, e.g. tracking Object#hash, which would prevent any need to call will_change! Therefore we can avoid any deprecations, offer better performance, and conform to the same behaviour as with regular model attributes.

Since no core team members have outright said no, at this point it's probably up to us to code a pull request and have it reviewed.

@CyborgMaster

+1 for detecting changes using Object#hash, or at least let me turn this off so I can manage it myself where I want to.

@kbrock
Contributor
kbrock commented Dec 20, 2013

There seems to be 2 solutions mentioned so far:

1. Turn off auto save for serialized fields and rely upon attribute_will_change!
2. Save original value of the serialized attributes. Modify changed or keys_for_partial_write to compare hash codes.

The second one is quite difficult. It may make sense to just go for the low hanging fruit of the first solution. I put together code for the simple solution here: #13423

Any comments would be appreciated.

Thanks,
Keenan

UPDATE: the preferred solution is option 2.

@kbrock
Contributor
kbrock commented Dec 21, 2013

Thanks so much for the quick response on solution 1.

For the option of using hash to compare values, I created solution: #13428

Any suggestions would be appreciated

Thanks,
Keenan

@schmurfy

why not delegate the comparaison to the the serializer class ? (if possible)

Something like:

def same_value?(column_data, ruby_object)
  # ...
end

The advantage I see is to allow complete control in edge cases if the user needs it.

@kbrock
Contributor
kbrock commented Jan 2, 2014

As @al2o3cr mentioned before, storing the previous value is difficult. for #13428 I stored the hash code of the previous value on first attribute access. To cut down work.

Unfortunately, most of the changed methods need a previous value. So not having the actual value introduces some complexities.

@jonleighton / @neerajdotname you have any ideas on the best way to store / fetch the old value?

@kbrock
Contributor
kbrock commented Jan 6, 2014

to further comment on @schmurfy fix above:

module DontAutoSaveSerialized
    def keys_for_partial_write
      changed
    end

    def should_record_timestamps?
      self.record_timestamps && (!partial_writes? || changed?)
    end
end

class MyModel < ActiveRecord::Base
  include DontAutoSaveSerialized

  serialize :something
end

ASIDE: For rails 3.x, you need to patch Dirty#save to use keys_for_partial_write, and use partial_updates? instead of partial_writes?.

@jonashuckestein

I've been following this issue for a while now. I wrote a patch for Rails 3 a while ago that let you change this behavior on a per column basis, but then I came across this thread and my solution got shot down ;)

What do you guys think of implementing this as an option of the serialize method like so:

serialize :some_column, dirty: :always | :never | some_lambda
  • :always is the default and the way it currently is
  • :never doesn't save the column unless #some_column_will_change was called
  • some_lambda gets applied to the field value once after initialization and once before saving. If the results don't match, the field is considered dirty (this could be used for hashes, copies, whatever)

It seems to me like there's no way around storing a hashed or otherwise comparable version of the field after initialization for every record we read from the database. I wouldn't feel comfortable storing away the initial value/hash thereof upon first attribute access. I'm not sure about Rails 4, but IIRC Rails 3 allowed access/modification of serialized attributes via model#serialized_attributes. For me, patching the attribute accessor in this way also violates the principle of least surprise.

Regardless, I don't think storing a hash/copy of the field value is a huge concern, because this behavior would be opt-in. If you really, for whatever reason, need to instantiate millions of records (or perhaps the serializable field contains a lot of data), you can always exclude the field from your query.

@schmurfy

From how it looks I don't think we are gonna get anywhere soon, maybe in 1 more year who knows ;)

fixing what I consider a bug by removing any special handling of serialized attribute with a prior warning does not seems that hard/unreasonable (activerecord breaks something every release anyway for me) but having layers upon layers of complexity seems the way to go for rails...
Seriously, each time I have to debug some crazy bug (yes that's a bug !) it is a damn nightmare just managing to follow what exactly happens where and the worst thing is that the code gets harder and harder to trace with 200 lines of useless backtrace when you get an exception with generated methods calling other generated methods calling generate blocks...

I think the only sane thing for me is just to unsuscribe for this thread, my 6 lines patch works fine and I don't think it will be replaced by anything soon, good luck with that.

@kbrock
Contributor
kbrock commented Jan 10, 2014

@jonashuckestein My only concern with defining this field inline is adding yet another set of logic to an already confusing block of code. Currently, we have:

  • always save (via partial_writes = false)
  • only save dirty fields, but always save serialized (using (attributes.keys & self.class.serialized_attributes.keys) )

and we potentially are going to add:

  • only save dirty fields, and a select list of serialized fields if they have changes, and all the rest of serialized fields

It seems to me like there's no way around storing a hashed or otherwise comparable version of the field after initialization for every record we read from the database. I wouldn't feel comfortable storing away the initial value/hash thereof upon first attribute access. For me, patching the attribute accessor in this way also violates the principle of least surprise.

I'm having trouble parsing your sentence. Are you proposing:

  • storing the initial values at initialization time
  • storing the initial values at first access of the attribute (read: read_attribute(attr))
  • storing the initial values at some other time.

I agree we need to store a comparable version, and I think that is the initial value. Since the whole change mechanism is based upon knowing the previous value, we probably need to be able to produce the initial value. It gets a little too kludgy to have a changed?(attr) == false and hash_changed?(attr) == true. Or a changed?(attr) == true but changed_attributes(attr) == nil.

There are cache tests that make it a little tricky to get the value out at initialization time. So maybe store the @attributes version of the attribute? These attributes are sometimes stored in caches, and sometimes have modified getters/setters, or tweaked time zones. This makes the code a little tricky to determine the true values.

Also, the write_attribute is currently overridden to help determining dirty. Not sure how that plays into violating the principle of least surprise.

@mlangenberg
Contributor

I think @unorthodoxgeek has a good point about using an MD5 or SHA of the stored serialized string. When reading a record from the database, before deserializing, computing the SHA1 of the attribute that is still in string form would be very quick and requires almost no additional memory.

On write, after serializing an attribute, we could compute the SHA1 of the to-be-stored string and compare it to SHA1 we calculated on read. Are they equal? No update of this column is needed.

The overhead of doing a SHA1(attr) is way less than the overhead of a database write. And since we are just comparing SHA1's of strings, there is no need to deep compare nested hashes, or to be afraid of .dup or .clone.

This doesn't require any changes to API's and is also backwards compatible.

@kbrock
Contributor
kbrock commented Jan 15, 2014

@mlangenberg Storing a hash/MD5/SHA1 has merit. It saves the call to .dup or .clone. (example #13428). The implementation can answer changed? and possibly changed_attribute?(attr). However, it can not answer changes, attr_was, changed_attributes, and similar methods. Those require the original value.

So an implementation that only stores a hash will never be complete: changed? == true, but changes == nil.

Maybe that is ok. The user did modify a variable in place after all. Currently, changed? == false and save actually writes to the database. So anything will be better.

If we implement a solution that uses dup or clone, we have a higher cost associated with duplicating the value. But methods like changed?, changed_attributes?(attr) and attr_was will all be implementable. (example #13606)

It is a trade off. Please add comments or an implementation so we can all bounce ideas off of each other.

@kbrock
Contributor
kbrock commented Jan 15, 2014

If anyone has ideas on how to get the remaining 3 tests on #13606 to pass please share over there. It tricky to know if a number changed from 0 to foo. I can't get that to pass and not break some of the date tests.

Thanks

@jonashuckestein

@kbrock and @schmurfy I suspect that changing the current behavior would upset many people who rely on it (even though you consider it a bug). Your solution only populates original_values upon attribute read/writes, which is good because it saves overhead. Unfortunately I've seen plenty of rails code that uses .attributes directly to access attributes. In that case your dirty tracking would silently fail.

I don't think it's necessary to make serialized fields magically act like normal fields; they will always be different and there is no ned to return the original value using _was. Keep in mind these serialized fields can be quite large and complex objects.

I'd suggest adding a way for developers to opt into more expensive dirty tracking for certain fields (as I and other developers have done for certain projects). The simplest form could look like this: serialize :my_serialized_field, dirty: :always (default, current behavior) or serialize :my_serialized_field, dirty: :never (requires calling _will_change). I'd also allow values dirty: :clone and dirty: :hash, which would store a copy or hash of the field value on initialization. It would then compare the field value (or hash thereof) before saving with that original value.

I haven't looked into rails 4 code much, but I'll see if I can whip something up to illustrate.

Maybe somebody from the rails team can weigh in. @jonleighton, do you mind commenting on this because you implemented the current behavior?

@kbrock
Contributor
kbrock commented Jan 21, 2014

@jonashuckestein I would love to see a gist even non-working code if you can.

Implementing dirty: :never and dirty: :always are a piece of cake. Storing the field name are a minor change, but easy enough.

Adding the dirty: :hash is easy enough. The part I didn't like is the whole changed?(attr) == true and changes[attr] == nil. Or introducing yet another concept with hash_changed?(attr) == true. If you have ideas for that, please comment on that pull request. Storing the hash on initialization goes contrary to the whole don't access the field. (didn't realize this until some cache access specs started failing on me) Should we store the hash of the @attribute[attr] and not the __send__(attr)?

Implementing dirty: :clone. I guess the same questions about initializing the value comes into play. I only did a partial implementation for this, but it felt like there were 2 different changes mechanisms here coming into play.

@jonashuckestein To be honest, the real solution is to move Dirty up the ancestor chain, so @changed_attributes is defined in Dirty. Maybe mix-in a different Dirty scheme or support many of them. I'll also look into that.

UPDATE: added Dirty changes via #13799

@jonashuckestein

@kbrock storing a hash or even a clone of the serialized value on initialization is fine, if the developer has explicitly opted into the behavior and knows how to turn it off. Another performance implication of dirty tracking serialized columns is the comparison/hash calculation on each save, which you can't avoid anyway. This is likely another reason the current behavior was implemented.

I'll take some time tomorrow to gist this

@mrrooijen

What's the status on this issue? This is a terrible issue. I see that @kbrock got #13799 pulled into master, but has anything else changed since then that remedies this? I'm running into race conditions where my worker processes keep reverting user configuration because it keeps saving the CLEAN state of that configuration (serialized attribute) in the background right after a user updated the configuration through the web interface. This bug basically causes data (i.e. user input) to be lost.

@sgrif
Member
sgrif commented May 31, 2014

This is doable after the refactoring I've done recently. I'll be submitting a fix some time this week.

@sgrif sgrif added a commit to sgrif/rails that referenced this issue Jun 1, 2014
@sgrif sgrif Detect in-place changes on mutable attributes on Active Model
We have several mutable types on Active Record now. (Serialized, JSON,
HStore). We need to be able to detect if these have been modified in
place. By storing the hashed value of the original attribute, we can
achieve this without significantly increasing memory usage or time for
dirty checking per-record.

fixes #8328
6fb5e10
@sgrif
Member
sgrif commented Jun 1, 2014

This issue is fixed in #15458

@sgrif sgrif added a commit to sgrif/rails that referenced this issue Jun 1, 2014
@sgrif sgrif Detect in-place changes on mutable attributes on Active Model
We have several mutable types on Active Record now. (Serialized, JSON,
HStore). We need to be able to detect if these have been modified in
place. By storing the hashed value of the original attribute, we can
achieve this without significantly increasing memory usage or time for
dirty checking per-record.

fixes #8328
c53c5c0
@matthewd matthewd closed this in #15674 Jun 13, 2014
@kbrock
Contributor
kbrock commented Jun 16, 2014

thanks @sgrif

@Fryguy
Contributor
Fryguy commented Jun 16, 2014

Great work @sgrif ... Glad to see this got merged in.

EDIT: Should really say thanks as well to the many others who contributed to this long-standing issue.

@schmurfy

Thanks !
long standing is quite an understatement ;)
glad to see it fixed.

@felixbuenemann
Contributor

This is currently broken with serialized binary columns. The changes hash will be populated after load, so it will still always be saved. See #16701 for details.
Update: It's fixed now, thanks @sgrif.

@steakchaser

Rails 4.2.0 still seeing this issue when parent -> child with accepts_nested_attributes_for and child record has serialize field with type specified as Array.

If I omit the class_name param from serialize, it works fine. If present, saving the parent causes a save on each child.

@sgrif
Member
sgrif commented Jan 5, 2015

@steakchaser Can you please open a new issue, with a reproducible script to demonstrate the issue, using this template? Ping me on the issue, and I'll look into it.

@Ajaxy
Ajaxy commented Feb 17, 2015

Which rails version should this be fixed in? Still facing in 4.1.6 and 4.2.0

@felixbuenemann
Contributor

Should be in 4.2.0, if you're still having problems open a new issue and maybe add a reference to this ticket.

@sgrif
Member
sgrif commented Feb 17, 2015

There's a few edge cases not handled in 4.2.0 which are fixed on 4.2.1. Please check on the 4-2-stable branch before opening a new issue, and provide a reproduction script using our template here: https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_master.rb

@sgrif
Member
sgrif commented Feb 17, 2015

(In a new issue, not as a comment on this one)

@lacco lacco added a commit to lacco/rails that referenced this issue Dec 9, 2015
@lacco lacco move logic for determining which attributes should be saved into own …
…method so that it can be overwritten

also read rails#8328 (comment)
6c4245d
@lacco lacco added a commit to lacco/rails that referenced this issue Jul 4, 2016
@lacco lacco move logic for determining which attributes should be saved into own …
…method so that it can be overwritten

also read rails#8328 (comment)
689c23d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment