Undr

На память

Записи с меткой ‘rails’

Тестирование модулей с помощью RSpec

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (1 голосов, средний: 5.00 из 5)
Loading ... Loading ...

К примеру, у нас есть такой модуль, который мы добавляем в классы Airport, City:

  module Nameable
    extend ActiveSupport::Concern
   
    module InstanceMethods
      def name locale=:en
        locale = :en if !name_ru || name_ru.empty?
        send(name_method(locale))
      end
   
      def localized_name
        name(I18n.locale || :en)
      end

      private
      def name_method locale=:en
        "name_#{locale}".to_sym
      end
    end
   
    included do
      field :name_en, :type => String
      field :name_ru, :type => String
      validates_presence_of :name_en
    end
  end
  class Airport
    include Mongoid::Document
    include Nameable
  end
  class City
    include Mongoid::Document
    include Nameable
  end

Чтобы протестировать модуль, для него нужно создать shared_examples_for блок:

  shared_examples_for :Nameable do  
    it{should have_fields(:name_en).of_type(String)}
    it{should have_fields(:name_ru).of_type(String)}
    it{should validate_presence_of(:name_en)}

    describe '#name' do
      specify{nameable.name(:en).should == 'Name'}
      specify{nameable.name(:ru).should == 'Имя'}
 
      context 'if russian name is null' do
        before do
          nameable.name_ru = nil
        end
   
        specify{nameable.name(:en).should == 'Name'}
        specify{nameable.name(:ru).should == 'Name'}
      end
    end
   
    # И так далее...
  end

В блоке используется одна переменная nameable, которая будет определяться в спеке того класса, к которому мы подключим модуль. То есть в spec/models/airport_spec.rb пишем примерно так:

require 'spec_helper'
require 'models/nameable_spec'

describe Airport do
  it{should be_mongoid_document}
 
  before do
    Airport.delete_all
  end
 
  context do
    let(:nameable){Factory.create(:airport,
      :name_en => 'Name',
      :name_ru => 'Имя'
    )}
    it_behaves_like :Nameable
  end

Вобщем то, переменных может быть сколько угодно, это зависит от тестируемого модуля. Теперь добавляем примерно тоже самое в spec/models/city_spec.rb:

require 'spec_helper'
require 'models/nameable_spec'

describe City do
  it{should be_mongoid_document}
 
  before do
    City.delete_all
  end
 
  context do
    let(:nameable){Factory.create(:city,
      :name_en => 'Name',
      :name_ru => 'Имя'
    )}
    it_behaves_like :Nameable
  end

Запускаем тест:

undr$ bundle exec rspec spec/models/airport_spec.rb

Работает. Запускаем несколько тестов:

undr$ bundle exec rake spec:models

Тесты вызывают ошибку:

/Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.6.4/lib/rspec/core/shared_example_group.rb:59:in `ensure_shared_example_group_name_not_taken': Shared example group 'Nameable' already exists (ArgumentError)
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.6.4/lib/rspec/core/shared_example_group.rb:8:in `shared_context'
    from /Users/undr/projects/ruby/*******/spec/models/nameable_spec.rb:1:in `<top (required)>'
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:234:in `load'
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.1.0/lib/active_support/dependencies.rb:234:in `block in load'
...

Чтобы избежать этого надо предотвратить повторное определение блока shared_examples_for. Просто этот перед определением блока делайте проверку на его наличие:

unless RSpec.world.shared_example_groups.has_key?(:Nameable)
  shared_examples_for :Nameable do  
   
    ...
   
  end
end

Таким образом у меня получилось удобно, без лишнего кода, тестировать модули подмешанные к классам.

Написал undr ()

21 октября 2011 в 09:30

Доклад по Grape

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (Еще не оценили)
Loading ... Loading ...

Написал undr ()

3 октября 2011 в 06:41

Размещено в Примеры, Программирование

Метки: , , ,

MongoId документы и метод to_a

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (Еще не оценили)
Loading ... Loading ...

Сегодня натолкнулся на странный баг в программе. Использовал Mongoid для работы с MongoDb. Моделька была примерно такая:

class Content::Airport < Content::Place
  field :coordinates, :type => Array
  field :index, :type => Integer
 
  index [[ :coordinates, Mongo::GEO2D ]]
 
  referenced_in :parent, :class_name => 'Content::City', :inverse_of => :children, :index => true, :validate => false
 
  def city
    parent
  end
 
  def to_a
    [
      code,
      name,
      coordinates.try(:join, ':'),
      city.try(:name),
      city.try(:index).try(:to_i),
      index.to_i
    ]
  end
end

В классе Content::Place добавлялись некоторые общие поля и модуль Mongoid::Tree.

При попытке создать аэропорт привязанный к городу выпадала ошибка:

BSON::InvalidDocument: Cannot serialize an object of class Content::City into BSON.
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/bson-1.3.1/lib/bson/bson_c.rb:24:in `serialize'
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/bson-1.3.1/lib/bson/bson_c.rb:24:in `serialize'
    from /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/mongo-1.3.1/lib/mongo/cursor.rb:425:in `construct_query_message'

