Опубликован: 27.01.2016 | Доступ: свободный | Студентов: 916 / 58 | Длительность: 23:07:00
Лекция 4:

Rails — приправленный Ruby

Класс контроллер

Все эти разговоры о классах и наследованиях, возможно, вызвали вспышку узнавания, потому что мы видели их и раньше, в контроллере StaticPages (Листинг 3.16):

class StaticPagesController < ApplicationController

  def home
  end

  def help
  end

  def about
  end
end

Теперь вы в состоянии оценить, по крайней мере смутно, что этот код означает: StaticPagesController это класс, который наследует от ApplicationController и он оснащен home, help и about методами. Так как каждый сеанс Rails консоли загружает локальную среду Rails, мы можем даже создать контроллер в явном виде и изучить иерархию его классов:14Вы не должны знать, что делает каждый класс в этой иерархии. Я не знаю, что они все делают и я программирую на Ruby on Rails с 2005. Это означает или что или (a) я чрезвычайно некомпетентен или (b) можно быть квалифицированным Rails разработчиком не зная всех его внутренностей. Для нашей с вами пользы я уповаю на последнее.

>> controller = StaticPagesController.new
=> #<StaticPagesController:0x22855d0>
>> controller.class
=> StaticPagesController
>> controller.class.superclass
=> ApplicationController
>> controller.class.superclass.superclass
=> ActionController::Base
>> controller.class.superclass.superclass.superclass
=> ActionController::Metal
>> controller.class.superclass.superclass.superclass.superclass
=> AbstractController::Base
>> controller.class.superclass.superclass.superclass.superclass.superclass
=> Object

Диаграмма этой иерархии представлена на рис. 4.3.

Иерархия наследования для контроллера StaticPages.

Рис. 4.3. Иерархия наследования для контроллера StaticPages.

Мы можем даже вызвать действия контроллера в консоли, которые являются просто методами:

>> controller.home
=> nil

Здесь возвращаемое значение это nil поскольку home действие пустое.

