Pull to refresh

Использование ActiveRecord без Rails

Reading time 5 min
Views 9.5K
Библиотеку для работы с базами данных ActiveRecord можно использовать и вне Rails.

Задача

Наш тестовый проект будет брать время восхода луны с Яндекс.Погода и сохранять ее в базу данных, используя ActiveRecord. Заодно посмотрим на работу с Nokogiri (хорошую замену hpricot).

Структура проекта

Мы будем использовать миграции, файл конфигураций database.yaml, Rakefile, базу данных sqlite (development.sqlite3), в общем, окружение приближенное к любимым рельсам.

Посмотреть на github.

image

Настройка соединения с БД и создание таблицы с помощью миграций

Для удобства конфигурация соединения с БД вынесена в отдельный файл lib/config/database.yml:
  1. adapter: sqlite3
  2. database: lib/db/development.sqlite3
А соединение с БД в lib/config/environment.rb:
  1. require 'rubygems'
  2. require 'active_record'
  3. require 'yaml'
  4.  
  5. # Загружаем файл настройки соединения с БД
  6. dbconfig = YAML::load(File.open(File.join(File.dirname(__FILE__), 'database.yml')))
  7.  
  8. # Ошибки работы с БД направим в стандартный поток (консоль)
  9. ActiveRecord::Base.logger = Logger.new(STDERR) # Simple logging utility. logger.rb -- standart lib
  10.  
  11. # Соединяемся с БД
  12. ActiveRecord::Base.establish_connection(dbconfig)

Подготовим миграцию БД для создания таблицы. Для простоты в ней всего два строковых поля: day и time:
  1. class CreateMoonRiseTimes < ActiveRecord::Migration
  2.   def self.up
  3.     create_table :moon_rise_times do |t|
  4.       t.string :day
  5.       t.string :time
  6.     end
  7.   end
  8.  
  9.   def self.down
  10.     drop_table :moon_rise_times
  11.   end
  12. end
Для выполнения миграции создадим rake-файл.
  1. require 'lib/config/environment.rb'
  2.  
  3. # Документация по rake docs.rubyrake.org
  4. # namespace -- rake.rubyforge.org/classes/Rake/NameSpace.html
  5.  
  6. namespace :db do
  7.   desc "Migrate the database"
  8.   task :migrate do
  9.     # выполнение всех миграций из lib/db/migrate,
  10.     # метод принимает параметры: migrate(migrations_path, target_version = nil)
  11.     # в нашем случае
  12.     # migrations_path = lib/db/migrate
  13.     # target_version =  ENV["VERSION"] ? ENV["VERSION"].to_i : nil
  14.     # миграция запускается как rake db:migrate VERSION=номер_версии
  15.     ActiveRecord::Migrator.migrate('lib/db/migrate', ENV["VERSION"] ? ENV["VERSION"].to_i : nil )
  16.   end
  17. end


Попробуем мигрировать:
  1. $ rake db:migrate VERSION=1

  2. (in /home/data/projects/ActiveRecord-without-Rails)
  3. ==  CreateMoonRiseTimes: migrating ============================================
  4. -- create_table(:moon_rise_times)
  5.   SQL (1.0ms)   CREATE TABLE "moon_rise_times" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "day" varchar(255), "time" varchar(255))
  6.    -> 0.0019s
  7. ==  CreateMoonRiseTimes: migrated (0.0020s) ===================================
  8.   SQL (0.1ms)   INSERT INTO schema_migrations (version) VALUES ('1')


Отлично. Миграция 001_create_moon_rise_times.rb создала таблицу moon_rise_times с полями day и time.

Извлечение данных и сохранение их в БД

Теперь надо найти какие-нибудь полезные данные для сохранения в базу данных. Для примера будем брать с сайта Яндекс.Погода время восхода Луны. Также можно вылавливать курсы валют, новости, значение кармы, etc...

