Лаб 5_RubyOnRails (1075652), страница 2
Текст из файла (страница 2)
В результатевыполнения запроса было выполнено подключение к базе данных, указанной вdatabase.yml, а изображение успешно возвращено клиенту (код 200 OK). Теперьостановим веб-сервер нажатием комбинации Ctrl-C.Исследование Rails-приложенияВ рамках знакомства с Rails воспользуемся генератором типовыхконтроллеров, так называемым Rails Scaffold (строительные леса). Внимание,пример приводится только для иллюстрации и в лабораторнойнепосредственно в работе использоваться не будет!Для этого выполним команду:rails generate scaffold User name:string email:stringВ итоге получим примерно следующий набор сообщений.
Проиллюстрируемего по ходу.Создание спецификации базы данных:invokecreateactive_recorddb/migrate/20120817160323_create_users.rbИ создание эквивалентной модели:createapp/models/user.rbСоздание Unit-тестов приложения:invokecreatecreatetest_unittest/unit/user_test.rbtest/fixtures/users.ymlПрописывание нового маршрута:invokerouteresource_routeresources :usersСоздание нового контроллера:invokecreatescaffold_controllerapp/controllers/users_controller.rbГенерация представлений:invokecreatecreatecreatecreatecreatecreateerbapp/views/usersapp/views/users/index.html.erbapp/views/users/edit.html.erbapp/views/users/show.html.erbapp/views/users/new.html.erbapp/views/users/_form.html.erbСоздание функционального теста:invokecreatetest_unittest/functional/users_controller_test.rbСоздание помощника:invokecreatehelperapp/helpers/users_helper.rbСоздание теста для него:9invokecreatetest_unittest/unit/helpers/users_helper_test.rbСоздание «полезностей» (Assets):invokeinvokecreateinvokecreateinvokecreateassetscoffeeapp/assets/javascripts/users.js.coffeescssapp/assets/stylesheets/users.css.scssscssapp/assets/stylesheets/scaffolds.css.scssДля реального создания базы данных запустим:rake db:migrateПроизойдет создание базы данных /db/development.sqlite3 (задан вконфигурации) по файлу миграции db/migrate/20130820160323_create_users.rb.Посмотрим содержимое этого файла:class CreateUsers < ActiveRecord::Migrationdef changecreate_table :users do |t|t.string :namet.string :emailt.timestampsendendendВыделенные строки соответствуют полям, которые были указаны при запускеScaffold-генератора.
При этом будет создана таблица users, а каждая записьбудет содержать name, email и timestamp. Обратите внимание на то, что вкоманде запуска Scaffold-генератора было использовано имя User, а таблицаназывается users! Причина этого заключается в принятом соглашении обименах.
В момент запуска генератора указывается называние сущности вединственном числе, а имя контроллера, таблица будет образованомножественным числом.После создания базы данных можно опять запустить веб-сервер командой railsserver.Обратимся по адресу http://localhost:3000/users/. В данном случае users – имясозданного контроллера. Получим следующую страницу:Рисунок 3 Страница http://localhost:3000/users/10Нажмем «New User» и получим форму добавления нового пользователя сполями name, email, заданными при запуске Scaffold-генератора. Добавимпоочерёдно нескольких пользователей.Рисунок 4 Страница http://localhost:3000/users/newРисунок 5 Страница http://localhost:3000/users/1В итоге возвращаемся на страницу http://localhost:3000/users/ и видим страницу,представленную на рисунке 6.Рисунок 6 Страница http://localhost:3000/users/В итоге можем убедиться, что сгенерированное приложение позволяетвыполнять просмотр, добавление, редактирование и удаление пользователей.
Иэто при том, что пока еще руками написаны лишь команды создания railsприложения и запуск scaffold-генератора.В дальнейшем будут показаны и некоторые другие генераторы, однако напримере сгенерированного приложения разберём назначение компонентовRails.Внесём дополнения в диаграмму взаимодействия компонентов по концепцииMVC с учётом реального сгенерированного приложения Rails.11Rack11. Браузеротправляет запросhttp://localhost:3000/users/12. Маршрутизаторнаходит контроллерusers3.
КонтроллерUserController взаимодействуетс модельюUser4. Контроллерподключает представлениеUser5. Средствамиотображенияформируетсяноваястраницадлябраузера2routingБраузерКонтроллерUsersController54ActiveViewПредставлениеUser3ActiveRecordМодельUserСУБДРисунок 7 MVC на примере Rails-приложения.Принципиальных отличий на данной диаграмме от общей концепции MVC немного. Rails приложение контролирует компонент с названием Rack, которыйявляется посредником в передаче запросов пользователей от веб-сервера к вебприложению.
В документации1 приводятся следующие веб-серверы, скоторыми rack может работать: Mongrel EventedMongrel SwiftipliedMongrel WEBrick FCGI CGI SCGI LiteSpeed ThinС использованием этого компонента построено несколько фреймворков вебприложений: Camping Coset Halcyon Mack Maveric Merb Racktools::SimpleApplication1http://rack.rubyforge.org/doc/12RamazeRuby on RailsRumSinatraSinVintageWavesWee…Большая их часть имеет достаточно ограниченное применение. В контекстеRails необходимо знать, что запрос от Rack поступает компонентумаршрутизации.
Исходный код, который контролирует маршрутизацию,расположен в файле config/routes.rb.Изначально этот файл содержит лишь каркас для добавления маршрутовTestApp::Application.routes.draw do…endОднако после работы Scaffold-генератора в него была добавлена строка:resources :usersЗапись resources означает создание стандартного набора REST маршрутов,который создаст 4 именованных маршрута (в концепции CRUD - Create ReadUpdate Destroy) и 7 действий всего: index, show, new, create, edit, update, destroy.Маршруты выделяются из URL. Например, адреса http://localhost:3000/users/ иhttp://localhost:3000/users/new явно ведут на маршруты UserController#index,UserController#new, а http://localhost:3000/users/1 - неявно наUserController#show, но с подразумеваемым параметром :id.Маршруты указывают конкретные контроллеры, которые должныобрабатывать запросы.
В нашем случае существует единственный контроллерapp/controllers/application_controller.rb. После автоматической генерации онсодержит следующий код:class UsersController < ApplicationController# GET /users# GET /users.jsondef index@users = User.allrespond_to do |format|format.html # index.html.erbformat.json { render json: @users }endend13# GET /users/1# GET /users/1.jsondef show@user = User.find(params[:id])respond_to do |format|format.html # show.html.erbformat.json { render json: @user }endend# GET /users/new# GET /users/new.jsondef new@user = User.newrespond_to do |format|format.html # new.html.erbformat.json { render json: @user }endend# GET /users/1/editdef edit@user = User.find(params[:id])end# POST /users# POST /users.jsondef create@user = User.new(params[:user])respond_to do |format|if @user.saveformat.html { redirect_to @user, notice: 'User was successfullycreated.' }format.json { render json: @user, status: :created, location: @user }elseformat.html { render action: "new" }format.json { render json: @user.errors, status: :unprocessable_entity }endendend# PUT /users/1# PUT /users/1.jsondef update@user = User.find(params[:id])respond_to do |format|if @user.update_attributes(params[:user])format.html { redirect_to @user, notice: 'User was successfullyupdated.' }format.json { head :no_content }elseformat.html { render action: "edit" }format.json { render json: @user.errors, status: :unprocessable_entity }endendend# DELETE /users/1# DELETE /users/1.jsondef destroy14@user = User.find(params[:id])@user.destroyrespond_to do |format|format.html { redirect_to users_url }format.json { head :no_content }endendendКласс UsersController является потомком Rails-класса ApplicationController.Обратите внимание на то, что в комментариях перед методамисгенерированного класса UsersController указаны маршруты, по которымпредполагается вызов этих методов.
Рассмотрим внимательно один измаршрутов и, соответственно один метод контроллера. Например index:def index@users = User.allrespond_to do |format|format.html # index.html.erbformat.json { render json: @users }endendПервая строка метода содержит получение списка пользователей через классUser. Этот класс является моделью пользователей. Из вызова метода .all можемпредположить получение списка всех пользователей. Для дальнейшегоиспользования этого списка заведена переменная уровня экземпляра с именем@users.Модель app/models/user.rb содержит код:class User < ActiveRecord::Baseattr_accessible :email, :nameendИз этого кода можем заключить, что класс User является потомком Rails-классаActiveRecord::Base. Более того, в классе объявлено два атрибута- :email и:name, поэтому в экземплярах этого класса к ним можно непосредственнообратиться.Возвращаемся к контроллеру. Метод respond_to предназначен дляпредоставления возможности получения ответа от веб-сервера в различныхформатах.
Однако явно он может и не использоваться, если формат полученияединственный. Здесь же предусмотрено два формата. Попробуем ввести вбраузере адрес: http://localhost:3000/users.json. В итоге получим ответ вформате json типа:[{"created_at":"2013-08-20T17:33:40Z","email":"ivanov@smb.ru","id":1,"name":"\u0418\u0432\u0430\u043d\u043e\u0432 \u0410.\u0410.","updated_at":"2013-0820T17:33:40Z"},15{"created_at":"2013-08-20T17:36:57Z","email":"petrov@smb.ru","id":2,"name":"\u041f\u0435\u0442\u0440\u043e\u0432 \u041f.\u041f.","updated_at":"2012-0817T17:36:57Z"}]В случае format.html указан предполагается использование представленияindex.html.erb.
Обратите внимание на то, что здесь “# index.html.erb” – всеголишь комментарий поясняющий, откуда будет использовано представление.В момент генерации представления были сгенерированы для каждогомаршрута, однако сейчас нас интересует лишь app/views/users/index.html.erb.Этот файл содержит код:<h1>Listing users</h1><table><tr><th>Name</th><th>Email</th><th></th><th></th><th></th></tr><% @users.each do |user| %><tr><td><%= user.name %></td><td><%= user.email %></td><td><%= link_to 'Show', user %></td><td><%= link_to 'Edit', edit_user_path(user) %></td><td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are yousure?' } %></td></tr><% end %></table><br /><%= link_to 'New User', new_user_path %>В коде присутствует HTML-разметка и специальная разметка <% %>, а также<%= … %>, которая содержит вызовы Ruby-кода и специальных методов типаlink_to.