Rails: вызов класса модели в библиотеке

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

def schedule(action, *args)
  if arg.is_a? Aircraft
    ...
  end
end

Я делаю это в библиотечном классе (файл находится в lib/) и получаю ошибку неинициализированная константа Aircraft. Самолет — это класс модели с соответствующим файлом aircraft.rb в app/models.

Могу ли я использовать классы моделей и экземпляры в библиотеке? Как?


Контекст ошибки:

Ошибка возникает в тестах RSpec; код работает в браузере. Я пытался запросить модель в файле _spec.rb, пока безуспешно.


person Christian Lescuyer    schedule 28.11.2008    source источник


Ответы (4)


Вы можете использовать классы моделей в файлах библиотеки Rails, и вы делаете это совершенно правильно. Rails должен автоматически загружать класс Aircraft при обращении к нему.

Поэтому нам нужно немного больше контекста, чтобы понять, почему это не работает для вас. Возможно ли, что вы загружаете файл lib/ без среды Rails?

Одним из способов решения этой проблемы было бы явное требование файла модели plane.rb. Однако вы обнаружите, что такой подход быстро ведет к безумию, поскольку он ломает автозагрузчик Rails тонкими и удивительными способами. Rails намного проще, если вы работаете с загрузчиком классов Rails, а не против него.

Обновить

Итак, если это тест RSpec, можем ли мы увидеть код, который вы используете для загрузки среды, в файле спецификации? Это должно выглядеть примерно так:

require File.dirname(__FILE__) + '/../spec_helper'

и он должен быть в верхней части файла. Предполагается, что у вас установлен подключаемый модуль RSpec Rails (здесь) и что у вас есть файл spec/spec_helper.rb по умолчанию из подключаемого модуля RSpec. Если такого файла нет, попробуйте запустить:

ruby script/generate rspec
person Daniel Lucraft    schedule 28.11.2008
comment
Ах, большое спасибо! Вы указали мне правильное направление: он отлично работает в браузере. Я еще не пробовал, потому что работаю с TDD: он ломается в RSpec. Я поправлю вопрос. - person Christian Lescuyer; 29.11.2008

Это даст вам доступ к модели самолета:

require File.dirname(__FILE__) + "/../app/models/aircraft"

[редактировать]

Даниэль поднимает хороший вопрос о контексте. Если вы используете задачу rake, убедитесь, что вы загружаете среду:

task :my_task => :environment do
  # something happens...
end 
person Mike Breen    schedule 28.11.2008

Ответ Даниэля правильный, но подумайте: почему библиотечный класс относится к классу модели? Код библиотеки не должен знать о реальных классах модели, хотя он может знать об интерфейсе, который они предоставляют.

Еще одно соображение: почему метод #schedule запрашивает класс модели? Если бы новый класс модели Spaceship захотел работать с #schedule, то #schedule пришлось бы измениться, чтобы работать с ним. Это не обязательно.

Вместо этого, в чем разница между способами, которыми объект Aircraft и объекты других классов обрабатываются #schedule? Можете ли вы извлечь это различие в отдельный метод? Затем вы можете переместить эти реализации в каждый из классов модели и решить, какой из них используется полиморфизмом, а не путем ветвления.

Например, что было раньше:

def schedule(action, vehicle)
  if vehicle.is_an?(Aircraft)
    possible_days = case action
    when "travel"
      ["Mon", "Wed", "Fri"]
    when "repair"
      ["Sat", "Sun"]
    end
    possible_days.rand
  elsif vehicle.is_a?(Spaceship)
    possible_days = case action
    when "travel"
      ["Sat", "Tue", "Thu"]
    when "repair"
      ["Sun", "Mon"]
    end
    possible_days.rand
  end
end

станет:

def schedule(action, vehicle)
  vehicle.days_action_can_be_performed(action).rand
end


class Aircraft
  def days_action_can_be_performed(action)
    possible_days = case action
    when "travel"
      ["Mon", "Wed", "Fri"]
    when "repair"
      ["Sat", "Sun"]
    end
    possible_days
  end
end

class Spaceship
  def days_action_can_be_performed(action)
    possible_days = case action
    when "travel"
      ["Sat", "Tue", "Thu"]
    when "repair"
      ["Sun", "Mon"]
    end
    possible_days
  end
end

Когда добавляется новый класс, ему просто нужно реализовать #days_action_can_be_performed, и он будет работать с #schedule.

person Peeja    schedule 23.02.2011

Должны попробовать это: if arg.is_a? ::Aircraft ?

person Autodidact    schedule 15.02.2011