Для начала создадим тестовый файл lib/test_search.rb ищущий нужные данные на Яндекс.Погода:
  1. # Файл с небольшим скприптом для тестирования работы nokogiri.
  2.  
  3. $KCODE = "u"
  4. require 'jcode'
  5. require 'rubygems'
  6. require 'open-uri'
  7. require 'iconv'
  8. require 'nokogiri'
  9.  
  10.  
  11. # Загрузим html-документ
  12. source = open("pogoda.yandex.ru/26063/details/")
  13.  
  14. # Создадим объект nokogiri из загруженного документа
  15. data = Nokogiri::HTML(source)
  16. # Извлечем все строки html-таблицы с помощью метода search и простого xpath-выражения
  17. # wiki.github.com/tenderlove/nokogiri
  18.  
  19.  
  20. =begin
  21. Фрагмент исходного html-файла, в котором надо найти дату восхода Луны :)
  22.  
  23. <th class="date" rowspan="4"><b title="">9</b> <span>июля</span></th>
  24.  
  25. =end
  26.  
  27. data_html = data.search("th[@class = date]//b").first.inner_html + " " + data.search("th[@class = date]//span").first.inner_html
  28. puts data_html
  29.  
  30. =begin
  31. Фрагмент исходного html-файла, в котором надо найти время восхода Луны в день, определенный выше :)
  32.  
  33. <td class="dawn-dark" rowspan="4">
  34.     <dl>
  35.        <dt>Восход</dt>
  36.        <dd>04:52</dd>
  37.        <dt>Заход</dt>
  38.        <dd>23:15</dd>
  39.     </dl>
  40. <img src="//i.yandex.st/weather/i/moon/07.gif" alt="Убывающая луна" title="Убывающая луна">
  41. </td>
  42.  
  43. =end
  44.  
  45. time_html = data.search("td[@class = dawn-dark]//dl//dd").first.inner_html
  46. puts time_html


Получаем:
  1. $ ruby lib/test_search.rb
  2. 10 июля
  3. 04:53

Ок, то, что нам нужно.
Теперь надо сохранить полученные данные в БД. Для этого в ActiveRecord::Base есть метод create

Файл, выполняющий главную работу, lib/main.rb:
  1. $KCODE = "u"
  2. require 'jcode'
  3. require 'rubygems'
  4. require 'active_record'
  5. require 'yaml'
  6. require 'logger'
  7. require 'open-uri'
  8. require 'iconv'
  9. require 'nokogiri'
  10.  
  11.  
  12. # загружаем файл environment.rb настройки и соединение с БД
  13. require File.join(File.dirname(__FILE__), 'config/environment.rb')
  14.  
  15. # Создаем класс MoonRiseTime, обертывающий таблицу moon_rise_times
  16. # Ячейки таблицы: day -- тип data, rise_times -- тип time
  17. #
  18.  
  19. class MoonRiseTime < ActiveRecord::Base
  20. end
  21.  
  22. MoonRiseTime.create do |moon_rise_time|
  23.   # Загрузим html-документ
  24.   source = open("pogoda.yandex.ru/26063/details/")
  25.  
  26.   # Создадим объект nokogiri из загруженного документа
  27.   data = Nokogiri::HTML(source)
  28.   # Извлечем все строки html-таблицы с помощью метода search и простого xpath-выражения
  29.   # nokogiri.org/Nokogiri/XML/Node.html#method-i-inner_html
  30.  
  31.  # :TODO:  Привести типы данных к data и time
  32.  # Находим в исходном html дату
  33.   data_moon_rise = data.search("th[@class = date]//b").first.inner_html
  34.   month_moon_rise = data.search("th[@class = date]//span").first.inner_html
  35.  
  36. # передаем найденные данные методам класса-обертки БД
  37.   moon_rise_time.day = data_moon_rise + " " + month_moon_rise
  38.  
  39.   moon_rise_time.time = data.search("td[@class = dawn-dark]//dl//dd").first.inner_html
  40. end

Запустим его:
  1. ruby lib/main.rb
  2.   MoonRiseTime Create (0.4ms)   INSERT INTO "moon_rise_times" ("time", "day") VALUES('04:53', '10 июля')


Вроде все хорошо.

Посмотрим, что сохранилось в базе с помощью небольшого скрипта lib/test_fetch_data.rb:
  1. # Файл с небольшим скприптом для тестирования
  2. # извлечения данных из таблицы moon_rise_times.
  3.  
  4. # загружаем файл настройки и соединеняемся с БД в файле environment.rb
  5. require File.join(File.dirname(__FILE__), 'config/environment.rb')
  6.  
  7. # Создаем класс MoonRiseTime, обертывающий таблицу moon_rise_times
  8. # Ячейки таблицы: day, time -- тип string
  9.  
  10. class MoonRiseTime < ActiveRecord::Base
  11. end
  12.  
  13. # Извлекаем все записи из БД в fetch_result
  14. fetch_result = MoonRiseTime.all
  15.  
  16. # Выводим на экран fetch_result
  17. fetch_result.each do |result_item|
  18.   puts result_item.id
  19.   puts result_item.time
  20.   puts result_item.day
  21. end

Вывод:
  1. $ ruby lib/test_fetch_data.rb
  2.   MoonRiseTime Load (0.5ms)   SELECT * FROM "moon_rise_times"
  3. 1
  4. 04:53
  5. 10 июля

Ок! Теперь, запуская каждый день нашу программу можно следить за временем восхода луны!

Использованные материалы

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+16
Comments 16
Comments Comments 16

Articles