Но постойте: действия не имеют возвращаемых значений, по крайней мере не действия со знаком вопроса (#булевые). Целью home действия, как мы видели в Главе 3, является визуализация веб-страницы. И я бы точно не забыл, если бы когда-либо вызывал StaticPagesController.new где-нибудь. Что происходит?

Происходит вот что: Rails написан на Ruby, но Rails это не Ruby. Некоторые Rails классы используются как обычные объекты Ruby, но некоторые из них просто льют воду на Рельсовую "волшебную мельницу". Rails это sui generis и должен быть изучен и понят отдельно от Ruby. Именно поэтому, если ваш основной интерес программирования заключается в написании веб-приложений, я рекомендую изучать вначале Rails, затем изучать Ruby, затем вернуться обратно на рельсы.

Класс User

Мы закончим наше путешествие по Ruby комплектацией собственного класса, User класса, который ожидает User модель, которая появится в Главе 6.

До сих пор мы вводили определения классов на консоли, но это быстро стало утомительным, вместо этого создайте файл example_user.rb в корневом каталоге приложения и заполните его содержимым Листинга 4.9.

class User
  attr_accessor :name, :email

  def initialize(attributes = {})
    @name  = attributes[:name]
    @email = attributes[:email]
  end

  def formatted_email
    "#{@name} <#{@email}>"
  end
end
Листинг 4.9. Код для примера пользователя. example_user.rb

Здесь довольно много чего происходит, так что давайте разбираться шаг за шагом. Первая строка,

 attr_accessor :name, :email

создает атрибуты доступа соответствующие имени пользователя и адресу электронной почты. Это создает "получатель" ("getter") и "назначатель" ("setter") методы, которые позволяют нам получать (get) и назначать (set) @name и @email переменные экземпляра, которые мы вкратце упоминали в Разделе 2.2.2. В Rails, принципиальная важность переменных экземпляра заключается в том что они автоматически доступны в представлениях, но в общем случае они используются для переменных которые должны быть доступны в Ruby классе повсеместно. (Мы вскоре расскажем об этом более подробно.) Переменные экземпляра всегда начинаются со знака @, и являются nil если они не определены.

Первый метод, initialize, специальный в Ruby: этот метод вызывается, когда мы выполняем User.new. Конкретно этот initialize принимает один аргумент, attributes:

  def initialize(attributes = {})
    @name  = attributes[:name]
    @email = attributes[:email]
  end

Здесь attributes переменная имеет значение по умолчанию равное пустому хэшу, так что мы можем определить пользователя без имени или адреса электронной почты (напомним, из Раздела 4.3.3 , что хэши возвращают nil на несуществующие ключи, поэтому attributes[:name] будет nil, если нет :name ключа, и так же для attributes[:email]).

Наконец, наш класс определяет метод, называемый formatted_email который использует значения присваиваемые @name и @email переменным для создания отформатированной версии адреса электронной почты пользователя, с помощью интерполяции строки (Раздел 4.2.2):

  def formatted_email
    "#{@name} <#{@email}>"
  end

Переменные @name и @email автоматически доступны в методе formatted_email из-за того что они являются переменными экземпляра (на что указывает знак @).

Давайте запустим консоль, и запросим (require) код примера пользователя, и покрутим наш User класс.

>> require './example_user'           # Так вы загружаете код example_user.
=> ["User"]
>> example = User.new
=> #<User:0x224ceec @email=nil, @name=nil>
>> example.name                   # nil поскольку attributes[:name] является nil
=> nil
>> example.name = "Example User"      # Назначение не-nil имени
=> "Example User"
>> example.email = "user@example.com" # и не-nil email адреса
=> "user@example.com"
>> example.formatted_email
=> "Example User <user@example.com>"

Здесь ’.’ — Unix обозначение для "текущего каталога" и ’./example_user’ говорит Ruby искать файл примера пользователя относительно этого расположения. Последующий код создает пустого пользователя в качестве примера и затем заполняет имя и адрес электронной почты, присвоением непосредственно к соответствующим атрибутам (присвоение стало возможными благодаря attr_accessor строке в Листинге 4.9). Когда мы пишем

example.name = "Example User"

Ruby создает @name переменную для "Example User" (и аналогично дляemail атрибута), которую мы затем используем в formatted_email методе.

Ссылаясь на Раздел 4.3.4 мы можем опустить фигурные скобки для последнего хеш аргумента, мы можем создать другого пользователя, передавая хэш initialize методу для создания пользователя с заранее определенными атрибутами:

>> user = User.new(name: "Michael Hartl", email: "mhartl@example.com")
=> #<User:0x225167c @email="mhartl@example.com", @name="Michael Hartl">
>> user.formatted_email
=> "Michael Hartl <mhartl@example.com>"

Мы увидим, начиная с Главы 7 что инициализация объектов с использованием хэш аргумента является общепринятой в Rails приложениях.

Заключение

На этом мы завершаем обзор языка Ruby. В Главе 5 мы начнем применять полученные знания при разработке примера приложения.

Файл example_user.rb из Раздела 4.4.5 нам больше не пригодится, поэтому я рекомендую удалить его:

$ rm example_user.rb

Затем зафиксируйте остальные изменения в основном репозитории проекта:

$ git add .
$ git commit -m "Add a full_title helper"

Упражнения

  1. Заменяя знаки вопроса в Листинге 4.10 на соответствующие методы, скомбинируйте split, shuffle и join для того чтобы написать функцию которая тасует буквы в данной строке.
  2. Используя Листинг 4.11 как руководство, добавить shuffle метод к String классу.
  3. Создайте три хэша, назовите их person1, person2, и person3, С именем (first name) и фамилией (last name) под ключами :first и :last. Затем создайте params хэш с тем, чтобы params[:father] являлся person1, params[:mother] являлся person2, и params[:child] являлся person3 (father, mother, child это отец, мать, и ребенок соответственно). Убедитесь, что, например, params[:father][:first] имеет правильное значение.
  4. Найдите онлайн версию Ruby API и почитайте о Hash методе merge.
  5. Пройдите Ruby Koans15http://rubykoans.com/ для того чтобы достичь просветления в Ruby.
>> def string_shuffle(s)
>>   s.split('').?.?
>> end
=> nil
>> string_shuffle("foobar")
Листинг 4.10. Скелет для функции тасующей строку.
>> class String
>>   def shuffle
>>     self.split('').?.?
>>   end
>> end
=> nil
>> "foobar".shuffle
Листинг 4.11. Скелет для shuffle метода, принадлежащего String классу.
Вадим Обозин
Вадим Обозин

Здравствуйте, записался на курс. При этом ставил галочку на "обучаться с тьютором". На email пришло письмо, о том, что записался на самостоятельное изучение курса. Как выбрать тьютора?