Какво програмирам тия дни... (казус, за разтуха)

0 views
Skip to first unread message

Петьо Иванов

unread,
Mar 4, 2008, 2:48:14 PM3/4/08
to Ruby on Rails: България
Привет,

Днес решавах една малко по-забавна задача, която реших да споделя с
вас. Хем да видим дали някой друг не го е решавал вече.

Имам обект (човек), който има няколко "features", всяка от която може
да бъде само с предефинирана стойност. Например - цвят на косата -
черен, червен, рус, бял. Очи - сини, кафеви, зелени. Пушач - да, не,
наргиле. Пие - не, рядко, често, всеки ден, по няколко пъти. И още
няколко такива. Вероятно по-нататък ще изникват още. За момента са 7
на брой.
Условието на задачата включва възможността за редакция и добавяне на
нови възможности към всеки feature от администратор, през UI. Нови
features ще добавя само разработчика.

Как бихте го решили? Сега ако някой изкара бесния плъгин
acts_with_features или нещо подобно, направо си подавам оставката, и
оставям клиента да си програмира сайта ;).

Sava Chankov

unread,
Mar 4, 2008, 3:40:41 PM3/4/08
to ruby-on-rai...@googlegroups.com
On 04/03/2008, Петьо Иванов <unde...@gmail.com> wrote:
Имам обект (човек), който има няколко "features", всяка от която може
да бъде само с предефинирана стойност. Например - цвят на косата -
черен, червен, рус, бял. Очи - сини, кафеви, зелени. Пушач - да, не,
наргиле. Пие - не, рядко, често, всеки ден, по няколко пъти. И още
няколко такива. Вероятно по-нататък ще изникват още. За момента са 7
на брой.
Условието на задачата включва възможността за редакция и добавяне на
нови възможности към всеки feature от администратор, през UI. Нови
features ще добавя само разработчика.

Как бихте го решили? Сега ако някой изкара бесния плъгин
acts_with_features или нещо подобно, направо си подавам оставката, и
оставям клиента да си програмира сайта ;).

Едно възможно решение e антишаблонът Entity-Attribute-Value. Виж и тази статия - http://www.stonemind.net/blog/2007/07/13/exploring-an-entity-attribute-value-data-model-for-flexible-metadata-in-a-digital-asset-management-system/

Все пак имай предвид, че този подход не се мащабира - за много feature-и и много обекти (хора) заявката, която извежда всички feature-и на човека ще е доста бавна. Аз лично бих дал възможност на администратора да си добавя и feature-и. Едно възможно начало (разбира се, след съответното саниране на входящите параметри!):

class Person < ActiveRecord::Base
  def add_feature(name,type,values)
    ActiveRecord::Migration.create_table("human_feature_#{name}"){|t| t.send(type, :attr)}
    feature_klass = name.camelize.constantize
    values.each{ |v| feature_klass.create(:attr => v) }
    ActiveRecord::Migration.add_column(:people, "human_feature_#{name}_id")
  end
end

Stefan Kanev

unread,
Mar 5, 2008, 3:44:15 AM3/5/08
to ruby-on-rai...@googlegroups.com
Искаш ли да може потребителя да добавя нови фичъри или само да променя тяхните стойности?
  • Не. В този случай, това е някак класическо. Създаваш таблица за всеки фийчър и предлагаш опции за редакцията им в админ панела (ала номенклатура). Всеки потребител има по една колонка за фийчър (hookah_id, smoking_id) и т.н. Понеже контролерите на всички ще са еднакви, би трябвало да е сравнително простичко да направиш нещо като scaffold :hookah и така да спестиш повторение на контролер код. С малко въображение, може да спестиш доста код. Очевидно програмиста ще добавя фийчъри ръчно, като може да се напишат migration helper-и които да улесняват това допълнително - add_feature :hookah, вместо create_table :hookah ...; add_column :users, :hookah_id. Това ако фичърите се променят средно често или по-рядко. Ако се променят сравнително често, 
  • Да. В този случай бих тръгнал с идеята на Сава и бих добавил код, който всъщност бара схемата на базата данни. Това е нещо от което не би трябвало да те е страх.
В никакъв случай не бих тръгнал с entity-attribute-value антипатерна (таблица user_id, feature_name, feature_value). Ама за нищо на света. Проблемите които той създава са много, много повече от тези, които ще имаш ако променяш структурата на базата данни динамично.

Петьо Иванов

unread,
Mar 5, 2008, 10:18:44 AM3/5/08
to Ruby on Rails: България
Интересни идеи, особено със динамичното създаване на таблици :).
Мисля, че не бих изригнал чак така. Решението ми е нещо като тоя анти-
паттерн, ама с по-нормализирана база данни. Проблема, който трябваше
да спомена е, че вероятно ще дойдат още езици, и тия ми ти опции ще
трябва да се превеждат...

