Em quinta-feira, 19 de abril de 2012 15h50min13s UTC-3, Jeremy Evans escreveu: > > On Thursday, April 19, 2012 9:43:49 AM UTC-7, Rodrigo Rosenfeld Rosas > wrote: > >> For example, take a look at this AR model excerpt: >> >> after_update :remove_options_if_changed_type_was_options >> private >> def remove_options_if_changed_type_was_options >> options.clear if type_changed? && type_was == 'options' >> end >> >> I've even asked for a type_was? method in a Rails pull request at that >> time: >> >> https://github.com/rails/rails/pull/5763 >> > > Sequel currently doesn't provide a similar feature, as it doesn't save > previous values of columns. It's probably not difficult to add a plugin > that would do so, though. > > >> So, I tried this to get a similar result in Sequel: >> >> private >> def after_update >> super >> options_dataset.delete if type_was_options? >> end >> >> def data_type_was_options? >> changed_columns.include?(:type) && type != 'options' >> end >> > Yes, I know about the warnings in the documentation: >> >> "This isn't completely accurate, as it could contain columns whose values >> have not changed." >> > > "isn't completely accurate" refers to this: > > m = Model.new(:name=>'a') > m.changed_columns # => [] > m.name = 'b' > m.name = 'a' > m.changed_columns # => [:name] >
I guessed so. That is ok because that would never happen in my controllers or in any web applications in normal use cases. For example, if you have an update action it will only try to set to the values passed in the parameters. Usually there would be no reason to set some value twice... At least, this doesn't happen in my particular controller action. > I think ActiveModel::Dirty has the same issue, though that could > theoretically be fixed as it has access to the initial value. > > Although not ideal, that is ok. But the issue is that my spec won't pass. >> When I try to print "changed_columns" it is empty. Maybe this information >> is reset after a save. >> > > changed_columns is cleared during the save. Note that you can access > @columns_updated inside the after_update hook to get the data used in the > UPDATE statement. > I'm afraid of accessing this internal variable since it is not in the API public documentation and so it could change in future versions. Maybe if you could document it in the official documentation of Model Hooks, I could use it. > However, even if you did that, I'm not sure if your Sequel code would do > what you want. > For my particular case, even this would work: options_dataset.delete unless type == 'options' See? It is just an optimization because there won't be any values to be deleted if the type hasn't changed and it was not 'options'. So I'd just be avoiding the DELETE query and avoid polluting my database log. So, even if the changed_columns is not accurate in my particular case, it wouldn't be a problem at all. I'd just issue an unneffective unneccessary DELETE in the situation you mentioned. Do you want to run options_dataset.delete only if the value of the type > column was changed from "options" to something else during the update? > That is the idea. > > >> I've read somewhere in this group that such feature wasn't requested >> before, so I'm requesting it now :P >> >> Could I ask you to include an official "dirty" plugin for Sequel::Model? >> One that would even work in after-hooks? And that would be completely >> accurate whatever it means? >> > > I'm not opposed to adding one. It will probably not be exactly like > ActiveModel::Dirty, though. I'll probably just give the ability to get the > previous value, so you could do: > > def after_update > super > options_dataset.delete if type_was_options? > end > > def type_was_options? > initial_value(:type) == 'options' && @columns_updated[:type] != > 'options' > end > > I do like the idea of having access to the initial value of some column. That would suffice in my opinion. But I'd write type_was_options? in a more compact way though ;) type != 'options' && initial_value(:type) == 'options' Note that if you have such an option, a better way to do what you want is > using a database trigger. > I do have this option, as I'm using PostgreSQL, but I'd really prefer to get this kind of constraint in the application side for maintainability sake :) Also, the application under production is still in top of MySql, while the one at QA was already converted to PostgreSQL. I'm still trying to convince my employers not to worry about the migration as we had no problem in the QA server ;) But that is to say that sometimes having constraints in the application side is also useful. If you're going to migrate your database for example, you'd not have to convert your triggers from the old database to the new one :) While on the subject, while I agree that setting "CASCADE DELETE" is a better option for handling cascading, some "databases" won't allow you to do so. For example my production database of this application I'm maintained (which wasn't chosen by me) is MySql and is not using the InnoDB engine. That means it doesn't support foreign keys. So ActiveRecord is able to handle that by providing the "dependent: :delete_all" to the association method. So, you might be interested in considering such an option for those "databases" that do not support foreign keys (I guess this is only MySql with default engine as far as I can tell you). With regards to PostgreSQL, I gave sequel_pg a try but I couldn't notice any difference on my specs run total time. On the other hand, they were taking about 1.1s with ActiveRecord and now they're taking about 0.6s and that was awesome! :D Thank you very much :) Rodrigo. -- You received this message because you are subscribed to the Google Groups "sequel-talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/sequel-talk/-/1sHhgEy6y-0J. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sequel-talk?hl=en.
