13 февр. 2009 г.

Сам себе Stylesheet. CSS.ERB.


Для того чтобы спрятать вещь, достаточно положить ее на видном месте.


CSS раздражал и пугал меня уже давно: куча неуправляемого наваленного в один файл хлама, прикосновение к которому подобно миске со спагетти - тянеш с одного конца и что-то движеться с другого.

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

Подумывалось даже написть свой парсер, чтобы генерировать стили налету. Но буквально недавно в разговоре с Евгением Гуриным на тему HAML vs ERB было упомянуто расширение css.erb. Мозг откликнулся почти сразу :-)

Раз можно получить ресурс в формате JSON или XML, то почему бы ему не быть CSS


В принципе, на этом все. Писать особо больше нечего Джо Сассер и так уже все доходчиво объясняет.

application.css

p {
color: <%= @user.color %>;
}


stylesheet_controller.erb


def show
@user = User.find(params[:id])
respond_to do |format|
format.html
format.css
end
end

application.html.erb

<%= stylesheet_link_tag formatted_user_path(@user, "css") %>


Вот тут эще статья по динамической генерации стилей.

Вобщем все на HAML, товарищи! Там это все уже есть встроенное.

P.S. Правда немного смущает структурирование отступами, чем нередко подкалывают питоноводов. Но ничего, переживем. YAML же мы как-то приняли.

P. P. S. YAML не допускает отступы табуляциями, желательно два пробела.

10 февр. 2009 г.

Scaffold in Ruby on Rails

ActiveScaffold, Streamlined, AutoAdmin - все это инструменты для автоматической генерации графического интерфейса по данным конфигурации или той информации. которую удается извлечь из модели.

Все три встраивают свой код на разных слоях:
ActiveScaffold - контроллер,
AutoAdmin - модель
Streamlined - слой ui с привязкой к модели

В принципе самым правильным с точки зрения гибкости и устойчивости к изменениям является Streamlined, потому, что можно одновременно иметь несколько вариантов настроек и заменять изменяя только одну строку в регистрации элемента UI слоя.

Из этого всего можно сделать вывод, что слой автоматического формирования графического интерфейса сущесвует. Где же его разместить, если каждый инструмент диктует нам свои условия?

Решение следующее. Вынести весь код отвечающий за генерацию UI в отдельный каталог app/ui.

Как нам заставить этот код работать?

Пользуясь тем, что классы Ruby всегда открыты и принципом примата соглашений создадим копии нужных нам классов(котроллеров или моделей, в зависимости от выбранного генератора UI) в каталоге UI и загрузить каждый из этих классов.

После загрузки все обявления одноименных класов сольються воедино.

Данная методика может быть использована не только для GUI, но и для любого другого слоя сложной логики.

Никто так-же не запрещал нам использовать комбинацию из нескольких генераторов.

environment.rb

Dir["#{RAILS_ROOT}/app/ui/*.rb"].each(&:require)


app/controllers/welcome_controller.rb

class WelcomeController < ApplicationController
def index
#
end
end


app/ui/welcome_controller.rb

class WelcomeController < ApplicationController
active_scaffold do |config|
...
end
end

7 февр. 2009 г.

acts_as_extensible. Все факты в одном месте.

Практическое использование Rails: Часть 3. Оптимизация ActiveRecord

В данной статье описываются способы решения проблемы наследования в реализации патерна ActiveRecord Ruby on Rails.

По моему мнению, ни один из этих способов не является полным, так как не решает проблемы связаной с сосредоточением общих данных и логики в одном месте.

Недостатки однотабличного наследования там уже описаны(STI).
Многотабличные методы заставляют вносить общие поля во все таблице, а это неоправданное расточительство времени при большем количестве подкласов.

Больше всего подходит способ полиморфизма, но и он имеет недостаток потому, что заставляет вас заботиться о создании экземпляра модели связанной ассоциацией has_one, а потом обращаться к ней по длинному пути, а также не дает способа включить общиее поведение сразу всем классам одновременно.

Для решения задачи можно использовать расширение acts_as_extensible делигирует вызовы свойств объекту связанному по has_one, а так же берет на себя заботу о его создании и уничтожении.

Но все еще не решена задача раздачи общего функционала. Возможно стоит усовершенствовать расширение, чтобы помимо полей включалось бы еще и общее поведение описанное в базовой модели.

Есть другой путь, несколько избыточный, но позволяющий решить задачу без вмешательства в код расширения.

Унаследовать все подсклассы от одного абстрактного суперкласса и определить общее поведение там.
Это избавит нас от перебора всех моделей и встаки кода например через include 'Module'.

Код становиться чище, вероятность ошибок снижается.

# Общие поля
# title: string
# body: string
# contentible_id
# contentible_type

class Content < ActiveRecord::Base
belongs_to :contentible, :polymorphic => true
validates_presence_of :title, :body # Проверка общих свойств
end

class AbstractContent < ActiveRecord::Base
self.abstract_class = true
acts_as_extensible :content, :as => :contentible

# общие связи
has_many :comments, :as => :commentable

def publish # общие методы
...
end
end

class Post < AbstractContent
end

class News < AbstractContent

end

class Comment < AbstractContent
validates_something :field, :field2 # Проверка индивидуальных свойств
end


Таким образом мы можем обращаться к свойствам подкласов как будто бы они определены в самом классе и добавлять общие свойства и поведение всем подклассам одновременно, также определять проверки общих свойств.

Вообще ActiveRecord допольно неплохой патерн, пока речь не заходит о наследовании.

DRY!!!

Спасибо, Коля :-)