Пользовательский миграционный генератор Ruby on Rails - PullRequest
6 голосов
/ 05 марта 2011

Я создаю гем Rails, который тесно интегрируется с Active Record.Драгоценный камень требует несколько полей, которые будут определены.Например:

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

Возможно ли иметь что-то вроде:

rails g model user name:string avatar:attached

В результате:

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

Если это невозможно, в любом случаесделать:

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

Создать несколько полей?Спасибо!

Ответы [ 3 ]

4 голосов
/ 14 марта 2011

На самом деле, если вы вызываете

rails g model profile name:string next:attached

, rails уже генерирует миграцию с помощью

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

    t.timestamps
  end
end

, однако вы можете переопределить шаблон миграции по умолчанию, поместив его в / lib / templates / active_record/model/migration.rb

Вы должны написать грабли my_gem: задача установки, чтобы поместить туда файл, который я не пробовал, но я полагаю, что rails не ищет в гемах без движка эти шаблоны

Содержимое вашего шаблона миграции будет выглядеть как

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
3 голосов
/ 16 марта 2011

В то время как Правин действительно указывал в правильном направлении, я обнаружил, что реализовать его было непросто.Я сделал следующее, я добавил файл в config/initializers (имя не имеет значения), содержащий следующее:

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

тогда вы можете просто сделать что-то вроде:

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

который создаст следующую миграцию:

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

    t.timestamps
  end
end

Если вы затем запустите миграцию, rake db:migrate создаст следующую модель Person:

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) 

Надеюсь, это поможет !!

2 голосов
/ 11 марта 2011

Я считаю t.attached похожим на t.references в полиморфной ассоциации.

Применительно к методу references вы можете получить что-то вроде ниже

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

Вы можете продлить ActiveRecord::ConnectionAdapters::TableDefinition
Посмотри на это http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-references

...