Re: STI, #update_attributes and validations.

22 views
Skip to first unread message

Emily S

unread,
Jan 16, 2013, 1:55:39 PM1/16/13
to rubyonra...@googlegroups.com
Why are you doing
b = A.find("b-id") and not b = B.find("b-id") ?

I think it would be better if you did

b = B.find("b-id")
c = b.becomes(C)

try it in the console and verify that c.class is C

then you should be able to do
c.update_attributes(:attribute_x => 'present', :attribute_y => 'present')

Your validations will fail if you expect Rails to make the update to an object of class B without attribute_z, which is what you're doing here:
 b.update_attributes({ 'type' => 'C', :attribute_x => 'present', :attribute_y => 'present', :attribute_z => nil }) 

You need b to be of class C if you want your validations to pass.



On Monday, January 14, 2013 1:34:29 PM UTC-5, Guilherme Reis wrote:
I would like to know if there's a way to when doing STI the update_attributes, validate the attributes based on the new class type?

For e.g. suppose i have: 

    class A < ActiveRecord::Base
    end
    class B < A
        validates :attribute_z, :presence => true
    end 
    class C < A
        validates :attribute_x, :presence => true
        validates :attribute_y, :presence => true 
    end

If i run (the way rails is implemented):

    b = A.find('b-id')
    b.update_attributes({ 'type' => 'C', :attribute_x => 'present', :attribute_y => 'present', :attribute_z => nil }) # will return false with errors on 'attribute_z must be present'
    

    b = A.find('b-id')
    b = b.becomes(C)
    b.update_attributes({ 'type' => 'C', :attribute_x => 'present', :attribute_y => 'present', :attribute_z => nil })
    # this works partially, because the validations are ok but when i look to console i get something like: 
    UPDATE "as" SET "type" = 'c', "attribute_z" = NULL, "attribute_y' = 'present', 'attribute_x' = 'present' WHERE "as"."type" IN ('C') AND "as"."id" = 'b-id' 
    # which is terrible because it's looking for a record of B type on the C types.

i could put :if => proc { |record| record.type == 'C' } on the validations and put the validations at A class. But it wouldn't make sense to have the subclasses. The difference basically of B and C is only in the validation behavior. (I have many validations on both types)

Matt Jones

unread,
Jan 17, 2013, 10:56:27 AM1/17/13
to rubyonra...@googlegroups.com


On Monday, 14 January 2013 13:34:29 UTC-5, Guilherme Reis wrote:
 
i could put :if => proc { |record| record.type == 'C' } on the validations and put the validations at A class. But it wouldn't make sense to have the subclasses. The difference basically of B and C is only in the validation behavior. (I have many validations on both types)

Are you positive A, B and C should really be separate classes? The fact that there are transitions that change classes makes it sound a lot like there's really a statemachine here, not a class hierarchy...

--Matt Jones

Reply all
Reply to author
Forward
0 new messages