Читать далее »

Написал undr ()

4 августа 2011 в 16:50

Кэширование фрагментов HTML кода в шаблонах ActionMailer

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (1 голосов, средний: 5.00 из 5)
Loading ... Loading ...

Задача: реализовать кэширование фрагментов HTML кода в шаблоне письма для рассылки.

Первое решение которое приходит в голову – это использовать хелпер cache, например так:

...
<h1>Result has been executed for long time</h1>

<% cache cache_key do %>
  <div>
  <%= doing_something_long_time_and_show_result %>
  </div>
<% end %>
...

Но этот способ не работает, так как ActiveMailer не содержит методы для кэширования. И в результате у нас ошибка:

Error: ActionView::Template::Error - undefined method `perform_caching' for #<SomeMailer:0x0000010827a9f8>
  /Users/undr/.rvm/gems/ruby-1.9.2-p180/gems/actionpack-3.0.7/lib/action_view/helpers/cache_helper.rb:37:in `cache'
  ...

Второй вариант, это использовать Rails.cache.fetch:

...
<h1>Result has been executed for long time</h1>

<%= Rails.cache.fetch cache_key do %>
  <div>
  <%= doing_something_long_time_and_show_result %>
  </div>
<% end %>
...

Ошибки уже нет, но результат не верный. В кэш попадает все содержимое шаблона, а не часть в блоке, и, как следствие, в результате письмо содержит дублированные куски HTML кода. То есть сначала выводится заголовок, потом опять заголовок и содержимое блока.

Чтобы убрать дублирование HTML кода в результате, нужно написать примерно такой хелпер:

def mailer_cache key, &block
  Rails.cache.fetch(key) do
    with_output_buffer(&block)
  end
end

И в шаблоне вызывать его.

...
<h1>Result has been executed for long time</h1>

<%= mailer_cache cache_key do %>
  <div>
  <%= doing_something_long_time_and_show_result %>
  </div>
<% end %>
...

Написал undr ()

28 июня 2011 в 14:58

Что же такое Railtie, Engine и Plugin?

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (5 голосов, средний: 5.00 из 5)
Loading ... Loading ...

Railtie

Railtie – это ядро фреймворка, обеспечивает возможности для расширения Rails и/или изменения процесса инициализации.

Каждый основной компонент Rails (ActionMailer, ActionController, ActionView, ActiveRecord и ActiveResource) является Railtie, так что каждый из них сам несет ответственность за свою инициализацию. Например, это освобождает Rails от каких-либо привязок к ActiveRecord, позволяя другой ORM работать с Rails.

