More Related Content Similar to Tequila - язык для продвинутой генерации JSON (20) More from Ivan Nemytchenko (7) Tequila - язык для продвинутой генерации JSON2. JSON
{
“id” : 205633,
“name” : “jQuery in Action”,
“authors” : [“Yehuda Katz”, “Bear Bibeault”]
}
9. to_json
@products.to_json(
:methods =>
[:label, :confirmed?, :formatted_description, :comment_text,
:tag_list, ...],
:include => {
:comments => {
:only => [:comment, :id, :commenter_id],
:methods => [:commenter_name, :date]
},
:taggings => {
:methods => [:date],
:include => {
:tag => {
:only => [:name, :background, :foreground]
},
:tagger => {
:only => [:login]
}}}})
11. переопределение as_json в модели
class Product
def as_json(options)
super(
:methods => [:label, :confirmed?,
:formatted_description, :comment_text, :tag_list, ...],
:include => {
:comments => {
:only => [:comment, :id, :commenter_id],
:methods => [:commenter_name, :date]},
:taggings => {
:methods => [:date],
:include => {
:tag => { :only =>[:name, :background, :foreground]},
:tagger => { :only => [:login] }}}}
)
end
end
12. переопределение as_json в моделях
class Product < AR::Base class Tagging
def label; end def as_json # ...
def confirmed?; end end
#...
def as_json class Tag
super( def as_json # ...
:methods => [:label, :confirmed?, end
:formatted_description, :comment_text,
:tag_list, ...], class User
:include => { :comments, :taggings } def as_json # ...
) end
end
end
class Comment < AR::Base
def as_json
super(
:only => [:comment, :id, :commenter_id],
:methods => [:commenter_name, :date]
)
end
end
13. Гладкий и шелковистый контроллер
class ProductsController < ApplicationController
def index
render :json => @products
end
end
15. нужно более чем одно представление модели
class ProductsController < ApplicationController
def index
render :json => @products.as_json(...)
end
end
17. хочется передать параметр в метод
render :json => @product.to_json(
я
Так нельз :methods => :favorited_by_user?(current_user)
)
18. хочется передать параметр в метод
render :json => @product.to_json(
я
Так нельз :methods => :favorited_by_user?(current_user)
)
class Product < AR::Base
attr_accessor :current_user
def favorited_by_user?(user=nil)
user ||= current_user
# ... Если си
ль
end то можн но хочется,
end о конеч
но
@product.current_user = current_user
render :json => @product.to_json(:methods => :favorited_by_user?)
21. Неприятности:
• Каша из :include и :methods в сложных случаях
• Структура базы меняется → Меняется JSON
• Модель засоряется мелкими методами, только
чтобы “причесать” JSON output
22. Неприятности:
• Каша из :include и :methods в сложных случаях
• Структура базы меняется → Меняется JSON
• Модель засоряется мелкими методами, только
чтобы “причесать” JSON output
• Нельзя вызвать метод с параметрами
23. Неприятности:
• Каша из :include и :methods в сложных случаях
• Структура базы меняется → Меняется JSON
• Модель засоряется мелкими методами, только
чтобы “причесать” JSON output
• Нельзя вызвать метод с параметрами
• Модель может иметь одно представление в
JSON при использовании as_json
24. Неприятности:
• Каша из :include и :methods в сложных случаях
• Структура базы меняется → Меняется JSON
• Модель засоряется мелкими методами, только
чтобы “причесать” JSON output
• Нельзя вызвать метод с параметрами
• Модель может иметь одно представление в
JSON при использовании as_json
• Некоторые модели вынесены в плагины
28. Задачи:
• Вынести логику представления в отдельный
слой (presenter)
• Очистить модели от методов-хелперов
• Вызов методов с параметрами
29. Задачи:
• Вынести логику представления в отдельный
слой (presenter)
• Очистить модели от методов-хелперов
• Вызов методов с параметрами
• Получить больший контроль над
представлением данных
30. Задачи:
• Вынести логику представления в отдельный
слой (presenter)
• Очистить модели от методов-хелперов
• Вызов методов с параметрами
• Получить больший контроль над
представлением данных
• Чтобы красиво!
31. Задачи:
• Вынести логику представления в отдельный
слой (presenter)
• Очистить модели от методов-хелперов
• Вызов методов с параметрами
• Получить больший контроль над
представлением данных
• Чтобы красиво!
• Успеть за 2 дня!!!
32. Отступы
-@humans => people
:only
.name => login
:code => enhanced_name
name + "!!!"
:code => hello_world
"Hello world!"
+pets
:except
.human_id
.pet_type_id
+toys
:methods
.railsize("$", price.to_s)
42. Опциональный ключ
-users [{
:only "user": {
.username "username": "heather"
}},{
"user": {
"username": "george"
}},{
"user": {
"username": "frank"
}},{
"user": {
"username": "aaron"
}}]
43. Опциональный ключ
-users~ [{
:only "username": "heather"},{
.username "username": "george"},{
"username": "frank"},{
"username": "elizabeth"}
]
44. Подклеивание ассоциаций
+tag {'tag' :
:only {'label' : 'Happy Christmas!',
'tagger' : {'name' : 'Mr Lawrence"}}
.label
+tagger
:only
.name
45. Подклеивание ассоциаций
+tag {'tag' :
:only {'label' : 'Happy Christmas!',
'tagger' : {'name' : 'Mr Lawrence"}}
.label
+tagger
:only
.name
+tag {'tag' :
:only {'label' : 'Happy Christmas!',
'tagger_name' : 'Mr Lawrence"}}
.label
<tagger
:only
.name => tagger_name
46. Partials
-users
:only
.name
&shared/pets
render :partial => ‘shared/pets’
56. Как использовать
gem install tequila
config.gem ‘tequila’
/app/views/users/index.json.jazz
59. Спасибо, вопросы!
github.com/inem/tequila
inem.github.com/tequila
twitter.com/inem
twitter.com/0ex0
jazzcloud.net
http://www.flickr.com/photos/tequilaphotos/
Editor's Notes
- JavaScript Object Notation.
- &#x432; &#x43F;&#x435;&#x440;&#x435;&#x432;&#x43E;&#x434;&#x435;: &#x422;&#x435;&#x43A;&#x441;&#x442;&#x43E;&#x432;&#x44B;&#x439; &#x444;&#x43E;&#x440;&#x43C;&#x430;&#x442; &#x43E;&#x431;&#x43C;&#x435;&#x43D;&#x430; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x43C;&#x438;, &#x43E;&#x441;&#x43D;&#x43E;&#x432;&#x430;&#x43D;&#x43D;&#x44B;&#x439; &#x43D;&#x430; &#x441;&#x438;&#x43D;&#x442;&#x430;&#x43A;&#x441;&#x438;&#x441;&#x435; JavaScript
- &#x421;&#x444;&#x435;&#x440;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x439; JSON &#x432; &#x432;&#x430;&#x43A;&#x443;&#x443;&#x43C;&#x435;.
&#x413;&#x434;&#x435; &#x43D;&#x443;&#x436;&#x435;&#x43D; JSON?
&#x414;&#x43B;&#x44F; &#x43D;&#x430;&#x447;&#x430;&#x43B;&#x430; &#x434;&#x430;&#x432;&#x430;&#x439;&#x442;&#x435; &#x440;&#x430;&#x441;&#x441;&#x43C;&#x43E;&#x442;&#x440;&#x438;&#x43C; &#x441;&#x438;&#x442;&#x443;&#x430;&#x446;&#x438;&#x438;, &#x43A;&#x43E;&#x433;&#x434;&#x430; &#x432;&#x43E;&#x437;&#x43D;&#x438;&#x43A;&#x430;&#x435;&#x442; &#x43D;&#x435;&#x43E;&#x431;&#x445;&#x43E;&#x434;&#x438;&#x43C;&#x43E;&#x441;&#x442;&#x44C; &#x43F;&#x435;&#x440;&#x435;&#x434;&#x430;&#x432;&#x430;&#x442;&#x44C; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x435; &#x432; &#x444;&#x43E;&#x440;&#x43C;&#x430;&#x442;&#x435; JSON
&#x41A;&#x43E;&#x433;&#x434;&#x430; &#x443; &#x43D;&#x430;&#x441; &#x435;&#x441;&#x442;&#x44C; &#x444;&#x440;&#x43E;&#x43D;&#x442;&#x435;&#x43D;&#x434; &#x43D;&#x430; &#x43A;&#x43B;&#x438;&#x435;&#x43D;&#x442;&#x441;&#x43A;&#x43E;&#x439; &#x441;&#x442;&#x43E;&#x440;&#x43E;&#x43D;&#x435; &#x43D;&#x430;&#x43F;&#x440;&#x438;&#x43C;&#x435;&#x440; &#x441; &#x434;&#x438;&#x43D;&#x430;&#x43C;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x43E;&#x439; &#x444;&#x438;&#x43B;&#x44C;&#x442;&#x440;&#x430;&#x446;&#x438;&#x435;&#x439;/&#x441;&#x43E;&#x440;&#x442;&#x438;&#x440;&#x43E;&#x432;&#x43A;&#x43E;&#x439; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x445;.
&#x41F;&#x440;&#x438;&#x43C;&#x435;&#x440;: http://ukijs.org/examples/core-examples/table/
&#x41A;&#x43E;&#x433;&#x434;&#x430; &#x43C;&#x44B; &#x43F;&#x438;&#x448;&#x435;&#x43C; backend &#x434;&#x43B;&#x44F; ExtJS, Flash, AIR-&#x43F;&#x440;&#x438;&#x43B;&#x43E;&#x436;&#x435;&#x43D;&#x438;&#x439;
&#x418;&#x43B;&#x438; &#x43D;&#x430;&#x43C; &#x43D;&#x443;&#x436;&#x43D;&#x43E; &#x432;&#x44B;&#x43A;&#x430;&#x442;&#x438;&#x442;&#x44C; API &#x43D;&#x430;&#x448;&#x435;&#x433;&#x43E; &#x43F;&#x440;&#x438;&#x43B;&#x43E;&#x436;&#x435;&#x43D;&#x438;&#x44F; &#x43D;&#x430;&#x440;&#x443;&#x436;&#x443;
&#x41A;&#x430;&#x43A; &#x43E;&#x431;&#x44B;&#x447;&#x43D;&#x43E; &#x43E;&#x442;&#x434;&#x430;&#x435;&#x442;&#x441;&#x44F; JSON &#x438;&#x437; &#x440;&#x435;&#x43B;&#x44C;&#x441;&#x43E;&#x432;&#x43E;&#x433;&#x43E; &#x43F;&#x440;&#x438;&#x43B;&#x43E;&#x436;&#x435;&#x43D;&#x438;&#x44F;?
&#x41C;&#x43E;&#x436;&#x43D;&#x43E; &#x434;&#x435;&#x43B;&#x430;&#x442;&#x44C; &#x43F;&#x43E; &#x441;&#x442;&#x430;&#x440;&#x438;&#x43D;&#x43A;&#x435;
&#x41F;&#x43E;&#x43B;&#x443;&#x447;&#x430;&#x435;&#x43C; &#x432;&#x43E;&#x442; &#x442;&#x430;&#x43A;&#x443;&#x44E; &#x43D;&#x430;&#x440;&#x44F;&#x434;&#x43D;&#x443;&#x44E; &#x43A;&#x430;&#x448;&#x443; &#x432; &#x43A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x435;
&#x412; Rails 2.3.3 &#x440;&#x435;&#x448;&#x438;&#x43B;&#x438; &#x440;&#x430;&#x437;&#x434;&#x435;&#x43B;&#x438;&#x442;&#x44C; &#x43F;&#x440;&#x435;&#x434;&#x441;&#x442;&#x430;&#x432;&#x43B;&#x435;&#x43D;&#x438;&#x435; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x445; &#x438; &#x43D;&#x435;&#x43F;&#x43E;&#x441;&#x440;&#x435;&#x434;&#x441;&#x442;&#x432;&#x435;&#x43D;&#x43D;&#x43E; &#x43A;&#x43E;&#x43D;&#x432;&#x435;&#x440;&#x442;&#x438;&#x440;&#x43E;&#x432;&#x430;&#x43D;&#x438;&#x435;.
as_json &#x444;&#x43E;&#x440;&#x43C;&#x438;&#x440;&#x443;&#x435;&#x442; &#x445;&#x44D;&#x448;, &#x430; to_json &#x435;&#x433;&#x43E; &#x442;&#x443;&#x43F;&#x43E; &#x43F;&#x435;&#x440;&#x435;&#x433;&#x43E;&#x43D;&#x44F;&#x435;&#x442; &#x432; json
&#x412;&#x441;&#x435; &#x43D;&#x430;&#x448;&#x438; &#x201C;&#x43D;&#x435;&#x441;&#x442;&#x430;&#x43D;&#x434;&#x430;&#x440;&#x442;&#x43D;&#x43E;&#x441;&#x442;&#x438;&#x201D; &#x442;&#x435;&#x43F;&#x435;&#x440;&#x44C; &#x43C;&#x43E;&#x436;&#x43D;&#x43E; &#x438; &#x43D;&#x443;&#x436;&#x43D;&#x43E; &#x432;&#x44B;&#x43D;&#x43E;&#x441;&#x438;&#x442;&#x44C; &#x432; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x44C;
&#x410; &#x432;&#x435;&#x440;&#x43D;&#x435;&#x435; &#x432; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x438;.
&#x412; &#x43A;&#x430;&#x436;&#x434;&#x43E;&#x439; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x438; &#x433;&#x434;&#x435; &#x43D;&#x430;&#x43C; &#x43D;&#x443;&#x436;&#x43D;&#x43E; &#x43F;&#x43E;&#x432;&#x435;&#x434;&#x435;&#x43D;&#x438;&#x435;, &#x43E;&#x442;&#x43B;&#x438;&#x447;&#x43D;&#x43E;&#x435; &#x43E;&#x442; &#x441;&#x442;&#x430;&#x43D;&#x434;&#x430;&#x440;&#x442;&#x43D;&#x43E;&#x433;&#x43E;, &#x43C;&#x44B; &#x43E;&#x43F;&#x440;&#x435;&#x434;&#x435;&#x43B;&#x44F;&#x435;&#x43C; &#x43C;&#x435;&#x442;&#x43E;&#x434; as_json.
&#x41C;&#x44B; &#x43C;&#x43E;&#x436;&#x435;&#x43C; &#x43D;&#x435; &#x432;&#x44B;&#x437;&#x44B;&#x432;&#x430;&#x442;&#x44C; super, &#x430;
&#x41A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x44B; &#x442;&#x435;&#x43F;&#x435;&#x440;&#x44C; &#x443; &#x43D;&#x430;&#x441; &#x433;&#x43B;&#x430;&#x434;&#x43A;&#x438;&#x435; &#x438; &#x448;&#x435;&#x43B;&#x43A;&#x43E;&#x432;&#x438;&#x441;&#x442;&#x44B;&#x435;.
Fat model. Skinny controller.
&#x412;&#x441;&#x435; as_json &#x442;&#x435;&#x43F;&#x435;&#x440;&#x44C; &#x443; &#x43D;&#x430;&#x441; &#x43F;&#x440;&#x43E;&#x441;&#x442;&#x43E; &#x432;&#x44B;&#x437;&#x44B;&#x432;&#x430;&#x44E;&#x442;&#x441;&#x44F; &#x43F;&#x43E; &#x446;&#x435;&#x43F;&#x43E;&#x447;&#x43A;&#x435;.
&#x418;&#x442;&#x43E;&#x433;&#x43E; &#x438;&#x43C;&#x435;&#x435;&#x43C;:
- &#x43C;&#x435;&#x442;&#x43E;&#x434;-&#x43F;&#x440;&#x435;&#x437;&#x435;&#x43D;&#x442;&#x435;&#x440; &#x432; &#x43A;&#x430;&#x436;&#x434;&#x43E;&#x439; &#x438;&#x437; &#x43D;&#x443;&#x436;&#x43D;&#x44B;&#x445; &#x43D;&#x430;&#x43C; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x435;&#x439;
- &#x43D;&#x435;&#x43A;&#x43E;&#x442;&#x43E;&#x440;&#x43E;&#x435; &#x43A;&#x43E;&#x43B;&#x438;&#x447;&#x435;&#x441;&#x442;&#x432;&#x43E; &#x43C;&#x435;&#x442;&#x43E;&#x434;&#x43E;&#x432;-&#x445;&#x435;&#x43B;&#x43F;&#x435;&#x440;&#x43E;&#x432;, &#x447;&#x442;&#x43E;&#x431;&#x44B; &#x201C;&#x43F;&#x440;&#x438;&#x447;&#x435;&#x441;&#x430;&#x442;&#x44C;&#x201D; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x435; &#x43F;&#x435;&#x440;&#x435;&#x434; &#x432;&#x44B;&#x434;&#x430;&#x447;&#x435;&#x439; &#x43D;&#x430; &#x43A;&#x43B;&#x438;&#x435;&#x43D;&#x442;
&#x42D;&#x442;&#x43E; &#x442;&#x43E;, &#x447;&#x442;&#x43E; &#x441;&#x435;&#x439;&#x447;&#x430;&#x441; &#x43D;&#x430;&#x437;&#x44B;&#x432;&#x430;&#x435;&#x442;&#x441;&#x44F; Rails way.
&#x43D;&#x430;&#x43C; &#x43D;&#x443;&#x436;&#x43D;&#x43E; &#x431;&#x43E;&#x43B;&#x435;&#x435; &#x447;&#x435;&#x43C; &#x43E;&#x434;&#x43D;&#x43E; &#x43F;&#x440;&#x435;&#x434;&#x441;&#x442;&#x430;&#x432;&#x43B;&#x435;&#x43D;&#x438;&#x435; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x438; &#x432; json
&#x41D;&#x430;&#x43F;&#x440;&#x438;&#x43C;&#x435;&#x440;, &#x434;&#x43B;&#x44F; &#x441;&#x442;&#x440;&#x430;&#x43D;&#x438;&#x446;&#x44B; &#x441;&#x43E; &#x441;&#x43F;&#x438;&#x441;&#x43A;&#x43E;&#x43C; &#x43F;&#x43E;&#x43B;&#x44C;&#x437;&#x43E;&#x432;&#x430;&#x442;&#x435;&#x43B;&#x435;&#x439; &#x43C;&#x44B; &#x445;&#x43E;&#x442;&#x438;&#x43C; &#x432;&#x44B;&#x434;&#x430;&#x432;&#x430;&#x442;&#x44C; &#x43C;&#x43D;&#x43E;&#x433;&#x43E; &#x438;&#x43D;&#x444;&#x43E;&#x440;&#x43C;&#x430;&#x446;&#x438;&#x438; &#x43E; &#x44E;&#x437;&#x435;&#x440;&#x435;, &#x430; &#x432; &#x441;&#x43B;&#x443;&#x447;&#x430;&#x435;, &#x43A;&#x43E;&#x433;&#x434;&#x430; &#x43C;&#x44B; &#x438;&#x43D;&#x43A;&#x43B;&#x44E;&#x434;&#x438;&#x43C; &#x43F;&#x43E;&#x43B;&#x44C;&#x437;&#x43E;&#x432;&#x430;&#x442;&#x435;&#x43B;&#x44F; &#x43A; &#x43A;&#x43E;&#x43C;&#x435;&#x43D;&#x442;&#x430;&#x440;&#x438;&#x44E;, &#x43D;&#x430;&#x43C; &#x43D;&#x443;&#x436;&#x43D;&#x44B; &#x442;&#x43E;&#x43B;&#x44C;&#x43A;&#x43E; &#x435;&#x433;&#x43E; login &#x438; id.
&#x422;&#x43E;&#x433;&#x434;&#x430; &#x43D;&#x430;&#x43C; &#x43D;&#x435;&#x43A;&#x443;&#x434;&#x430; &#x434;&#x435;&#x432;&#x430;&#x442;&#x44C;&#x441;&#x44F;, &#x438;, &#x432;&#x441;&#x435; &#x43C;&#x435;&#x441;&#x442;&#x430;, &#x432; &#x43A;&#x43E;&#x442;&#x43E;&#x440;&#x44B;&#x445; &#x43F;&#x43E;&#x432;&#x435;&#x434;&#x435;&#x43D;&#x438;&#x435; &#x43E;&#x442;&#x43B;&#x438;&#x447;&#x430;&#x435;&#x442;&#x441;&#x44F; &#x43E;&#x442; &#x434;&#x435;&#x444;&#x43E;&#x43B;&#x442;&#x43D;&#x43E;&#x433;&#x43E;(&#x437;&#x430;&#x434;&#x430;&#x43D;&#x43D;&#x43E;&#x433;&#x43E; &#x43D;&#x430;&#x43C;&#x438;), &#x43E;&#x43F;&#x44F;&#x442;&#x44C; &#x43F;&#x438;&#x441;&#x430;&#x442;&#x44C; &#x440;&#x443;&#x447;&#x43A;&#x430;&#x43C;&#x438; &#x432; &#x43A;&#x43E;&#x43D;&#x442;&#x440;&#x43E;&#x43B;&#x43B;&#x435;&#x440;&#x435;
&#x422;&#x430;&#x43A; &#x43D;&#x435;&#x43B;&#x44C;&#x437;&#x44F; &#x43A; &#x441;&#x43E;&#x436;&#x430;&#x43B;&#x435;&#x43D;&#x438;&#x44E;
&#x41D;&#x43E; &#x435;&#x441;&#x43B;&#x438; &#x441;&#x438;&#x43B;&#x44C;&#x43D;&#x43E; &#x445;&#x43E;&#x447;&#x435;&#x442;&#x441;&#x44F;, &#x442;&#x43E; &#x43C;&#x43E;&#x436;&#x43D;&#x43E;.
&#x418;&#x442;&#x43E;&#x433;&#x43E;, &#x432;&#x43E;&#x442; &#x43D;&#x430; &#x43A;&#x430;&#x43A;&#x438;&#x435; &#x43D;&#x435;&#x43F;&#x440;&#x438;&#x44F;&#x442;&#x43D;&#x43E;&#x441;&#x442;&#x438; &#x43C;&#x44B; &#x438;&#x43C;&#x435;&#x435;&#x43C; &#x448;&#x430;&#x43D;&#x441;&#x44B; &#x43D;&#x430;&#x440;&#x432;&#x430;&#x442;&#x44C;&#x441;&#x44F;.
&#x415;&#x441;&#x43B;&#x438; &#x438;&#x441;&#x43F;&#x43E;&#x43B;&#x44C;&#x437;&#x443;&#x435;&#x442;&#x441;&#x44F; &#x448;&#x442;&#x430;&#x442;&#x43D;&#x44B;&#x439; to_json, &#x43F;&#x440;&#x438; &#x438;&#x437;&#x43C;&#x435;&#x43D;&#x435;&#x43D;&#x438;&#x438; &#x441;&#x442;&#x440;&#x443;&#x43A;&#x442;&#x443;&#x440;&#x44B; &#x431;&#x430;&#x437;&#x44B; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x445;, &#x438;&#x437;&#x43C;&#x435;&#x43D;&#x44F;&#x435;&#x442;&#x441;&#x44F; &#x441;&#x442;&#x440;&#x443;&#x43A;&#x442;&#x443;&#x440;&#x430; JSON-&#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x445;
&#x41D;&#x435;&#x442; &#x43F;&#x440;&#x43E;&#x441;&#x442;&#x43E;&#x433;&#x43E; &#x441;&#x43F;&#x43E;&#x441;&#x43E;&#x431;&#x430; &#x432;&#x44B;&#x437;&#x432;&#x430;&#x442;&#x44C; &#x43C;&#x435;&#x442;&#x43E;&#x434; &#x441; &#x43F;&#x430;&#x440;&#x430;&#x43C;&#x435;&#x442;&#x440;&#x430;&#x43C;&#x438;
&#x41F;&#x440;&#x438; &#x43F;&#x435;&#x440;&#x435;&#x43E;&#x43F;&#x440;&#x435;&#x434;&#x435;&#x43B;&#x435;&#x43D;&#x438;&#x438; as_json &#x432; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x438; &#x43C;&#x44B; &#x438;&#x43C;&#x435;&#x435;&#x43C; &#x442;&#x43E;&#x43B;&#x44C;&#x43A;&#x43E; &#x43E;&#x434;&#x43D;&#x43E; &#x43F;&#x440;&#x435;&#x434;&#x441;&#x442;&#x430;&#x432;&#x43B;&#x435;&#x43D;&#x438;&#x435; &#x43D;&#x430;&#x448;&#x435;&#x439; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x438;. &#x410; &#x438;&#x43D;&#x43E;&#x433;&#x434;&#x430; &#x43D;&#x443;&#x436;&#x43D;&#x43E; &#x431;&#x43E;&#x43B;&#x44C;&#x448;&#x435;
&#x415;&#x441;&#x43B;&#x438; &#x43D;&#x435;&#x43A;&#x43E;&#x442;&#x43E;&#x440;&#x44B;&#x435; &#x43C;&#x43E;&#x434;&#x435;&#x43B;&#x438; &#x432;&#x44B;&#x43D;&#x435;&#x441;&#x435;&#x43D;&#x44B; &#x432; &#x43F;&#x43B;&#x430;&#x433;&#x438;&#x43D;&#x44B;, &#x438;&#x441;&#x43F;&#x43E;&#x43B;&#x44C;&#x437;&#x43E;&#x432;&#x430;&#x43D;&#x438;&#x435; as_json &#x43E;&#x431;&#x43E;&#x440;&#x430;&#x447;&#x438;&#x432;&#x430;&#x435;&#x442;&#x441;&#x44F; &#x440;&#x44F;&#x434;&#x43E;&#x43C; &#x43D;&#x435;&#x443;&#x434;&#x43E;&#x431;&#x441;&#x442;&#x432;.
!! &#x412;&#x441;&#x442;&#x430;&#x432;&#x438;&#x442;&#x44C; &#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x443;
&#x41A;&#x430;&#x43A;&#x438;&#x435; &#x437;&#x430;&#x434;&#x430;&#x447;&#x438; &#x43C;&#x44B; &#x440;&#x435;&#x448;&#x430;&#x43B;&#x438; &#x441;&#x43E;&#x437;&#x434;&#x430;&#x43D;&#x438;&#x435;&#x43C; &#x442;&#x435;&#x43A;&#x438;&#x43B;&#x44B;.
&#x427;&#x442;&#x43E;&#x431;&#x44B; &#x44D;&#x442;&#x43E; &#x431;&#x44B;&#x43B;&#x43E; &#x43A;&#x440;&#x430;&#x441;&#x438;&#x432;&#x43E; &#x438; &#x43D;&#x430;&#x433;&#x43B;&#x44F;&#x434;&#x43D;&#x43E;. &#x41A;&#x430;&#x43A; &#x432; HAML &#x43D;&#x430;&#x43F;&#x440;&#x438;&#x43C;&#x435;&#x440;.
&#x421;&#x430;&#x43C;&#x43E;&#x435; &#x432;&#x435;&#x441;&#x435;&#x43B;&#x43E;&#x435; &#x432; &#x442;&#x43E;&#x43C;, &#x447;&#x442;&#x43E; &#x43C;&#x44B; &#x434;&#x435;&#x43B;&#x430;&#x43B;&#x438; &#x44D;&#x442;&#x43E; &#x43F;&#x440;&#x43E;&#x435;&#x43A;&#x442; &#x432; &#x440;&#x430;&#x43C;&#x43A;&#x430;&#x445; RailsRumble. &#x418; &#x43D;&#x430;&#x43C; &#x43D;&#x430;&#x434;&#x43E; &#x431;&#x44B;&#x43B;&#x43E; &#x443;&#x441;&#x43F;&#x435;&#x442;&#x44C; &#x437;&#x430;&#x43A;&#x43E;&#x43D;&#x447;&#x438;&#x442;&#x44C; &#x435;&#x433;&#x43E; &#x437;&#x430; &#x434;&#x432;&#x430; &#x434;&#x43D;&#x44F;.
1. &#x43A;&#x43E;&#x434; to json -> tequila
2. &#x43E;&#x43F;&#x442;&#x438;&#x43C;&#x438;&#x437;&#x438;&#x440;&#x443;&#x435;&#x43C;
3. &#x432;&#x44B;&#x43D;&#x43E;&#x441;&#x438;&#x43C; &#x445;&#x435;&#x43B;&#x43F;&#x435;&#x440;&#x44B; &#x432; &#x448;&#x430;&#x431;&#x43B;&#x43E;&#x43D;
&#x424;&#x438;&#x447;&#x438;
&#x43D;&#x430;&#x434;&#x43E; &#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x44C; &#x43F;&#x43E; &#x43A;&#x440;&#x430;&#x441;&#x438;&#x432;&#x43E;&#x43C;&#x443; &#x43F;&#x440;&#x438;&#x43C;&#x435;&#x440;&#x447;&#x438;&#x43A;&#x443; &#x43D;&#x430; &#x43A;&#x430;&#x436;&#x434;&#x443;&#x44E; &#x444;&#x438;&#x447;&#x443;.
&#x41E;&#x442;&#x441;&#x442;&#x443;&#x43F;&#x43E;-&#x43E;&#x440;&#x438;&#x435;&#x43D;&#x442;&#x438;&#x440;&#x43E;&#x432;&#x430;&#x43D;&#x43D;&#x43E;&#x435; &#x444;&#x43E;&#x440;&#x43C;&#x430;&#x442;&#x438;&#x440;&#x43E;&#x432;&#x430;&#x43D;&#x438;&#x435;
&#x41A;&#x430;&#x43A; &#x432; python, HAML, SASS
&#x43C;&#x43E;&#x436;&#x43D;&#x43E; &#x43F;&#x435;&#x440;&#x435;&#x438;&#x43C;&#x435;&#x43D;&#x43E;&#x432;&#x430;&#x442;&#x44C; &#x43D;&#x430;&#x437;&#x432;&#x430;&#x43D;&#x438;&#x435; &#x430;&#x441;&#x441;&#x43E;&#x446;&#x438;&#x430;&#x446;&#x438;&#x438;
&#x43C;&#x43E;&#x436;&#x43D;&#x43E; &#x43F;&#x435;&#x440;&#x435;&#x438;&#x43C;&#x435;&#x43D;&#x43E;&#x432;&#x430;&#x442;&#x44C; &#x430;&#x442;&#x440;&#x438;&#x431;&#x443;&#x442;&#x44B; &#x438; &#x43C;&#x435;&#x442;&#x43E;&#x434;&#x44B;
&#x41F;&#x43E;&#x434;&#x43A;&#x43B;&#x435;&#x438;&#x432;&#x430;&#x43D;&#x438;&#x435; has_one &#x430;&#x441;&#x441;&#x43E;&#x446;&#x438;&#x430;&#x446;&#x438;&#x439;
&#x41F;&#x43E;&#x434;&#x43A;&#x43B;&#x435;&#x438;&#x432;&#x430;&#x43D;&#x438;&#x435; has_one &#x430;&#x441;&#x441;&#x43E;&#x446;&#x438;&#x430;&#x446;&#x438;&#x439;
&#x42D;&#x442;&#x43E; &#x440;&#x430;&#x431;&#x43E;&#x442;&#x430;&#x435;&#x442; &#x43D;&#x430; &#x441;&#x43A;&#x43E;&#x43B;&#x44C; &#x443;&#x433;&#x43E;&#x434;&#x43D;&#x43E; &#x432;&#x43B;&#x43E;&#x436;&#x435;&#x43D;&#x43D;&#x44B;&#x435; &#x430;&#x441;&#x441;&#x43E;&#x446;&#x438;&#x430;&#x446;&#x438;&#x438;.
&#x410; &#x442;&#x435;&#x43F;&#x435;&#x440;&#x44C; &#x43F;&#x43E;&#x437;&#x43D;&#x430;&#x447;&#x430;&#x442;&#x435;&#x43B;&#x44C;&#x43D;&#x430;&#x44F; &#x441;&#x442;&#x440;&#x430;&#x43D;&#x438;&#x447;&#x43A;&#x430; &#x43E; &#x442;&#x43E;&#x43C; &#x43A;&#x430;&#x43A; &#x432;&#x441;&#x435; &#x44D;&#x442;&#x43E; &#x43F;&#x440;&#x43E;&#x438;&#x441;&#x445;&#x43E;&#x434;&#x438;&#x442;
&#x41C;&#x44B; &#x431;&#x435;&#x440;&#x435;&#x43C; &#x43D;&#x430;&#x448;&#x438; &#x43A;&#x443;&#x447;&#x435;&#x440;&#x44F;&#x432;&#x44B;&#x435; &#x434;&#x430;&#x43D;&#x43D;&#x44B;&#x435;
&#x41F;&#x440;&#x438;&#x432;&#x43E;&#x434;&#x438;&#x43C; &#x438;&#x445; &#x432; &#x43F;&#x440;&#x438;&#x43B;&#x438;&#x447;&#x43D;&#x44B;&#x439; &#x43D;&#x443;&#x436;&#x43D;&#x44B;&#x439; &#x43D;&#x430;&#x43C; &#x432;&#x438;&#x434;
&#x414;&#x43E;&#x432;&#x43E;&#x434;&#x438;&#x43C; &#x434;&#x43E; &#x43A;&#x43E;&#x43D;&#x434;&#x438;&#x446;&#x438;&#x438;
&#x414;&#x43E;&#x432;&#x43E;&#x434;&#x438;&#x43C; &#x434;&#x43E; &#x43A;&#x43E;&#x43D;&#x434;&#x438;&#x446;&#x438;&#x438;
Treetop!