Заметки о релизе Ruby on Rails 3.1

Ключевые новинки в Rails 3.1:

Эти заметки о релизе покрывают основные обновления, но не включают все мелкие багфиксы и изменения. Чтобы увидеть все, обратитесь к списку комитов в главном репозитории Rails на GitHub.

Обновление до Rails 3.1

Если обновляете существующее приложение, было бы хорошо иметь перед этим покрытие тестами. Также, до попытки обновиться до Rails 3.1, необходимо сначала обновиться до Rails 3 и убедиться, что приложение все еще выполняется так, как нужно. Затем нужно предпринять следующие изменения:

Rails 3.1 требует как минимум Ruby 1.8.7

Rails 3.1 требует Ruby 1.8.7 или выше. Поддержка всех прежних версий Ruby была официально прекращена, и следует обновиться как можно быстрее. Rails 3.1 также совместим с Ruby 1.9.2.

Отметьте, что в Ruby 1.8.7 p248 и p249 имеются ошибки маршализации, ломающие Rails. Хотя в Ruby Enterprise Edition это было исправлено, начиная с релиза 1.8.7-2010.02. В ветке 1.9, Ruby 1.9.1 не пригоден к использованию, поскольку он иногда вылетает, поэтому, если хотите использовать 1.9.x перепрыгивайте на 1.9.2 для гладкой работы.

Что обновить в приложении

Следующие изменения означают обновление вашего приложения до Rails 3.1.3, последней версии 3.1.x Rails.

Gemfile

Сделайте изменения в вашем Gemfile.

gem 'rails', '= 3.1.3'
gem 'mysql2'

# Needed for the new asset pipeline
group :assets do
  gem 'sass-rails',   "~> 3.1.5"
  gem 'coffee-rails', "~> 3.1.1"
  gem 'uglifier',     ">= 1.0.3"
end

# jQuery is the default JavaScript library in Rails 3.1
gem 'jquery-rails'
config/application.rb
config.assets.enabled = true
config.assets.version = '1.0'
# Defaults to '/assets'
config.assets.prefix = '/asset-files'
config/environments/development.rb
# Do not compress assets
config.assets.compress = false

# Expands the lines which load the assets
config.assets.debug = true
config/environments/production.rb
# Compress JavaScripts and CSS
config.assets.compress = true

# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false

# Generate digests for assets URLs
config.assets.digest = true

# Defaults to Rails.root.join("public/assets")
# config.assets.manifest = YOUR_PATH

# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
# config.assets.precompile += %w( search.js )

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
config/environments/test.rb
# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
config/initializers/wrap_parameters.rb
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.

# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
  wrap_parameters :format => [:json]
end

# Disable root element in JSON by default.
ActiveSupport.on_load(:active_record) do
  self.include_root_in_json = false
end

Создание приложения Rails 3.1

# Нужен установленный руби-гем 'rails'
$ rails new myapp
$ cd myapp

Сторонние гемы

Сейчас Rails использует Gemfile в корне приложения, чтобы определить гемы, требуемые для запуска вашего приложения. Этот Gemfile обрабатывается Bundler, который затем устанавливает все зависимости. Он может даже установить все зависимости локально в ваше приложение, и оно не будет зависеть от системных гемов.

Подробнее: – bundler homepage

Живите на грани

Bundler и Gemfile замораживает ваше приложение Rails с помощью новой отдельной команды bundle. Если хотите установить напрямую из репозитория Git, передайте флажок --edge:

$ rails new myapp --edge

Если у вас есть локальная копия репозитория Rails, и вы хотите создать приложение с ее использованием, передайте флажок --dev:

$ ruby /path/to/rails/railties/bin/rails new myapp --dev

Архитектурные изменения Rails

Файлопровод (Assets Pipeline)

Главное изменение в Rails 3.1 это Assets Pipeline. Он делает CSS и JavaScript первосортным кодом, и делает доступной надлежащую организацию, включая использование в плагинах и engine-ах.

Файлопровод работает с помощью Sprockets и раскрывается в руководстве Asset Pipeline.

HTTP Streaming

HTTP Streaming это другое новшество в Rails 3.1. Он позволяет браузеру загружать таблицы стилей и файлы JavaScript, пока сервер все еще создает отклик. Это требует Ruby 1.9.2, является опциональным, а также требует настройки веб-сервера, но популярная связка nginx и unicorn уже готова предоставлять это преимущество.

Библиотека JS по умолчанию теперь jQuery

jQuery является библиотекой JavaScript по умолчанию, которая поствляется вместе с Rails 3.1. Но если вы используете Prototype, это просто переключить.

$ rails new myapp -j prototype

Identity Map

В Active Record имеется Identity Map в Rails 3.1. Identity map содержит ранее загруженные экземпляры записей и возвращает объект, связанный с записью, если к нему обращаются снова. Identity map создается при каждом запросе и уничтожается при его завершении.

Rails 3.1 поставляется с отключенной по умолчанию identity map.

Railties

Action Pack

Action Controller

class PostsController < ApplicationController
  USER_NAME, PASSWORD = "dhh", "secret"

  before_filter :authenticate, :except => [ :index ]

  def index
    render :text => "Everyone can see me!"
  end

  def edit
    render :text => "I'm only accessible if you know the password"
  end

  private
    def authenticate
      authenticate_or_request_with_http_basic do |user_name, password|
        user_name == USER_NAME && password == PASSWORD
      end
    end
end

..теперь может быть написано как

class PostsController < ApplicationController
  http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index

  def index
    render :text => "Everyone can see me!"
  end

  def edit
    render :text => "I'm only accessible if you know the password"
  end
end
class PostsController < ActionController::Base
  stream
end

Можно ограничить некоторые экшны от этого с использованием :only или :except. Подробности можно прочитать в документации по ActionController::Streaming.

Action Dispatch

Action View

tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)})
# => <div data-name="Stephen" data-city-state="[&quot;Chicago&quot;,&quot;IL&quot;]" />

Ключи преобразуются в дефисные. Значения кодируются в JSON, кроме строк и символов.

Active Record

class User < ActiveRecord::Base
  self.pluralize_table_names = false
end
class User < ActiveRecord::Base
  has_one :account
end

user.build_account{ |a| a.credit_limit = 100.0 }
class Post < ActiveRecord::Base
  attr_accessible :title
  attr_accessible :title, :published_at, :as => :admin
end

Post.new(params[:post], :as => :admin)
change_table(:users, :bulk => true) do |t|
  t.string :company_name
  t.change :birthdate, :datetime
end
class MyMigration < ActiveRecord::Migration
  def change
    create_table(:horses) do |t|
      t.column :content, :text
      t.column :remind_at, :datetime
    end
  end
end
class FooMigration < ActiveRecord::Migration
  def up # Не self.up
    ...
  end
end
has_many :things, :conditions => 'foo = #{bar}'          # до
has_many :things, :conditions => proc { "foo = #{bar}" } # после

Внутри proc, self это объект, являющийся владельцем связи, за исключением случая, когда связь лениво загружается, в этом случае self это класс, в котором определена связь.

Внутри proc можно иметь “нормальные” условия, поэтому следующее будет работать:

has_many :things, :conditions => proc { ["foo = ?", bar] }
# Schema: User(name:string, password_digest:string, password_salt:string)
class User < ActiveRecord::Base
  has_secure_password
end

Active Model

Active Resource

class User < ActiveResource::Base
  self.format = :xml
end

Active Support

Устарело: