Рельсы модель без базы данных


Я хочу создать модель Rails (2.1 и 2.2) с проверками ActiveRecord, но без таблицы базы данных. Каков наиболее широко используемый подход? Я нашел некоторые плагины, которые утверждают, что предлагают эту функциональность, но многие из них, похоже, не широко используются или поддерживаются. Что сообщество рекомендует мне делать? Прямо сейчас я склоняюсь к тому, чтобы придумать свое собственное решение, основанное на этот блог.

13 61

13 ответов:

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

есть лучший способ сделать это в Rails 3:http://railscasts.com/episodes/219-active-model

это подход, который я использовал в прошлом:

на приложение / модели / без таблиц.РБ

class Tableless < ActiveRecord::Base
  def self.columns
    @columns ||= [];
  end

  def self.column(name, sql_type = nil, default = nil, null = true)
    columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default,
      sql_type.to_s, null)
  end

  # Override the save method to prevent exceptions.
  def save(validate = true)
    validate ? valid? : true
  end
end

на приложение / модели / foo.РБ

class Foo < Tableless
  column :bar, :string  
  validates_presence_of :bar
end

на скрипт/консоли

Loading development environment (Rails 2.2.2)
>> foo = Foo.new
=> #<Foo bar: nil>
>> foo.valid?
=> false
>> foo.errors
=> #<ActiveRecord::Errors:0x235b270 @errors={"bar"=>["can't be blank"]}, @base=#<Foo bar: nil>>

теперь есть более простой способ:

class Model
  include ActiveModel::Model

  attr_accessor :var

  validates :var, presence: true
end

ActiveModel::Model код:

module ActiveModel
  module Model
    def self.included(base)
      base.class_eval do
        extend  ActiveModel::Naming
        extend  ActiveModel::Translation
        include ActiveModel::Validations
        include ActiveModel::Conversion
      end
    end

    def initialize(params={})
      params.each do |attr, value|
        self.public_send("#{attr}=", value)
      end if params
    end

    def persisted?
      false
    end
  end
end

http://api.rubyonrails.org/classes/ActiveModel/Model.html

просто создайте новый файл с окончанием ".rb " после соглашений, к которым вы привыкли (единственное число для имени файла и имени класса, подчеркнуто для имени файла, случай верблюда для имени класса) в вашем каталоге "модели/". Ключ здесь-не наследовать вашу модель от ActiveRecord (потому что именно AR дает вам функциональность базы данных). например: для новой модели для автомобилей, создайте файл под названием "автомобиль.РБ" в вашей модели/ каталог и внутри вашей модели:

class Car
    # here goes all your model's stuff
end

правка: кстати, если вы хотите атрибуты вашего класса, вы можете использовать здесь все, что вы используете на ruby, просто добавьте пару строк с помощью "attr_accessor":

class Car
    attr_accessor :wheels # this will create for you the reader and writer for this attribute
    attr_accessor :doors # ya, this will do the same

    # here goes all your model's stuff
end

edit #2: после прочтения комментария Майка, я бы сказал вам идти своим путем, если вы хотите, чтобы все функции ActiveRecord, но не таблицы в базе данных. Если вы просто хотите обычный класс Ruby, возможно, вы найдете это решение лучше ;)

здесь видеоуроки о неактивной модели записи, составленной Райаном Бейтсом. Хорошее место для начала.

на всякий случай, если вы еще не смотрели его.

для полноты картины:

Rails now (at V5) имеет удобный модуль, который вы можете включить:

include ActiveModel::Model

Это позволяет инициализировать с помощью хэша и использовать проверки среди прочего.

полная документация здесь.

Я построил быстрый миксин, чтобы справиться с этим, согласно предложению Джона Топли.

http://github.com/willrjmarshall/Tableless

Как насчет маркировки класса как абстрактного?

class Car < ActiveRecord::Base
  self.abstract = true
end

это скажет рельсы, что класс автомобиля не имеет соответствующей таблицы.

[edit]

это действительно не поможет вам, если вам нужно будет сделать что-то вроде:

my_car = Car.new

используйте проверяемый камень. Как вы говорите, есть решения на основе AR, но они, как правило, хрупкие.

http://validatable.rubyforge.org/

кто-нибудь когда-либо пытался включить ActiveRecord::Validations и ActiveRecord::Validations::ClassMethods в неактивный класс записи и посмотреть, что происходит при попытке установить валидаторы ?

Я уверен, что существует множество зависимостей между платформой проверки и самим ActiveRecord. Но вы можете успешно избавиться от этих зависимостей, разветвив свою собственную структуру проверки из структуры проверки AR.

просто идея.

обновление: Oops, это больше или меньше того, что предлагается в сообщении, связанном с вашим вопросом. Извините за беспокойство.

сделайте, как сказал Тиаго Пинто, и просто не наследуйте свою модель от ActiveRecord::Base. Это будет просто обычный класс Ruby, который вы вставляете в файл в своем каталоге app/models/. Если ни одна из ваших моделей не имеет таблиц, и вы вообще не используете базу данных или ActiveRecord в своем приложении, обязательно измените свою среду.rb файл должен иметь следующую строку:

config.frameworks -= [:active_record]

Это должно быть в пределах Rails::Initializer.run do |config| блок.

вы должны проверить PassiveRecord плагин. Это дает вам ActiveRecord-подобный интерфейс для моделей без базы данных. Это просто, и меньше хлопот, чем борьба с ActiveRecord.

мы используем PassiveRecord в сочетании с Validatable драгоценный камень, чтобы получить желаемое поведение ОП.