#ruby-on-rails #ruby #ruby-on-rails-4 #activerecord
#ruby-on-rails #ruby #ruby-on-rails-4 #activerecord
Вопрос:
Недавно я переключил свое приложение Rails 4.2 с ruby 2.0.0 на 2.3.0, и когда я запускаю свой rails-сервер ($ rails s), только что появилось новое уведомление
/home/app/models/user.rb:127: warning: key :numericality is duplicated and overwritten on line 128
/homeapp/models/user.rb:127: warning: key :on is duplicated and overwritten on line 128
/home/app/admin/user.rb:142: warning: key :collection is duplicated and overwritten on line 147
/home/app/models/deal.rb:223: warning: key :numericality is duplicated and overwritten on line 226
/home/app/models/deal.rb:234: warning: key :numericality is duplicated and overwritten on line 237
Вот пример строки, вызывающей проблемы, это те, в которых при создании учетной записи я устанавливаю атрибут nb равным 3 (on: :create), и пользователь в течение срока действия своей учетной записи может увеличить количество разрешений, но никогда не сможет иметь большечем 7 (on: :update).
validates :nb_of_permissions,
presence:true,
numericality: { equal_to: 3 }, on: :create,
numericality: { less_than_or_equal_to: 7 }, on: :update
Что я должен изменить?
Спасибо
Комментарии:
1. Проблема / ошибка всегда была. Просто теперь вы можете это увидеть. 🙂
2. У меня было такое чувство:) спасибо Rails / ruby за строгие соглашения и уведомления 🙂
Ответ №1:
Основное отличие здесь в том, что обновление Ruby сообщает вам об ошибке в вашем приложении, которая ранее оставалась незамеченной. numericality: { less_than_or_equal_to: 7 }, on: :update
На самом деле когда-либо использовался только второй.
irb(main):001:0> { foo: 1, foo: 2 }
(irb):1: warning: key :foo is duplicated and overwritten on line 1
=> {:foo=>2}
Используйте validates :att, {}
, когда у вас есть относительно простые условия.
Поскольку ваши проверки применяются к разным событиям жизненного цикла, вы должны объявлять каждое из них как отдельную проверку.
validates :nb_of_permissions, { presence: true }
validates_numericality_of :nb_of_permissions equal_to: 3, on: :create
validates_numericality_of :nb_of_permissions less_than_or_equal_to: 7, on: :update
Тестирование базовых костей проверки модели на самом деле довольно просто (хотя и не так гладко, как с Shoulda-Matchers):
RSpec.describe Thing do
describe "validations"
describe "#nb_of_permissions" do
context "when updating" do
let(:thing) { Thing.create(nb_of_permissions: 3) }
let(:errors) { thing.valid?.errors[:nb_of_permissions] }
it 'is must be present' do
thing.nb_of_permissions = nil
expect(errors).to include 'must be present.'
end
it 'is must be at least 7' do
thing.nb_of_permissions = 10000
expect(errors).to include "must be less than or equal to 7"
end
end
end
end
end
Комментарии:
1. PS. У вас действительно должен быть где-то тест, который гарантирует, что обе проверки будут применены
nb_of_permissions
, если это важно для вашего приложения.2. @Mathieu: думаю, ваши тесты ничего не тестировали 🙂
3. ОК. в этом случае вы должны закомментировать обе строки и убедиться, что у вас есть по крайней мере два сбоя теста, поскольку ваши тесты вообще не охватывают его.
4. на самом деле у меня были тесты, но я закомментировал, поскольку мне так и не удалось заставить их работать для on: update. это было что-то вроде: validate_numericality_of(:max_nb).only_integer.is_less_than_or_equal_to(90).on(:update) / сбой, и у других людей такая же проблема: github.com/thoughtbot/shoulda-matchers/issues/678
5. Добавлен пример того, как выполнить тест проверки модели без shoulda-matchers. Если вы используете FactoryGirl, вы можете использовать
build_stubbed
для сценария обновления, поскольку он подделывает сохранение, поэтомуon: update
вызывается проверка.
Ответ №2:
Вы должны попробовать это
validates :nb_of_permissions, presence:true, numericality: { equal_to: 3 }, on: :create
validates :nb_of_permissions, presence:true, numericality: { less_than_or_equal_to: 7 }, on: :update
Комментарии:
1. круто, что это сработало. просто сопутствующий вопрос: тогда, если при создании у меня есть presence: true, если подразумевает, что при обновлении оно, конечно, уже присутствует, тогда, может быть, в вашей второй строке предложения при обновлении мне не нужно будет снова проверять, что presence = true?
2. Нет, вы либо разделяете проверки наличия и численности, как в моем ответе, либо добавляете проверку наличия к обоим. Если вы удалите
presence: true
во второй строке, это позволит вам обновить значение nil дляnb_of_permissions
из-за способаvalidates_numericality_of
работы.3. Вам нужно проверить наличие, если это необходимо для существования. После всех nb_of_permissions потенциально может быть установлено значение null перед вызовом update.
Ответ №3:
Ваш старый код был ошибочным и не выполнял то, что вы думаете. Здесь не произошло никаких изменений в поведении; вам просто показывают полезное предупреждение, чтобы выделить вероятную ошибку!
Рассмотрим следующий простой пример:
hash = {a: 1, a: 2}
В версиях Ruby 2.0 и 2.3 это эквивалентно простому определению:
hash = {a: 2}
… Потому что хэш-ключ переопределяется. Аналогично, ваш код:
validates :nb_of_permissions,
presence:true,
numericality: { equal_to: 3 }, on: :create,
numericality: { less_than_or_equal_to: 7 }, on: :update
… Это и всегда было эквивалентно простой записи:
validates :nb_of_permissions,
presence:true,
numericality: { less_than_or_equal_to: 7 },
on: :update
Существует несколько способов сделать это, но, например, вы можете исправить эту ошибку, определив две проверки, такие как:
validates :nb_of_permissions,
presence:true,
numericality: { less_than_or_equal_to: 7 },
on: :update
validates :nb_of_permissions,
presence:true,
numericality: { equal_to: 3 },
on: :create