web-dev-qa-db-fra.com

Rails modèle sans base de données

Je veux créer un modèle Rails (2.1 et 2.2) avec des validations ActiveRecord, mais sans table de base de données. Quelle est l'approche la plus utilisée? J'ai trouvé des plugins qui prétendent offrir cela mais bon nombre d'entre elles ne semblent pas être largement utilisées ou maintenues. Qu'est-ce que la communauté recommande que je fasse? En ce moment, je penche pour trouver ma propre solution basée sur cet article de blog .

64
FlipFlop

Je pense que le blog que vous liez est la meilleure façon de procéder. Je suggérerais seulement de déplacer les méthodes tronquées dans un module pour ne pas polluer votre code.

8
Honza

Il existe une meilleure façon de le faire dans Rails 3: http://railscasts.com/episodes/219-active-model

67
d135-1r43

C'est une approche que j'ai utilisée dans le passé:

Dans app/models/tableless.rb

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

Dans app/models/foo.rb

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

Dans script/console

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>>
43
John Topley

Il existe maintenant un moyen plus simple:

class Model
  include ActiveModel::Model

  attr_accessor :var

  validates :var, presence: true
end

ActiveModel::Model code:

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

19
hlcs

créez simplement un nouveau fichier se terminant par ".rb" selon les conventions auxquelles vous êtes habitué (singulier pour le nom de fichier et le nom de classe, souligné pour le nom de fichier, cas de chameau pour le nom de classe) sur votre répertoire "models /". La clé ici est de ne pas hériter votre modèle d'ActiveRecord (car c'est AR qui vous donne la fonctionnalité de base de données). par exemple: pour un nouveau modèle de voiture, créez un fichier appelé "car.rb" dans votre répertoire models/et à l'intérieur de votre modèle:

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

edit: btw, si vous voulez des attributs sur votre classe, vous pouvez utiliser ici tout ce que vous utilisez sur Ruby, ajoutez simplement quelques lignes en utilisant "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: après avoir lu le commentaire de Mike, je vous dirais de suivre son chemin si vous voulez toutes les fonctionnalités d'ActiveRecord mais pas de table sur la base de données. Si vous voulez juste une classe Ruby class ordinaire, vous trouverez peut-être mieux cette solution;)

8
tpinto

Par souci d'exhaustivité:

Rails maintenant (à V5) dispose d'un module pratique que vous pouvez inclure:

include ActiveModel::Model

Cela vous permet d'initialiser avec un hachage et d'utiliser entre autres des validations.

La documentation complète est ici .

5
xmjw

Il y a un screencast sur le modèle d'enregistrement non actif, composé par Ryan Bates. Un bon point de départ.

Juste au cas où vous ne l'auriez pas déjà regardé.

4
Laurent Farcy

J'ai construit un Mixin rapide pour gérer cela, selon la suggestion de John Topley.

http://github.com/willrjmarshall/Tableless

3
Will Marshall

Qu'en est-il du marquage de la classe comme abstrait?

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

cela indiquera Rails que la classe Car n'a pas de table correspondante.

[modifier]

cela ne vous aidera pas vraiment si vous devez faire quelque chose comme:

my_car = Car.new
2
Mike Breen

Quelqu'un a déjà essayé d'inclure ActiveRecord::Validations et ActiveRecord::Validations::ClassMethods dans une classe d'enregistrement non actif et voyez ce qui se passe lorsque vous essayez de configurer des validateurs?

Je suis sûr qu'il existe de nombreuses dépendances entre le cadre de validation et ActiveRecord lui-même. Mais vous pouvez réussir à vous débarrasser de ces dépendances en forçant votre propre cadre de validation à partir du cadre de validation AR.

Juste une idée.

pdate: oopps, c'est plus ou moins ce qui est suggéré dans le post lié à votre question. Désolé pour le dérangement.

1
Laurent Farcy

Faites comme Tiago Pinto et ne faites pas hériter votre modèle d'ActiveRecord :: Base. Ce sera juste une classe Ruby régulière que vous collerez dans un fichier dans votre répertoire app/models /. Si aucun de vos modèles n'a de tables et que vous n'utilisez pas une base de données ou ActiveRecord sur tous dans votre application, assurez-vous de modifier votre fichier environment.rb pour avoir la ligne suivante:

config.frameworks -= [:active_record]

Cela devrait être dans le Rails::Initializer.run do |config| bloquer.

0
Sarah Vessels

Vous devez vérifier le plugin PassiveRecord . Il vous donne une interface de type ActiveRecord pour les modèles non-base de données. C'est simple et moins compliqué que de combattre ActiveRecord.

Nous utilisons PassiveRecord en combinaison avec la gemme Validatable pour obtenir le comportement souhaité de l'OP.

0
Tate Johnson