Создание расширений для Rails не требует какой-либо реализации Railtie, но, если Вы хотите взаимодействовать с Rails во время его загрузки или после нее, Railtie – это то, что Вам нужно для такого взаимодействия. Например, чтобы реализовать в плагине одно из ниже перечисленного Вам бы понадобился Railtie:

  • создать свои инициализаторы Rails::Initializable#initializer
  • конфигурировать Rails или приложение, например чтобы добавить свой генератор
  • добавить свои ключи в config.* для конфигурации среды (environment)
  • установить подписку на события ActiveSupport::Notifications
  • добавить rake задачи в Rails

    Читать далее »

Написал undr ()

1 апреля 2011 в 00:15

Как тестировать помощники для rails с помощью rspec, использующие методы render(), concat() и capture()?

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (Еще не оценили)
Loading ... Loading ...

Когда я писал небольшой плагин для rails, добавляющий в приложение возможность быстрого создания javascript вкладок, у меня возникли трудности с тестированием. Методы плагина, которые использовали методы render(), concat() и capture(), невозможно было нормально протестировать, все время возникали ошибки в самих тестах.

Читать далее »

Написал undr ()

24 ноября 2010 в 11:47

Соответствие MySQL и MongoDB запросов

with 8 comments

1 Star2 Stars3 Stars4 Stars5 Stars (15 голосов, средний: 4.73 из 5)
Loading ... Loading ...

Эта шпоргалка создана для того чтобы упростить переход с SQL баз данных на MongoDB. В ней остались не затронутыми многие особенности и возможности MongoDB, неимеющие аналогов в SQL, такие как MapReduce, например. Или те о которых я незнаю. Это просто список соответствий MySQL запросов и запросов MongoDb.

Читать далее »

Написал undr ()

27 января 2010 в 11:20

Добавление меток и древовидных категорий в Rails приложение на MongoMapper

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (3 голосов, средний: 4.00 из 5)
Loading ... Loading ...

Написал undr ()

12 января 2010 в 15:40

Пример написания приложения на Rails с использованием MongoDB и MongoMapper вместо MySQL и ActiveRecord.

with 20 comments

1 Star2 Stars3 Stars4 Stars5 Stars (5 голосов, средний: 4.60 из 5)
Loading ... Loading ...

Наше приложение должно уметь сохранять траты за день и выводить статистику по ним за разное время. Траты хранятся в древообразных категориях и им присваюваются метки. Будет облако меток и вывод списка трат для определенной метки. Приложение будет доступно только для зарегистрированных пользователей и данные пользователей будут скрыты друг от друга.

Статистика будет выводиться за определенные периоды в виде графиков и таблиц. Должно быть два варианта статистики: общая и личная. Личная статистика будет учитывать траты конкретного пользователя и будет доступна только ему. Общая статистика будет основана на данных всех пользователей, она будет анонимна и доступна всем. Общая статистика будет ограниченной детализации. В статистике необходимо учесть, какое эмоциональное воздействие оказала трата: положительное (трата принесла радость, удовлетворение), нейтральное (никаких эмоций) или отрицательное (неприятные траты).

Это приложение не ведет баланс, тут не будет прихода. Только расход. Это сервис статистики по тратам.

Читать далее »

Написал undr ()

11 января 2010 в 11:26

Два способа ‘eager loading’ в ActiveRecord

without comments

1 Star2 Stars3 Stars4 Stars5 Stars (1 голосов, средний: 5.00 из 5)
Loading ... Loading ...

Начиная с Rails версии 2.1 в ActiveRecord существует два способа нетерпеливой загрузки (’eager loading’). Первый использует один запрос в котором связывает таблицы оператором JOIN. Второй использует по одному запросу на каждую модель. В Rails версии до 2.1 использовался только первый способ, в версиях начиная с 2.1 используются оба, но второй используется по умолчанию.

Первый способ, обладает некоторыми проблеммами. Он считается медленным, из-за необходимости обрабатывать большое количество избыточных данных (пример 1), особенно при большой вложенности ассоциаций для загрузки, и используется только если в запросе необходимо использовать поля ассоциаций (например в параметре :conditions)

Читать далее »

Написал undr ()

26 декабря 2009 в 19:00

Размещено в Программирование

Метки: , , , ,