2016-04-06 2 views
0

У меня есть две модели:Weird поведение has_one после обновления до Rails 4.2.6

class User < ActiveRecord::Base 
    belongs_to :group, dependent: :destroy 

    validates :login, presence: true 

    before_create :add_group 

    private 

    def add_group 
    create_group(name: login) 
    end 
end 

и

class Group < ActiveRecord::Base 
    has_one :user 
end 

При попытке создать пользователя, я получаю SystemStackError: stack level too deep. Поэтому я изменил add_group обратного вызова, как это:

def add_group 
    create_group(name: login) unless group 
end 

Теперь он сохраняет имя пользователя и правильно установить GROUP_ID, но также создать вторую пустую запись пользователя без проверки. SQL:

>> u = User.create!(login: "foo") 
    (0.7ms) BEGIN 
    SQL (2.2ms) INSERT INTO "groups" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "foo"], ["created_at", "2016-04-06 10:09:52.981954"], ["updated_at", "2016-04-06 10:09:52.981954"]] 
    Group Load (1.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" = $1 LIMIT 1 [["id", 1453]] 
    SQL (2.0ms) INSERT INTO "users" ("login", "created_at", "updated_at", "group_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["login", "foo"], ["created_at", "2016-04-06 10:09:52.923926"], ["updated_at", "2016-04-06 10:09:52.923926"], ["group_id", 1453]] 
    SQL (1.4ms) INSERT INTO "users" DEFAULT VALUES RETURNING "id" 
    (9.1ms) COMMIT 

Последние INSERT INTO таблицы пользователей нечетное. я не могу понять, почему это происходит ...

Я нашел два решения:

class Group < ActiveRecord::Base 
    has_one :user, autosave: false 
    ##OR## 
    has_one :usr, class_name: "User" 

    # has_one :user, class_name: "User" works weird too 
end 

но это не убеждает меня.

Что может быть неправильным? в Rails 4.0 все работает хорошо.

UPDATE 1

нормально, я нашел еще 2 решения:

class User < ActiveRecord::Base 
    belongs_to :group, dependent: :destroy 

    validates :login, presence: true 

    before_create :add_group 

    private 

    def add_group 
    self.group = Group.create(name: login) 
    # OR # 
    assign_attributes(group: Group.create(name: login)) 
    end 
end 

class Group < ActiveRecord::Base 
    has_one :user 
end 

, но до сих пор я не понимаю, почему он ведет себя так странно ... особенно этот дополнительный пустой запись и зафиксировать с помощью has_one :usr, class_name: "User"

+0

Вы пытались изменить before_create: add_group, after_create? – fanta

+0

да, но тогда у меня есть еще одна проблема: create_group in after_create запускает обратные вызовы after_update, что усложняет многие вещи –

+0

И я не могу создать пользователя, если группа создания не работает –

ответ

0

Вы должны только строить ваша группа и AR сохраняются для вас:

class User < ActiveRecord::Base 
    belongs_to :group, dependent: :destroy 

    validates :login, presence: true 

    before_create :add_group 

    private 

    def add_group 
    build_group(name: login) 
    end 
end 

При вызове create_group он снова перезапустит повторные проверки AR и, следовательно, перезапустит ваш крючок before_create.

+0

Я пытаюсь, но она не сохраняет группу, хотя она действительна (даже с собственностью: group: autosave: true) –

+0

И я думаю, вы имеете в виду 'build_group (name: login)', потому что 'группа' на данный момент' nil' :) –

+0

Абсолютно, спасибо! Я отредактирую свой ответ. Что касается того, почему он не работает ... '@ user.save!' Должен на самом деле упорствовать. Не могли бы вы добавить 'binding.pry' в обратном вызове' add_group' и попытаться запустить код, чтобы узнать, что происходит? – born4new

0

ответ здесь: autosave: false

Это означает, что при добавлении группы к пользователю, рельсы назначает де group_id для пользователя (belongs_to), поэтому пытается спасти от объекта снова, я полагаю, что из-за вас все еще находятся в поведении create, что #save снова запускает after_create, и вы слишком глубоко получаете уровень стека.

group.create(name: login) вместо этого.

+0

Я могу понять уровень стека слишком глубоко, но почему во второй версии (с исключением) он создает второй пустой объект без проверки? –

+0

'group.create (name: login)' is eql to 'nil.create (name: login)' - мы можем сделать это так: 'build_group (name: login) .save', но он дает нам тот же результат, что и 'create_group',' group = Group.create() 'и т. д. –

Смежные вопросы