2015-12-20 3 views
3

Учитывая эту простую модель:запись существует, когда он не

class Article < ActiveRecord::Base 

    validates :title, presence: true 
    validates :url, presence: true, uniqueness: true 
    validates :topic, presence: true 

    before_create :some_filter 

private 

    def some_filter 
    self.noframe = false 
    end 
end 

И тот факт, что нет:

  • нет наблюдателей
  • без индексов на колонке "noframe"

Как это возможно?

attrs = { title: "a", url: "http://www.example.com", topic: "test" } 

Article.where(attrs).count 
=> 0 

Article.where(url:"http://www.example.com").count 
=> 0 

article = Article.new(attrs) 
article.save 

(0.2ms) BEGIN 
Article Exists (0.6ms) SELECT 1 AS one FROM "articles" WHERE "articles"."url" = 'http://www.example.com' LIMIT 1 
(0.3ms) ROLLBACK 

article.errors.full_messages 
[] 

отладчик

При установке отладчик внутри метода "some_filter", это то, что происходит.

[12] pry(#<Article>)> self.noframe = nil 
=> nil 

[13] pry(#<Article>)> self.valid? 
    Article Exists (0.5ms) SELECT 1 AS one FROM "articles" WHERE "articles"."url" = 'http://www.example.com' LIMIT 1 
=> true 

[14] pry(#<Article>)> self.noframe = false 
=> false 

[15] pry(#<Article>)> self.valid? 
    Article Exists (0.5ms) SELECT 1 AS one FROM "articles" WHERE "articles"."url" = 'http://www.example.com' LIMIT 1 
=> true 

[16] pry(#<Article>)> self.save 
    Article Exists (0.5ms) SELECT 1 AS one FROM "articles" WHERE "articles"."url" = 'http://www.example.com' LIMIT 1 
=> false 

Более подробная информация

Чтобы сделать его более интересным, когда я изменяю «some_filter», чтобы установить noframe либо ноль, либо правда, я могу создать столько записей, сколько я хочу без «Статья Exists " ошибка.

Он также работает, когда я устанавливаю атрибут noframe напрямую, а не внутри фильтра before_create.

Почему это обходное решение работает?

Я могу «исправить» его, заменив «before_create» на «after_create» и обновив атрибут noframe дополнительно с помощью update_attributes (noframe: false). Но почему это решение? update_attributes также вызывает все обратные вызовы и проверку, поэтому почему это не работает в before_create?

ответ

5

before_create имеет одно не очевидное свойство - если оно возвращает ложное значение, оно завершает целую цепочку сохранения. То же самое относится ко всем обратным вызовам before-*. Вы можете найти его в callback documentation. Ваш метод возвращает false, поэтому вся транзакция возвращается. Измените его на:

def some_filter 
    self.noframe = false 
    true 
end 

И все будет работать.

+0

Имеет смысл. Тем не менее, менее сложное сообщение об ошибке будет приятным. Я подал сообщение об ошибке: https://github.com/rails/rails/issues/22713 – Sergey

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