2011-03-05 2 views
4

Je crée une gemme Rails qui s'intègre étroitement avec Active Record. La gemme nécessite un certain nombre de champs à définir. Par exemple:Générateur de migration personnalisé Ruby on Rails

class User < ActiveRecord::Base 
    # requires 'avatar_identifier', 'avatar_extension', 'avatar_size' 
    has_attached :avatar 
end 

Est-il possible d'avoir quelque chose comme:

rails g model user name:string avatar:attached 

Entraînant:

create_table :users do |t| 
    t.string :name 
    t.string :avatar_identifier 
    t.string :avatar_extension 
    t.integer :avatar_size 
end 

Si cela est impossible, une façon de faire:

create_table :users do |t| 
    t.string :name 
    t.attached :avatar 
end 

Générer plusieurs champs? Merci!

Répondre

3

Bien que Pravin ait indiqué la bonne direction, j'ai trouvé qu'il n'était pas simple de l'implémenter. Je l'ai fait ce qui suit, j'ai ajouté un fichier dans config/initializers (nom n'est pas pertinent), contenant les éléments suivants:

require 'active_support' 
require 'active_record' 

class YourApplication 
    module SchemaDefinitions 

    module ExtraMethod 
     def attachment(*args) 
     options = args.extract_options! 
     args.each do |col| 
      column("#{col}_identifier", :string, options) 
      column("#{col}_extension", :string, options) 
      column("#{col}_size", :integer, options) 
     end 
     end 
    end 

    def self.load! 
     ::ActiveRecord::ConnectionAdapters::TableDefinition.class_eval { include YourApplication::SchemaDefinitions::ExtraMethod } 
    end 

    end 
end 


ActiveSupport.on_load :active_record do 
    YourApplication::SchemaDefinitions.load! 
end 

alors vous pouvez juste faire quelque chose comme:

rails g model Person name:string title:string avatar:attachment 

qui va créer la migration suivante :

def self.up 
    create_table :people do |t| 
    t.string :name 
    t.string :title 
    t.attachment :avatar 

    t.timestamps 
    end 
end 

Si vous exécutez alors la migration, rake db:migrate il va créer le modèle Person suivant:

ruby-1.9.2-p0 > Person 
=> Person(id: integer, name: string, title: string, avatar_identifier: string, avatar_extension: string, avatar_size: integer, created_at: datetime, updated_at: datetime) 

Espérons que cela aide !!

2

Je considère t.attached similaire à t.references dans une association polymorphique.

En ce qui concerne la méthode references vous pouvez avoir quelque chose comme ci-dessous

def attached(*args) 
    options = args.extract_options! 
    column(:avatar_identifier, :string, options) 
    column(:avatar_extension, :string, options) 
    column(:avatar_size, :integer, options) 
end 

Vous aimeriez prolonger ActiveRecord::ConnectionAdapters::TableDefinition
Demandez regard à ce http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-references

3

En fait, si vous appelez

rails g model profile name:string next:attached 

rails déjà nerates vous une migration avec

def self.up 
    create_table :profiles do |t| 
    t.string :name 
    t.attached :next 

    t.timestamps 
    end 
end 

Cependant, vous pouvez remplacer le modèle de migration par défaut en le plaçant dans /lib/templates/active_record/model/migration.rb

Vous devriez écrire un my_gem râteau: tâche de configuration de mettre le fichier il je ne l'ai pas essayé, mais je suppose que les rails ne recherche pas dans les pierres précieuses non moteur pour ces modèles

le contenu de votre modèle de migration doit ressembler à

class <%= migration_class_name %> < ActiveRecord::Migration 
    def self.up 
    create_table :<%= table_name %> do |t| 
<% for attribute in attributes -%> 
    <% if attribute.type.to_s == "attached" %> 
     t.string :<%= attribute.name %>_identifier 
     t.string :<%= attribute.name %>_extension 
     t.integer :<%= attribute.name %>_size 
    <% else %> 
     t.<%= attribute.type %> :<%= attribute.name %> 
    <% end %> 
<% end -%> 
<% if options[:timestamps] %> 
     t.timestamps 
<% end -%> 
    end 
    end 

    def self.down 
    drop_table :<%= table_name %> 
    end 
end 
+0

Ceci est une bonne approche alternative, mais cela ne fonctionne que si vous utilisez les générateurs. – nathanvda

+0

bien la quiestion était "Est-il possible d'avoir quelque chose comme: rails g nom d'utilisateur du modèle: chaîne avatar: attaché". Par conséquent, je suppose que c'est applicable, mais je vois votre point. – Valdis