Ето как го направих:
таблици:
users
features
feature_options
feature_options_users

След това идва следната черна магия:

module Features
def self.included(base)

base.class_eval do
has_and_belongs_to_many :features, :class_name =>
'FeatureOption'
end

Feature.find(:all).each do |char|
method = char.name.gsub(' ', '_').underscore

id = char.id

base.class_eval <<METHODS

def #{method}()
@#{method} ||= features.to_a.find {|feature|
feature.feature_id == #{id}}
end

def #{method}_id()
#{method}.id
end

def #{method}=(value)
return if value.blank?
value = FeatureOption.find(value) if value.class == String
or value.class == Fixnum
features.delete #{method}
@#{method} = value
self.features << @#{method}
end

def #{method}_id=(value)
self.#{method} = value
end

def #{method}_options
# Тук съм добавил малко код в models/feature.rb, подобен на този горе,
който ми позволява да взимам отделните features "именувани", направо
от класа.
Feature.#{method}.options
end
METHODS

end # each char
end # self.included
end

(Имах неблагоразумието наместо Feature първо да го кръстя
Characteristic, което е трудно и гадно за писане, сега ме мързи да го
преименувам).

class User < ActiveRecord::Base
include Features
end

Tуйто. Сега юзъра вече има закачен метод smoker, smoker=, външно
изглежда като belongs_to. Ако добавя нов feature, ще се наложи да
рестартирам сървъра.

Носи си недостатъци, но чревно го усещам, че май е най-малката злина
за момента. Да видим...

Какво милите?



On Mar 5, 10:44 am, "Stefan Kanev" <stefan.ka...@gmail.com> wrote:
> *Искаш ли да може потребителя да добавя нови фичъри или само да променя
> тяхните стойности?
> *
>
> - *Не.* В този случай, това е някак класическо. Създаваш таблица за
> всеки фийчър и предлагаш опции за редакцията им в админ панела (ала
> номенклатура). Всеки потребител има по една колонка за фийчър (hookah_id,
> smoking_id) и т.н. Понеже контролерите на всички ще са еднакви, би
> трябвало да е сравнително простичко да направиш нещо като scaffold :hookah и
> така да спестиш повторение на контролер код. С малко въображение, може да
> спестиш доста код. Очевидно програмиста ще добавя фийчъри ръчно, като може
> да се напишат migration helper-и които да улесняват това допълнително -
> add_feature :hookah, вместо create_table :hookah ...; add_column :users,
> :hookah_id. Това ако фичърите се променят средно често или по-рядко. Ако се
> променят сравнително често,
> - *Да.* В този случай бих тръгнал с идеята на Сава и бих добавил код,
> който всъщност бара схемата на базата данни. Това е нещо от което не би
> трябвало да те е страх.
>
> В *никакъв* случай не бих тръгнал с entity-attribute-value антипатерна

Stanislav Bozhkov

unread,
Mar 5, 2008, 11:31:20 AM3/5/08
to ruby-on-rai...@googlegroups.com
Оле, това найстина е черна магия ....

2008/3/5 Петьо Иванов <unde...@gmail.com>:



--
Internet Entrepreneur
gsm: +359 897 941 631
site: http://svejo.net

Sava Chankov

unread,
Mar 5, 2008, 11:39:23 AM3/5/08
to ruby-on-rai...@googlegroups.com

Миля да има смисъл от модул, ако и други класове ще имат feature-и, иначе може да е директно в класа User. Ако си поиграеш и с method_missing, в който да се изпълнява base.class_eval няма да има нужда да рестартираш сървъра.

Sava Chankov

unread,
Mar 5, 2008, 11:46:27 AM3/5/08
to ruby-on-rai...@googlegroups.com
On 05/03/2008, Stanislav Bozhkov <stanisla...@gmail.com> wrote:
Оле, това найстина е черна магия ....

Приятно ми е, викат ми Вълчемор ;-) Нищо черно няма - ако отвориш вътрешностите на Rails ще видиш, че това е ежедневие.

Guda

unread,
Mar 9, 2008, 3:59:02 PM3/9/08
to Ruby on Rails: България
Мисля че съм виждал подобен плъгин, естествено го видях след като web-
a беше готов, и пак естествено не мога да се сетя как се казваше

On Mar 5, 6:46 pm, "Sava Chankov" <sava.chan...@gmail.com> wrote:

Guda

unread,
Mar 9, 2008, 4:08:49 PM3/9/08
to Ruby on Rails: България
Така е който пише а после чете, от поста нa Sava Chankov намерих
два :)

Петьо Иванов

unread,
Mar 11, 2008, 8:04:21 AM3/11/08
to Ruby on Rails: България
Ъм, аз ли съм недоскив? Как се казва плъгина?
Reply all
Reply to author
Forward
0 new messages