Rails это просто Ruby

Illustration of two people working on railroad tracks with tools, surrounded by fallen autumn leaves, in a monochromatic style with orange highlights. Illustration of two people working on railroad tracks with tools, surrounded by fallen autumn leaves, in a monochromatic style with orange highlights.

Желая научиться создавать крутые сайты и веб-приложения и избрав в качестве инструмента для этого Ruby on Rails, начинающие программисты нередко оказываются настолько очарованы известной "магией" фреймворка, что даже не задумываются о том, что лежит в её основе. Наглядным примером подобного очарования являются случаи, когда новичок ожидает, что атрибут контроллера будет доступен в файле модели, не понимая, как эти компоненты взаимодействуют между собой.

Фреймворк Ruby on Rails написан на динамическом объектно-ориентированном языке Ruby. Каждая строчка кода, каждый элемент волшебства, который воспринимается новичком как нечто само собой разумеющееся, является результатом выполнения ранее написанного разработчиками фреймворка кода на Ruby.

Прежде чем продолжать чтение, убедитесь, что вы имеете хотя бы базовое представление о том, как работает Ruby: что такое методы, что такое аргументы методов, что такое объекты и классы. Если вы не уверены в том, что понимаете значение перечисленных терминов, рекомендую прочитать книгу Криса Пайна "Учись программировать"(она очень короткая и совсем не скучная), а так же ознакомиться со следующими материалами:

Конечно, не стоит обходить вниманием и интерактивные обучающие сервисы: чтобы попробовать собственными руками написать код на Ruby и увидеть, что получится, воспользуйтесь Try Ruby и Codecademy.

После того, как вы освоились с синтаксисом Ruby и оценили по достоинству его возможности, предлагаю рассмотреть простой пример, наглядно описывающий ситуацию, которая описана в начале статьи.

Контроллер:

class HomeController < ApplicationController
  def review
    @translated_text = params[:translated_text]
    if @card.check_translation
      redirect_to :back, notice: "Правильно!"
    else
      redirect_to :back, notice: "Ошибка!"
    end
  end
end

Модель:

class Card < ActiveRecord::Base
  def check_translation
    translation == @translated_text
  end
end

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

class Card < ActiveRecord::Base
  def check_translation(text)
    translation == text
  end
end

Почему же в модели нельзя использовать переменные экземпляра, которые принимают свои значения в контроллере и имеют символ @ в начале? Ответ прост: потому что переменные экземпляра контроллера не транслируются в модель. В контроллере задаются переменные, которые будут использованы во вьюхах этого контроллера, к модели они не имеют никакого отношения. Что нужно делать, чтобы не допускать подобных ошибок? Не полагаться на "магию" фреймворка и тщательно изучать документацию. В первую очередь необходимо понять, что Ruby on Rails -- это не более, чем код, написанный на Ruby, и ведет он себя в соответствии с тем, что описано в его исходном коде. А исходный код Rails написан таким образом, что если в экшене show контроллера HomeController задать переменную @home, то она будет доступна для использования в файле app/views/show.html.erb.

Рассмотрим еще один пример, попроще.

Предположим, у нас есть модель Post:

class Post < ActiveRecord::Base
  has_many :comments
end

Код из примера выглядит очень простым и понятным, написанным практически человеческим языком. Однако, это всего лишь строка кода на Ruby, а именно - метод has_many, который принимает несколько аргументов, в нашем примере он всего один, имя модели во множественном числе в виде символа.

Чтобы убедиться, что это действительно так, можно проследовать в официальную документацию API фреймворка: http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many Здесь мы увидим, что помимо имени, метод has_many может принимать так же скоуп и опции, которые могут быть описаны в блоке.

Пример использования скоупа и дополнительных параметров(опций)

class Event < ActiveRecord::Base
  has_many :people, -> { where(banned: false) }, class: 'User'
end

В приведенном примере мы видим скоуп -> { where(banned: false) }, и параметр class: 'User' которые указывают, что использоваться будут экземпляры модели User, имеющие значение false в атрибуте banned.

Если взглянуть в исходный код метода has_many, мы увидим, что это самый обыкновенный код на Ruby, который написан таким образом, чтобы воплощать необходимый нам функционал:

# File activerecord/lib/active_record/associations.rb, line 1185
def has_many(name, scope = nil, options = {}, &extension)
  Builder::HasMany.build(self, name, scope, options, &extension)
end

Таким же образом устроен весь Ruby on Rails и все гемы, написанные сообществом.

В Ruby-сообществе пользуется большой популярностью парадигма DRY, Don't Repeat Yourself. Основываясь на ней, многие гемы используют другие гемы для того, чтобы осуществлять задуманный и воплощеный их авторами функционал, и Rails не является исключением. Введите в терминал команду:

gem dependency rails --pipe | gem dependency $1

В полученном ответе можно отыскать несколько строк:

Gem rails-4.1.6
  actionmailer (= 4.1.6)
  actionpack (= 4.1.6)
  actionview (= 4.1.6)
  activemodel (= 4.1.6)
  activerecord (= 4.1.6)
  activesupport (= 4.1.6)
  bundler (< 2.0, >= 1.3.0)
  railties (= 4.1.6)
  sprockets-rails (~> 2.0)

Несложно понять, что команда позволяет увидеть, какие гемы использует в качестве опоры для реализации собственного функционала каждый гем, установленный в системе. Блок текста чуть выше показывает, что Rails основывается на 9 гемах, каждый из которых можно использовать отдельно от фреймворка. Каждый из этих гемов, в свою очередь, может использовать другие в своей основе, но все они написаны на обычном Ruby. Если в достаточной степени изучить этот язык, чтение исходного кода практически любого гема, фреймворка или скрипта не составит большого труда. А наилучшее понимание возможностей чужого кода приходит именно в процессе чтения и понимания этого самого кода.

Самым полезным и достоверным источником информации о том, как работает Ruby on Rails можно считать документацию фреймворка: http://apidock.com/rails/ Помимо полного описания всех возможностей конкретного элемента в комментариях так же можно найти множество полезной информации, в частности, примеры использования описываемого кода в различных вариациях.