2014-11-11 3 views
0

Мне нужно установить по умолчанию (из удаленной службы) в ModelA, чтобы объект был передан в представление с ModelAController#new. Для этого я использовал after_initialize. Однако в #create у меня проблема. Если я использую model_b.create_model_a(some_attributes), атрибуты передаются в процессе инициализации, а затем переписывается after_initialize вызова:Установите значения по умолчанию для activerecord перед инициализацией массового присвоения

class ModelA < ActiveRecord::Base 
    after_initialize :set_defaults, if: :new_record? 

    def set_defaults 
    self.c = "default" 
    #actually a remote call, not something can be set as database default 
    end 
end 

class ModelB < ActiveRecord::Base 
    belongs_to :model_a 
end 

class ModelAController < ApplicationController 
    #ModelA is nested under ModelB in routes.rb 

    #GET /model_bs/:model_b_id/model_as/new 
    def new 
    model_b = ModelB.find(params[:model_b_id]) 
    #no problem 
    respond_with model_b.build_model_a 
    end 

    #POST /model_bs/:model_b_id/model_as 
    def create 
    model_b = ModelB.find(params[:id]) 
    #problem: 
    respond_with model_b.create_model_a({c: "not default"}) 
    #at this point the model_a instance still has attribute c set to "default" 
    end 
    ... 
end 

Я мог бы отделить создать шаги:

model_b = ModelB.find(params[:id]) 
model_a = model_b.build_model_a #should fire after_initialize 
model_a.update_attributes({c: "not default"}) #overwrite default c value 

Но я чувствую, как это делает жизненный цикл ModelA немного ловушка для других программистов. Это выглядит как очевидный кандидат на рефакторинг последних двух строк в один, но это снова создало бы эту проблему. Есть ли более аккуратное решение?

ответ

1

Сделать условное назначение:

def set_defaults 
    self.c ||= "default" 
end 

В качестве альтернативы вместо after_initialize крюк установлен по умолчанию в считывателем атрибута. Таким образом, вы устанавливаете значение по умолчанию только в том случае, когда вам действительно нужно значение атрибута, поэтому оно сохраняет ваш удаленный вызов, если он вам не нужен:

def c 
    super || self.c = 'default' 
end