Pull to refresh

Rails custom Scaffolding

Reading time 4 min
Views 25K

Наверное каждый в начале работы с ROR был впечатлен возможностью Scaffolding'а, который позволяет одной командой создавать migrations, controllers, models и views.

Но что делать если в своем проекте вы используете не стандартные Rails утилиты: erb, Test::Unit, fixturies, а сторонние инструменты: Haml, Rspec, Cucumber, Factory Girl и более того, хотите добавить собственные шаблоны?

Интересно? GOTO next line.

Исходные данные:
Ruby on Rails; Rspec; will-paginate; Haml; Factory-girl

Задача:
% rails generate scaffold post post:string
Генерирует:
  1. contoller's с поддержкой will_paginate, русскоязычными сообщениями
  2. model's с поддержкой will_paginate
  3. view's с заданным нами содержимым и в формате haml
  4. Rspec тесты, вместо Test::Unit
  5. Factory Girl factories вместо стандартных fixtures



Для начала коротко о Scaffold. Scaffold — это встроенный генератор, сам по себе он ничего не генерирует, но запускает другие генераторы.

Текущие настройки scaffold можно проверить с помощью:
% rails g scaffold --help

Генераторы настраиваются с помощью файла RAILS_ROOT/config/application.rb, внутри которого можно задавать параметры с помощью такой конструкции:
config.generators do |g|
  # настройки генераторов
end

CUSTOM CONTROLLERS


Начнём с того, что заменим стандартный шаблон контроллеров на свой.
Необходимо скопировать шаблон из гема используемого в проекте в сам проект.
Путь до гемов вашего проекта можно узнать таким способом:
RAILS_ROOT% rails console
puts $LOAD_PATH
...
...
... тут следует список всех гемов с полными путями


Скопируем шаблон controller.rb из GEMS_PATH/railties[version]/lib/rails/generators/rails/scaffold_controller/templates в RAILS_ROOT/lib/templates/rails/scaffold_controller/controller.rb

#Вот так выглядит исходный шаблон контроллера controller.rb
class <%= controller_class_name %>Controller < ApplicationController
  # GET <%= route_url %>
  # GET <%= route_url %>.xml
  def index
    @<%= plural_table_name %> = <%= orm_class.all(class_name) %>

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @<%= plural_table_name %> }
    end
  end
...

Немного кастомиризуем его, добавив поддержку русского языка, паджинацию и обрезав лишний текст
# encoding: UTF-8
class <%= controller_class_name %>Controller < ApplicationController
  # GET <%= route_url %>
  def index
    @<%= plural_table_name %> = <%= class_name %>.paginate :page => params[:page], :order => 'id DESC'
  end
...

После работы scaffold мы получим такой миловидный код
# encoding: UTF-8
class PostsController < ApplicationController
  # GET /posts
  def index
    @posts = Post.paginate :page => params[:page], :order => 'id DESC'
  end
...

CUSTOM MODELS


Скопируем файл шаблона model.rb с GEMS_PATH/activerecord[version]/lib/rails/generators/active_record/model/templates в RAILS_ROOT/lib/templates/active_record/model/model.rb

#Исходный код шаблона model.rb
class <%= class_name %> < <%= parent_class_name.classify %>
<% attributes.select {|attr| attr.reference? }.each do |attribute| -%>
  belongs_to :<%= attribute.name %>
<% end -%>
end


Добавим поддержку русского языка и 2 параметра для will_paginate
# encoding: UTF-8
class <%= class_name %> < <%= parent_class_name.classify %>
  cattr_reader :per_page
  @@per_page = 20
<% attributes.select {|attr| attr.reference? }.each do |attribute| -%>
  belongs_to :<%= attribute.name %>
<% end -%>
end


На выходе получаем:
# encoding: UTF-8
class Post < ActiveRecord::Base
  cattr_reader :per_page
  @@per_page = 20
end

CUSTOM VIEWS


В нашем примере мы используем HAML вместо .erb. Как заставить Rails генерировать не erb, a haml view's?
Очень просто, достаточно установить gem «haml-rails».
Дописываем в Gemfile
gem 'haml-rails'

И запускаем bundle install

Готово! Теперь рельсогенератор делает file_name.html.haml файлы для нас

Перейдём к нашим шаблонам. Скопируем 5 файлов (edit.html.haml, _form.html.haml, index.html.haml, new.html.haml, show.html.haml) из GEMS_PATH/haml-rails[version]/lib/generators/haml/scaffold/templates в уже полюбившуюся нам RAILS_ROOT/lib/templates/haml/scaffold

Не буду приводить здесь кода, его можно посмотреть по ссылкам ниже

Исходные шаблоны — haml-rails
Шаблон после редактирования — ссылка
Результат — ссылка

RSPEC


Как и в случае с haml, для замены стандартных тестов RSpec'овскими достаточно установить gem «rspec-rails».

По умолчанию scaffold будет создавать rspec файлы для тестирования моделей, контроллеров, хелперов, вьюх, роутинга и запросов.

Наверняка вам как и мне не нужно столько rspec файлов, к счастью ROR позволяет нам настроить этот пункт.

#RAILS_ROOT/config/application.rb
config.generators do |g|
  #Здесь я отключил генерацию rspec файлов для вьюх, хелперов, роутинга и запросов
  #т.о. оставив лишь генерацию spec's для моделей и контроллеров
  g.test_framework :rspec, :view_specs => false, :helper_specs => false, 
                           :routing_specs => false, :request_specs => false
end

FACTORY GIRL


Для добавления scaffolding для FG, установим gem «rails3-generators»
И добавим в конфиг следующую строчку
#RAILS_ROOT/config/application.rb
config.generators do |g|
    g.test_framework :rspec, :view_specs => false, :helper_specs => false, 
                             :routing_specs => false, :request_specs => false
    g.fixture_replacement :factory_girl, :dir => "spec/factories"
end

Помимо factory_girls гем «rails3-generators» добавляет генераторы для DataMapper, Authlogic, Mongomapper, Shoulda, Formtastic и SimpleForm

Что же у нас получилось?


% rails g scaffold final final:string
invoke  active_record
      create    db/migrate/20110713193843_create_finals.rb
      create    app/models/final.rb
      invoke    rspec
      create      spec/models/final_spec.rb
      invoke      factory_girl
      create        spec/factories/finals.rb
       route  resources :finals
      invoke  scaffold_controller
      create    app/controllers/finals_controller.rb
      invoke    haml
      create      app/views/finals
      create      app/views/finals/index.html.haml
      create      app/views/finals/edit.html.haml
      create      app/views/finals/show.html.haml
      create      app/views/finals/new.html.haml
      create      app/views/finals/_form.html.haml
      invoke    rspec
      create      spec/controllers/finals_controller_spec.rb
      invoke      helper
      invoke      rspec
      invoke    helper
      create      app/helpers/finals_helper.rb
      invoke      rspec
      invoke  stylesheets
   identical    public/stylesheets/scaffold.css

Собственные шаблоны для MVC; haml view's; factory_girl factories; RSpec's для моделей и контроллеров; встроенная паджинация.

Всё как мы хотели. Наслаждайтесь))

Посмотреть полный код

Github

Почитать

Generators manual
Paul's Barry Article: Customizing generators in rails 3
Rspec generators detail
Подкаст про генераторы
rails3-generators gem
haml-rails gem
Tags:
Hubs:
+35
Comments 26
Comments Comments 26

Articles