Mam model User w z którego chciałbym się pozbyć częsci w której definiuje gettery i settery.
[code=ruby]class User < ActiveRecord::Base
attr_accessible :email
validates :email,
presence: true
serialize :data, ActiveRecord::Coders::Hstore
%w[zipcode first_name].each do |key|
attr_accessible key
define_method(key) do
data && data[key]
end
define_method("#{key}=") do |value|
self.data = (data || {}).merge(key => value)
end
end
end[/code]
Oraz widok w którym chciałbym tylko po prostu dodawać ewentualne nowe pola, które automatycznie były by zapisywane jako hstore.
<%= simple_form_for User.new, validate: true do |f| %>
<%= hidden_field_tag :template, 'about' %>
<%= f.input :email %>
<%= f.input :first_name %>
<%= f.button :submit, 'Sign up', class: 'btn btn-large btn-warning' %>
<% end %>
Czy jest to w ogóle możliwe? Nie mogę nigdzie znaleźć informacji w sieci na ten temat.
Nie wiem też jakie powino być właściwe pytanie dotyczące tego zagadnienia.
define_method przyjmuje na pałę stringa, nie trzeba go “osymbolizować”?
Regedarek, to co napisałeś (i to co Sławosz podrzucił) powinno działać out-of-the-box z formularzami.
Używam czegoś zasadniczo identycznego w *Rage (wszystkie te facebook, twitter, bandcamp urle dla danego artysty), z tym że ze zwykłą railsową yaml-serializacją do kolumny tekstowej (bo MySQL, zresztą muszę wreszcie zmigrować).
Mój problem jest dokładnie taki, że chcę się pozbyć definiowania hstore atrybutów z modelu. Chodzi o to, że ktoś kto będzie tego używał, nie będzie miał pojęcia co to jest model i będzie chciał tylko dodać lub usunąć pole w widoku.
tomash masz racje z tym stringiem przy define_method.
Dzięki sławosz, właśnie sprawdzam twoje rozwiązanie.
Czyli nie chcesz modyfikować zupełnie kodu modelu? Wtedy możesz użyć method missing ale jej overriding w Railsach jest trickowy (zawsze wywołuj super) pozatym ktoś może przez przypadek użyć istniejącej nazwy. Może zmuś tą osobę do używania nazwy w stylu ‘form_*’, wtedy będzie łatwiej zaimplementować method missing:
def method_missing(*args)
if args.first =~ /form_/
# dodaj metody dla hstore
else
super
end
end
Stąd moje pytanie, bo ten pomysł jest bardzo głupi. Kwestią czasu jest kiedy nazwa pola trafi w jakieś słowo kluczowe w ruby (już nie wspominam o zaimplementowanych metodach dostępnych w każdej instancji AR::Base, trochę tego jest) a wtedy cała koncepcja wali się jak domek z kart.
Mam podobny problem w aplikacji, którą obecnie piszę. Wczoraj wydzieliłem definiowanie akcesorów do kilkulinijkowego, zewnętrznego gema. Też myślałem nad wrzucaniem do hstore dowolnych kluczy i wartości, jednak takie rozwiązanie pociąga za sobą kilka niedogodności. Railsy 4 używają domyślnie strong_parameters - jeśli nie mamy ściśle określonej listy atrybutów, to zabezpieczenie w zasadzie trzeba całkiem wyłączyć. Podobny problem wystąpi zapewne w Railsach 3 i MassAssignmentSecurity. Jeśli akceptujesz dowolne atrybuty, to akcesorów lepiej w ogóle nie definiować, żeby uniknąć problemów o jakich wspomniał Tomash. Ja zdecydowałem się zostać przy ściśle określonej liście atrybutów i definiowaniu akcesorów do nich (mój gem wspiera też prostą konwersję typów). W aktualnej aplikacji mam model, który implementuje prosty arkusz kalkulacyjny - dzięki zastosowaniu hstore uniknąłem konieczności definiowania ok. 100 kolumn w bazie. W Railsach 4 wszystko działa od strzału, nie trzeba żadnych dodatkowych gemów do obsługi hstore.