Rails: как лучше всего проверить, не существует ли запись в базе данных? - PullRequest
3 голосов
/ 23 ноября 2010

Мой метод загружает список стран (код, название) в базу данных, но перед этим он должен проверить, если данные о стране еще не существуют. Это отлично работает:

 def self.load_countries
    get_countries.each do |country|
      code, name = country
      if find_by_code(code).nil?
        create({ 'name' => name, 'code' => code })
      end
    end
  end

Однако, поскольку я новичок в Ruby, я хочу изучить лучшие практики. Итак, в этом коде я не уверен в двух вещах, которые могут быть (или не могут быть) оптимизированы:

  1. find_by_attribute возвращает оператор "select * from table". В этом случае, когда мне не нужны какие-либо данные из базы данных - я просто хочу знать, существует запись или нет - выбор всей строки кажется мне немного неэффективным. Есть ли лучший способ решить эту проблему? Например, «выбрать 1 из таблицы, где ...» с помощью ActiveRecord?
  2. Этот вопрос может быть глупым, но я хочу быть уверенным: когда я запускаю цикл с get_countries.each, нормально ли использовать метод вместо переменной? Разве один и тот же метод не называется каждым циклом (N раз)? Другими словами, будет ли это более эффективным:

    страны = get_countries

    страны. Каждая страна | страна |

Любые комментарии к этим нескольким строкам кода приветствуются, поскольку тот факт, что он работает, не обязательно означает, что я делаю это правильно.

Спасибо.

Ответы [ 7 ]

10 голосов
/ 23 ноября 2010

Вы можете использовать существующий? функция в ActiveRecord.

def self.load_countries
  get_countries.each do |country|
    code, name = country
    unless exists?(:code => code)
      create({ :name => name, :code => code })
    end
  end
end

Функция get_countries вызывается только один раз. Он возвращает перечислимый тип данных, а затем каждый просматривает каждый из них.

3 голосов
/ 23 ноября 2010

Использование find_or_create_by

get_countries.each do |country|
  code, name = country
  find_or_create_by_code_and_name(code, name)
end
1 голос
/ 17 мая 2018

В Ruby on rails у нас есть четыре способа проверить, существует ли запись в базе данных или нет?

  1. .present

    Это самый трудоемкий метод, поскольку он возвращает все записи из базы данных.

  2. .any? / .empty?

    Оба вышеупомянутых варианта имеют одинаковую эффективность, поскольку оба они в конце концов запускают запрос «COUNT» в базе данных. Следовательно, оба они эффективны по сравнению с .present?

  3. .exist

    Последний вариант еще более оптимизирован, и он должен быть вашим первым выбором при проверке существования записи. Используется подход «ВЫБОР 1 ... ЛИМИТ 1».

Помните одну вещь, когда ваши объекты ActiveRecord уже находятся в памяти (если вы предварительно загрузили их), тогда не используйте 'существующие? лучше использовать «любой?», так как «существует?» всегда обращайтесь к базе данных в отношении того, находится ли объект в памяти или нет, тогда как 'any? / пусто? Заполнить не ударить базу данных снова, если записи уже загружены в память.

Вы также можете обратиться к этой статье: Проверить, существует ли запись в ROR

1 голос
/ 23 ноября 2010

1) Добавьте проверку уникальности в вашу модель (при условии, что Rails 3)

validates :code, :uniqueness => true

Используйте db / seeds.rb для загрузки начальных данных в базу данных.ИМХО метод load_countries не относится к модели (особенно если это однократная операция).

0 голосов
/ 23 ноября 2010

1.) Вам не обязательно выделять всю строку, и вы можете использовать опцию: select =>, чтобы ограничить выборку столбцов, но мне это кажется микрооптимизацией.Я бы не беспокоился об этом.Если эффективность этого метода вас сильно беспокоит, вам лучше найти способ избежать выполнения SQL-запроса в цикле;например, рассмотрите возможность выбора всех существующих стран перед циклом, сохранения их в массиве или хэше и использования этого, чтобы увидеть, существует ли страна уже.Тогда вместо десятков поездок в базу данных вы сделаете только одну (не считая тех, где вы добавляете новые записи).С другой стороны, это не похоже на тот код, который вы собираетесь запускать много раз (это похоже на случай заполнения таблицы базы данных), поэтому он может не иметь большого значения.

2.) Нет, метод get_countries не будет вызываться на каждой итерации цикла, только один раз перед запуском #each;Предполагая, что get_countries возвращает массив, #each является методом в массиве.

0 голосов
/ 23 ноября 2010

Вы можете использовать уникальную проверку в вашей модели ActiveRecord, например:

class Country < ActiveRecord::Base
  validates_uniqueness_of :code
  validates_uniqueness_of :name
end
0 голосов
/ 23 ноября 2010

Может быть, вам нужно использовать UNIQUE для кодов в вашей модели базы данных?

Я имею в виду это http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000086

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...