[Hstore] Jak z poziomu formularza zapisywać wszystkie pola?

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. :slight_smile:

Tu jest rozwiązanie którego użyłem w jednym z projektów, można by rozszerzyć, jak masz pytania to wal śmiało:

A, i użyłem tych dwóch demów (ale już troche czasu upłynęło od tego czasu): active_record_hstore_serializer, activerecord-postgres-hstore

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.

I zamiast tego gdzie wolałbyś mieć te definicje?

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.

Hmm, masz rację. A gdybym chciał mieć te definicje w kontrolerze?

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.

To wtedy nie użyjesz railsowych helperów w ramach formularza do danego modelu.

Oraz to co Kuba napisał.