Thanks for answer. I understood, this is planned behaviour. But there are 
some issues with it:

1. it changed silently in minor release, so some code no more works as 
expected. This is not problem with single application but may be problem 
with framework-based application when framework requires Sequel. As for me 
I got bug with NULL in new record while I tested same code before and got 
"[]" (empty js-array) in same cell.

2. it confuse hooks logic:
class Test < Sequel::Model(:tests)
    plugin :serialization, :json, :data

    def before_save
        self.data ||= []
        self.name ||= 'bar'
        super
    end
end


t = Test.create()
p t

will return #<Test @values={:id=>1, :name=>"bar", :data=>nil}>
ie :name field was changed but :data was not! Not intuitive.

3. As for auto_validations plugin. I consider there are two types of 
possible validation: high-level (for unserialized data) and low-level (for 
raw data before put it to DB). High-level validation can be applied to be 
sure username filled or be sure currency specified with price. Low-level 
validation can be applied to sure raw data correct according DB/schema 
requirements. Thus rational save sequence is: high-level validation -> 
before_save modification -> serialization -> low-level validation -> query. 
Auto_validations plugin is low-level.

4. Just a question. Why _before_validation, not before_validation?


понедельник, 19 января 2015 г., 4:04:02 UTC+10 пользователь Jeremy Evans 
написал:
>
> On Saturday, January 17, 2015 at 9:40:25 PM UTC-8, Valentin Syrovatskiy 
> wrote:
>>
>> Hi, Jeremy!
>>
>> Gemfile:
>> source 'https://rubygems.org'
>>
>> gem 'sequel', '4.12'
>> gem 'sqlite3'
>>
>>
>>
>> test.rb:
>> require 'rubygems'
>> require 'bundler/setup'
>> require 'sequel'
>> require 'json'
>>
>>
>> Sequel::Model.db = Sequel.sqlite
>>
>> Sequel::Model.db.create_table(:tests){
>>     primary_key :id
>>     varchar     :name
>>     text        :data
>> }
>>
>> class Test < Sequel::Model(:tests)
>>     plugin :serialization
>>     serialize_attributes :json, :data
>>
>>     def before_save
>>         self.data ||= [1, 2]
>>         super
>>     end
>> end
>>
>> p Sequel::VERSION
>>
>> t = Test.create(name: 'foo')
>> p t
>>
>> Now I open console, run 'bundle install', then 'ruby test.rb' and got
>>
>>
>>
>> *"4.12.0"#<Test @values={:id=>1, :name=>"foo", :data=>"[1,2]"}>*
>>
>> But with sequel 4.13 up to 4.18 (change in Gemfile) with 'ruby test.rb' i 
>> got
>>
>>
>> *"4.18.0"#<Test @values={:id=>1, :name=>"foo", :data=>nil}>*
>>
>> Is this behaviour correct or this is a bug?
>>
>
> I consider the current behavior correct.  The behavior was changed in 
> 4.13.0 because when was serializing the data after before_save, Sequel 
> couldn't correctly run validations on the underlying columns, which made 
> serialization difficult to use with auto_vaildations.  So Sequel needs to 
> serialize before validation, not after, and before_save happens after 
> validation.  So modifying a deserialized value in before_save no longer has 
> an effect on the current save, since the serialization of the column has 
> already been done.
>
> If you want to add something to a serialized column before it is 
> serialized, you should switch to the _before_validation hook, which is 
> called on every save, before validation (if any) is done:
>
>   def _before_validation
>    self_data ||= [1, 2]
>     super
>   end
>
> You aren't the first person to bring this up as an issue.  As I've 
> mentioned in previous posts, I'm open to making the old behavior available 
> via an option.  However, since it is fairly easy to switch to the new 
> behavior, there doesn't seem to be much reason to do so.
>
> Thanks,
> Jeremy
>

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.

Reply via email to